안녕하세요
tcp 패킷의 경우 크기가 제멋대로 들어오잖아요
그걸 프로그램에서 처리할때 큐같은데 차례대로 집어넣어서 순차적으로 파싱해야할가요 ?
아니면 큐같은거 없이 받는 즉시 파싱 남는것 다음에 파싱 이런식으로 해야할까요 ?
보통 tcp 패킷 처리할때 어떡게 하나요 ?
책보니 정해진 에코 메시지만 다루고 있어서
직접 패킷 구조를 만들어서 사용할때 어떡게 다루어야 효율적일지 모르겠네요
가령
struct 구조
{
uint32_t size;
uint32_t type;
uint8_t *ptr;
};
이런식일때 패킷에서 4 바이트크기의 size 변수를 파싱할때 네트워 tcp 상에 3 바이트가 왔다면 (가령)
다음번 100 바이트... 이런식이면 3 + 1 바이트를 size 파싱, type 에 해당하는 그다음 데이터 4 바이트 파싱
나머지 데이터 파싱... 뭔가 간단한건데 어렵게 하는거 같아서 질문올립니다.
그럼 좋은 답변 부탁드리며... 좋은 하루 되세요
tcp 패킷 받아서 사용하기
Moderator: 류광
-
- Posts: 214
- Joined: 2006-10-30 10:56
-
- Posts: 4
- Joined: 2009-11-20 12:20
소스 참고 하시기 바랍니다. ACE 가 중간중간에 들어가있어서... 도움이 될지는... OTL
int
ZZL_Simple_Handler::recv (ACE_Message_Block *&mb)
{
if (this->msg_frag_ == 0)// No existing fragment...
ACE_NEW_RETURN (this->msg_frag_, ACE_Message_Block (ACE_DEFAULT_CDR_BUFSIZE), -1);
ssize_t header_received = 0;
ssize_t header_bytes_left_to_read = ZZL_HEADER_SIZE - this->msg_frag_->length ();
//해더를 받을 차례이거나, 헤더를 받다 말았다.
if (header_bytes_left_to_read > 0 )
{
header_received = this->peer().recv(this->msg_frag_->wr_ptr(), header_bytes_left_to_read);
if (header_received == -1 /* error */|| header_received == 0 /* EOF */)
{
ZZL_ERROR ("Recv error during header read err_code[%d]\n", ARG1(::WSAGetLastError()));
ZZL_DEBUG ("attempted to read %d bytes\n", ARG1(header_bytes_left_to_read));
this->msg_frag_ = this->msg_frag_->release ();
return header_received;
}
this->msg_frag_->wr_ptr (header_received);
if (this->msg_frag_->length () < ZZL_HEADER_SIZE)
{
ZZL_DEBUG ("Partial header received: only %d bytes\n", ARG1(this->msg_frag_->length ()));
errno = EWOULDBLOCK;
return -1;
}
ZZL_Packet_Parser parser(*msg_frag_);
size_t body_size = parser.written_body_size ();
size_t msg_size = parser.packet_size ();
if (body_size > 4096) //ServiceBase::getMaxPacketBodySize()
{
errno = EINVAL;
ZZL_DEBUG ("Data payload(body size) is too big (%d bytes)\n", ARG1(body_size));
mb->release ();
return 0;
}
this->msg_frag_->size(msg_size);
}
// 자 헤더를 받았으니. Body를 받자, 처음일수도 있고, 바디가 너무 커서, 2번째 이상일수도 있다.(EWOULDBLOCK)
// class Message 내부에 header 필드 자체가 없음으로, 아쉽지만, message_type, body size -> hard coding
u_short body_size = *((u_short *) (this->msg_frag_->rd_ptr () + 2)); // first 2byte: msg_type, next 2byte: bodysize
ssize_t data_bytes_left_to_read = body_size - (this->msg_frag_->length() - ZZL_HEADER_SIZE);
ssize_t body_received = !data_bytes_left_to_read ? 0 :
this->peer ().recv (this->msg_frag_->wr_ptr (), data_bytes_left_to_read);
switch (body_received)
{
case -1:
if (errno == EWOULDBLOCK)
return -1;
else
/* FALLTHROUGH */;
case 0: // Premature EOF.
if (data_bytes_left_to_read)
{
this->msg_frag_ = this->msg_frag_->release ();
return 0;
}
/* FALLTHROUGH */;
default:
this->msg_frag_->wr_ptr (body_received);
if (body_received != data_bytes_left_to_read)
{
errno = EWOULDBLOCK;
return -1;
}
else
{
this->msg_frag_->rd_ptr (this->msg_frag_->base ());
mb = this->msg_frag_;
this->msg_frag_ = 0;
}
return body_received + header_received;
}
}
int
ZZL_Simple_Handler::recv (ACE_Message_Block *&mb)
{
if (this->msg_frag_ == 0)// No existing fragment...
ACE_NEW_RETURN (this->msg_frag_, ACE_Message_Block (ACE_DEFAULT_CDR_BUFSIZE), -1);
ssize_t header_received = 0;
ssize_t header_bytes_left_to_read = ZZL_HEADER_SIZE - this->msg_frag_->length ();
//해더를 받을 차례이거나, 헤더를 받다 말았다.
if (header_bytes_left_to_read > 0 )
{
header_received = this->peer().recv(this->msg_frag_->wr_ptr(), header_bytes_left_to_read);
if (header_received == -1 /* error */|| header_received == 0 /* EOF */)
{
ZZL_ERROR ("Recv error during header read err_code[%d]\n", ARG1(::WSAGetLastError()));
ZZL_DEBUG ("attempted to read %d bytes\n", ARG1(header_bytes_left_to_read));
this->msg_frag_ = this->msg_frag_->release ();
return header_received;
}
this->msg_frag_->wr_ptr (header_received);
if (this->msg_frag_->length () < ZZL_HEADER_SIZE)
{
ZZL_DEBUG ("Partial header received: only %d bytes\n", ARG1(this->msg_frag_->length ()));
errno = EWOULDBLOCK;
return -1;
}
ZZL_Packet_Parser parser(*msg_frag_);
size_t body_size = parser.written_body_size ();
size_t msg_size = parser.packet_size ();
if (body_size > 4096) //ServiceBase::getMaxPacketBodySize()
{
errno = EINVAL;
ZZL_DEBUG ("Data payload(body size) is too big (%d bytes)\n", ARG1(body_size));
mb->release ();
return 0;
}
this->msg_frag_->size(msg_size);
}
// 자 헤더를 받았으니. Body를 받자, 처음일수도 있고, 바디가 너무 커서, 2번째 이상일수도 있다.(EWOULDBLOCK)
// class Message 내부에 header 필드 자체가 없음으로, 아쉽지만, message_type, body size -> hard coding
u_short body_size = *((u_short *) (this->msg_frag_->rd_ptr () + 2)); // first 2byte: msg_type, next 2byte: bodysize
ssize_t data_bytes_left_to_read = body_size - (this->msg_frag_->length() - ZZL_HEADER_SIZE);
ssize_t body_received = !data_bytes_left_to_read ? 0 :
this->peer ().recv (this->msg_frag_->wr_ptr (), data_bytes_left_to_read);
switch (body_received)
{
case -1:
if (errno == EWOULDBLOCK)
return -1;
else
/* FALLTHROUGH */;
case 0: // Premature EOF.
if (data_bytes_left_to_read)
{
this->msg_frag_ = this->msg_frag_->release ();
return 0;
}
/* FALLTHROUGH */;
default:
this->msg_frag_->wr_ptr (body_received);
if (body_received != data_bytes_left_to_read)
{
errno = EWOULDBLOCK;
return -1;
}
else
{
this->msg_frag_->rd_ptr (this->msg_frag_->base ());
mb = this->msg_frag_;
this->msg_frag_ = 0;
}
return body_received + header_received;
}
}