TCP로 메시지 수신 중 메시지 유실
제가 구조체로 정의한 메지시(size 1024)를 TCP로 주고 받는 두 프로세스가 있습니다.
snd : 1024bytes 메시지를 usleep(1000)마다 send하는 프로세스(sequence number도 넘김니다.)
rcv : 1024bytes * 1024 짜리 버퍼에 recv() 할때마다 count도 하고 받은 메시지의 seq도 출력하는 프로세스
sig : rcv 프로세스에게 sleep(1)마다 SIGSTOP와 SIGCONT를 반복해서 보내는 프로세스
이렇게 3개의 프로세스가 있는데요 rcv에서 확인해보면 seq와 count가 다릅니다. 즉, 메시지가 유실이 된다는 건데요. TCP는 메시지 유실이 없는걸로 알고 있는데... 왜 메시지 유실이 생길까요? 버퍼사이즈도 충분하다고 생각하고 있고 더 키워도 보았는데 유실은 생깁니다...
제 짧은 생각으로는 SIGSTOP동안 버퍼에 메시지를 담지 못하는듯 하는데요(그러면 snd가 보내지 말아야 한다고 생각했지만... 실제로 유실이 발생하네요 ㅠ)
SIGSTOP과 메시지 유실 관련이 있나요?
해법도 알려주시면 너무 감사합니다.^^
-----------------------------------------
rcv.cpp
void create_server_socket_select(server_info_t *serv_info)
{
int client[MAX_CLIENT]; // array of client socket fd
int maxfd, maxi;
int nready;
int i;
fd_set fd_array, init_array; // fd[0] ... fd[maxfd], init_array exist for initialize
int bind_result, write_result, msg_len, addr_len;
int socket_fd, connect_fd;
char buf[MSG_LEN];
struct sockaddr_in server_addr, client_addr;
pid_t childpid;
struct msg_s *msg;
int cnt = 0;
socket_fd = socket(AF_INET, SOCK_STREAM, 0); // create socket for listen
if(socket_fd < 0){
printf("server: can't create socket.\n");
exit(-1);
}
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET; // set IPv4
server_addr.sin_addr.s_addr = htonl(INADDR_ANY); // transform ip address to big endian
server_addr.sin_port = htons(serv_info->port_number); // transform port number to big endian
// printf("serv_info->port_number: %d\n", serv_info->port_number);
bind_result = bind(socket_fd, (struct sockaddr *)&server_addr, sizeof(server_addr));
if(bind_result < 0){
printf("server: bind error!!\n");
exit(-1);
listen(socket_fd, LISTENQ); // socket_fd is listen socket
maxfd = socket_fd; // initialize
maxi = -1; // index into client[] array
for(i=0 ; i
client[i] = -1; // -1 indicates available entry
}
FD_ZERO(&init_array); // all bit off(0) in init_array
FD_SET(socket_fd, &init_array); // turn on(1) bit for socket_fd번째 in init_array
while(1){
fd_array = init_array; // structure assignment
nready = select(maxfd+1, &fd_array, NULL, NULL, NULL);
if(FD_ISSET(socket_fd, &fd_array)){
addr_len = sizeof(client_addr);
connect_fd = accept(socket_fd, (struct sockaddr *)&client_addr, &addr_len); // connect_fd is connect socket
if(connect_fd < 0){
printf("server: accept error!!\n");
exit(-1);
}
printf("connection new client (connect_fd: %d)...\n", connect_fd);
for(i=0 ; i
if(client[i] < 0){
client[i] = connect_fd; // save descriptor in fd_array
break;
}
}
if(i == MAX_CLIENT){
printf("too many clients\n");
}
FD_SET(connect_fd, &init_array); // add new descriptor to set
if(connect_fd > maxfd){
maxfd = connect_fd; // for select
}
if(i > maxi){
maxi = i; // max index in client[] array
}
if(--nready <= 0){
continue; // no more readable descriptor
}
}
for(i=0 ; i<=maxi ; i++){ // check all clients for data
connect_fd = client[i];
if(connect_fd < 0){
continue;
}
if(FD_ISSET(connect_fd, &fd_array)){
memset(buf, '\0', sizeof(buf));
msg_len = read(connect_fd, buf, MSG_LEN);
if(msg_len == 0){
close(connect_fd);
FD_CLR(connect_fd, &init_array);
client[i] = -1;
}
// what you want to do
else{
msg = (struct msg_s *)buf; // msg start pointer
printf("%d\n", msg->seq);
cnt++;
printf("cnt : %d\n", cnt);
}
if(--nready <= 0){
break; // no more readable descriptor
}
}
}
}
return;
}
-----------------------------------------
snd.cpp
#include
#include
#include
#include
#include
#include
#include
#define BUFF_SIZE 4056
#define MAX_MSG 10000
struct msg_s{
int seq;
char msg[16];
};
int main( int argc, char **argv)
{
int client_socket;
struct msg_s msg;
struct sockaddr_in server_addr;
char buff[BUFF_SIZE+5];
client_socket = socket( PF_INET, SOCK_STREAM, 0);
if( -1 == client_socket)
{
printf( "socket 생성 실패\n");
exit( 1);
}
memset( &server_addr, 0, sizeof( server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons( 4000);
server_addr.sin_addr.s_addr= inet_addr( "127.0.0.1");
if( -1 == connect( client_socket, (struct sockaddr*)&server_addr,
sizeof( server_addr) ) )
{
printf( "접속 실패\n");
exit( 1);
}
for(int i = 0 ; i < MAX_MSG ; i++){
msg.seq = i;
send( client_socket, &msg, sizeof(struct msg_s) + 1, 0); // +1: NULL까지 포함해서 전송
printf("send: %d\n", msg.seq);
usleep(1000);
}
return 0;
}
MSG_LEN 값이 얼마
MSG_LEN 값이 얼마 인지에 따라 작동 방식이 다를 텐데요.
send를 1024씩 여러번 했다고
recv가 1024씩 여러번 되는 건 아니라는거 아시나요?
send를 1024로 두번 한 후에 recv를 하면 한번에 2048로 수신 될 수 있습니다.
그러면 메시지
그러면 메시지 유실이 안일어났을 수도 있다는 것인가요?
첫번째 코드가 rcv.cpp인데요
memset(buf, '\0', sizeof(buf));
msg_len = read(connect_fd, buf, MSG_LEN);
MSG_LEN만큼만 read 하도록 코딩했는데
한꺼번에 2048을 읽어 들이나요?
msg_len의 길이를 확인해 보세요
msg_len의 길이를 확인해 보세요.
msg_len = read(connect_fd, buf, MSG_LEN);
디버깅하지 말고 트레이스로 Log로 찍어 보세요.
이상한 값이 나올 겁니다.
일반적으로 TCP 커넥션이 맺어 질 때 MSS는 1460바이트이기 때문에
send를 1024, 1024를 하더라도
수신에서는 1460, 588 로 수신될 수 있습니다.
www.gilgil.net
댓글 달기