|
클래스 명 |
역할 |
Packet |
프로그램 데이터를 패킷화하여 전송 및 수신 |
EhPacket |
패킷 헤더와 바디 형식으로 구성된 패킷 전송 및 수신 |
LogReq |
프로젝트 내의 패킷 종류 중 하나 |
RegReq |
프로젝트 내의 패킷 종류 중 하나 |
PacketFactory |
소켓으로부터 수신받아 프로젝트 내의 패킷으로 변환 |
u Packet클래스
<그림 2. Packet 클래스 구조>
l 멤버 필드
멤버 필드 명 |
설명 |
base |
패킷화된 데이터가 보관되는 버퍼 |
size |
현재 보관된 데이터 사이즈 |
ptr |
패킷 데이터를 언 패킷화해 나갈 때의 버퍼내의 위치 |
l 멤버 메서드
메서드 명 |
설명 |
.ctor(sock,_size) |
소켓에서 수신 받아 패킷을 생성 |
.ctor() |
비어있는 패킷을 생성 |
Packetizing |
프로그램 데이터를 패킷 데이터에 추가 |
UnPacketizing |
패킷의 데이터를 프로그램 주소로 복사 |
Reset |
언 패킷 할 위치 ptr을 base 시작 위치로 변경 |
Serialize |
소켓으로 패킷을 전송 |
PacketSize |
현재 보관된 패킷 데이터 사이즈 |
InitInstance(sock) |
소켓에서 수신 받아 패킷을 생성할 때 초기화 |
InitInstance |
패킷 생성 시 초기화 |
Packet::Packet(SOCKET sock,size_t _size) { InitInstance(); InitInstance(sock,_size); }
Packet::Packet(void) { InitInstance(); }
void Packet::InitInstance(SOCKET sock,size_t _size) { size = recv(sock,base,_size,0); }
void Packet::InitInstance() { ptr = base; size = 0; }
Packet::~Packet(void) {
}
bool Packet::Packetizing(void *src,size_t _size) { if((size+_size)<=MAX_PACKET_SIZE) { memcpy(base+size,src,_size); size += _size; return true; } return false; } size_t Packet::UnPacketizing(void *dst,size_t _size) { size_t availsize = base+size - ptr;
if(_size > availsize) { _size = availsize; }
memcpy(dst,ptr,_size); ptr += _size; return _size; }
void Packet::Reset() { ptr = base; }
size_t Packet::Serialize(SOCKET sock) { return send(sock,base,size,0); }
int Packet::PacketSize() { return size; } |
Packetizing메서드는 프로그램의 데이터를 패킷의 데이터로 추가하는 메서드이다.
먼저, 현재 보관된 사이즈와 새로 추가할 사이즈의 합이 버퍼의 크기를 벗어나는지 확인을 해야 한다. 벗어날 경우에는 실패한 것이므로 false를 반환하고 벗어나지 않은 경우에는 버퍼에서 현재 보관된 다음 위치에 프로그램 데이터를 복사하고 보관된 사이즈를 갱신시키면 될 것이다.
UnPacketizing메서드는 패킷의 데이터를 프로그램의 주소로 복사하는 메서드이다.
먼저, 현재 언 패킷 가능한 사이즈를 계산하여 요청한 사이즈와 가능한 사이즈 중에 작은 값을 구한다. 해당 사이즈 만큼 언 패킷할 주소에서 프로그램 주소로 복사하고 언 패킷할 위치를 갱신한다. 그리고, 실제 언 패킷한 사이즈를 반환하면 된다.
l 사용 방법
- 송신측
char name[10]="hello"; int i = 23;
Packet *pack= new Packet(); pack->Packetizing(name,10); pack->Packetizing(&i,sizeof(int));
int re = 0; re = pack->Serialize(sock); |
- 수신측
Packet *pack = new Packet(sock); int re = pack->PacketSize();
printf("%d 바이트수신성공\n",re); re =pack->UnPacketizing(name,10); printf("%d 바이트UnPacketizing 성공\n",re); re =pack->UnPacketizing(&i,sizeof(int)); printf("%d 바이트UnPacketizing 성공\n",re);
printf("수신한데이터이름:%s 번호:%d\n",name,i); |
uEhPacket클래스
<그림 3. EhPacket 클래스 구조>
l 멤버 필드
멤버 필드 명 |
설명 |
mh |
메시지 헤더(메시지 아이디 와 바디 길이로 구성) |
l 멤버 메서드
메서드 명 |
설명 |
.ctor(sock,_size) |
소켓에서 수신 받아 Eh패킷을 생성 |
.ctor(msgid) |
Msgid의 Eh패킷을 생성 |
Serialize |
재 정의(헤더와 바디를 하나의 패킷으로 보내기 위함) |
GetMsgId |
Msgid를 반환 |
EhPacket::EhPacket(SOCKET sock,size_t size) { char tempbase[MAX_PACKET_SIZE+sizeof(MsgHead)]; int re = recv(sock,tempbase,size,0);
memcpy(&mh,tempbase,sizeof(MsgHead));
Packetizing(tempbase+sizeof(MsgHead),re - sizeof(MsgHead)); } EhPacket::EhPacket(int _msgid) { mh.msgid = _msgid; }
EhPacket::~EhPacket(void) { }
size_t EhPacket::Serialize(SOCKET sock) {
char tempbase[MAX_PACKET_SIZE+sizeof(MsgHead)];
Reset(); mh.bdlen = Packet::UnPacketizing(tempbase+sizeof(MsgHead),MAX_PACKET_SIZE); memcpy(tempbase,&mh,sizeof(MsgHead)); size_t re= 0; re = send(sock,tempbase,sizeof(MsgHead)+mh.bdlen,0); Reset(); return re; }
int EhPacket::GetMsgId() { return mh.msgid; } |
소켓을 인자로 받는 생성자에서는 소켓에서 수신받아 Eh패킷을 형성해야 한다. 먼저, 임시 버퍼에 수신을 받아 헤더 부분을 복사하고 body부분은 base클래스의 버퍼에 Packetizing하면 된다.
Serialize메서드는 소켓으로 Eh패킷을 전송을 하기 위해 재정의를 해야 한다. EhPacket에는 메시지 헤더와 Body가 분리되어 있기 때문이다.
먼저, base클래스의 UnPacketizing을 통해 임시 버퍼에 body를 복사하고 (이 과정에서 메시지 헤더의 bdlen 필드도 채운다.) 메시지 헤더 부분도 임시 버퍼에 복사를 한다. 이 후 메시지 헤더와 Body부분이 보관된 임시 버퍼를 소켓에 보내면 된다. (Reset을 하는 이유는 Body의 시작 부분부터 얻어와야 되기 때문이다.)
l 사용 방법
- 송신측
char name[10]="hello"; int i = 45;
EhPacket *pack= new EhPacket(10238); pack->Packetizing(name,10); pack->Packetizing(&i,sizeof(int));
int re = 0; re = pack->Serialize(sock); |
- 수신측
char name[10]; int i;
EhPacket *pack = new EhPacket(sock); int re = pack->PacketSize();
printf("메세지헤더아이디:%d\n",pack->GetMsgId()); printf("바디사이즈:%d 바이트수신성공\n",re); re =pack->UnPacketizing(name,10); printf("%d 바이트UnPacketizing 성공\n",re); re =pack->UnPacketizing(&i,sizeof(int)); printf("%d 바이트UnPacketizing 성공\n",re);
printf("수신한데이터이름:%s 번호:%d\n",name,i);
|
uPacketFactory와 응용에서 정의할 Packet클래스(RegReq)
<그림 4. PacketFactory, RegReq 클래스 구조>
l RegReq 멤버 메서드
멤버 필드 명 |
설명 |
.ctor(id,pw) |
id,pw를 패킷화 된 RegReq패킷을 생성 |
.ctor(sock,bdlen) |
소켓에서 Body를 수신받아 RegReq패킷을 생성 |
GetID |
패킷의 id부분을 프로그램의 버퍼로 이동 |
GetPW |
패킷의 pw부분을 프로그램의 버퍼로 이동 |
l PacketFactory 메서드
메서드 명 |
설명 |
MakePacket |
소켓에서 수신받아 Eh패킷을 생성(static 메서드) |
ConvertRegReq |
Eh패킷을 RegReq패킷으로 변환 |
l RegReq 소스
RegReq::RegReq(wchar_t *id,wchar_t *pw):EhPacket(REG_REQ) { int idlen = (lstrlen(id)+1)*2; int pwlen = (lstrlen(pw)+1)*2; Packetizing(&idlen,sizeof(int)); Packetizing(id,idlen); Packetizing(&pwlen,sizeof(int)); Packetizing(pw,pwlen); } RegReq::RegReq(SOCKET sock,int bdlen):EhPacket(REG_REQ) { char tempbase[MAX_PACKET_SIZE]; recv(sock,tempbase,bdlen,0); Packetizing(tempbase,bdlen); }
RegReq::~RegReq(void) { } void RegReq::GetID(wchar_t *dst,int bsize) { int idlen = 0; Reset(); UnPacketizing(&idlen,sizeof(int)); UnPacketizing(dst,idlen); Reset(); } void RegReq::GetPW(wchar_t *dst,int bsize) { int idlen = 0; wchar_t id[MAX_ID_LEN]; Reset(); UnPacketizing(&idlen,sizeof(int)); UnPacketizing(id,idlen); int pwlen = 0; UnPacketizing(&pwlen,sizeof(int)); UnPacketizing(dst,pwlen); Reset(); } |
id,pw를 인자로 받는 생성자에서는 base클래스의 생성자를 통해 메시지 헤더의 msgid가 설정되고 입력 인자인 id,pw를 base클래스의 Packetizing을 통해 body에 추가한다. id와 pw는 가변적인 길이를 갖고 있기 때문에 id의 길이를 먼저 Packetizing하고 id를 Packetizing하는 순으로 이루어져야 한다.
sock,bdlen을 인자로 받는 생성자에서는 base클래스의 생성자를 통해 메시지 헤더의 msgid가 설정되고 bdlen만큼 수신하여 수신한 body를 base클래스의 Packetizing을 이용하여 body에 추가하면 된다. 본 생성자를 호출하기 이전에 PacketFactory에서는 먼저 socket에서 메시지 헤더를 수신 후 메시지 id를 확인하여 해당 id가 REG_REQ일 경우에 사용하도록 설계되었다.
GetID메서드는 body에 있는 id를 UnPacketizing을 통해 프로그램의 버퍼 주소 dst에 복사를 하면 된다. 현재, RegReq패킷의 body구조는 idlen, id, pwlen, pw순으로 되어 있기 때문에 id를 얻기 위해서는 idlen을 먼저 얻고 나서 idlen만큼 id를 얻어오면 된다.
l PacketFactory소스
EhPacket *PacketFactory::MakePacket(SOCKET sock) { MsgHead mh; int re = recv(sock,(char *)&mh,sizeof(mh),0); //보낸패킷을받는다.
switch(mh.msgid) { case REG_REQ: return new RegReq(sock,mh.bdlen); …중략… } return 0;
}
RegReq *PacketFactory::ConvertRegReq(EhPacket *ehpacket) { if(ehpacket->GetMsgId() == REG_REQ) { return dynamic_cast<RegReq *>(ehpacket); } return 0; } |
l 사용 방법
- 송신측
RegReq *regreq = new RegReq(TEXT("hello"),TEXT("yahoo"));
re = regreq->Serialize(sock); |
- 수신측
EhPacket *ehpacket = PacketFactory::MakePacket(sock); switch(ehpacket->GetMsgId() == REG_REQ) { case REG_REQ: RegProc( PacketFactory::ConvertRegReq(ehpacket)); …중략… }
void RegProc(RegReq *regreq) { printf("메세지헤더아이디:%d\n",regreq->GetMsgId());
WCHAR id[MAX_ID_LEN]; WCHAR pw[MAX_ID_LEN]; regreq->GetID(id,MAX_ID_LEN); regreq->GetPW(pw,MAX_ID_LEN); char sid[MAX_ID_LEN]; char spw[MAX_ID_LEN]; WideCharToMultiByte(CP_ACP, 0 ,id,MAX_ID_LEN,sid,MAX_ID_LEN,0,0); WideCharToMultiByte(CP_ACP, 0 ,pw,MAX_ID_LEN,spw,MAX_ID_LEN,0,0); printf("id:%s pw:%s\n",sid,spw); } |
|