소켓 프로그램문의 (서버쪽)

익명 사용자의 이미지

고수님들의 조언을 바랍니다.
다음 서버 프로그램에서 소켓을 리슨하고 있다가
크라이언트에서 접속이 오면 통신하도록 되어있는데
이상하게도 크라이언트에서 접속을 끊으면 정상동작을 하는데
case 2 문에서 강제로 핸들러를 제거하면
case 0 문에서 'EADDRINUSE' 로 사용중이라고 나옵니다.
그대로 두면 1분후에 정상으로 돌아는 오는데
이게 무슨 문제때문일까요.

void main (int arfc, char **argv)
{
fd_set readable, rset, wset;
int len, ret, current_time;
struct sockaddr_in sock;
struct sockaddr_in client;
struct timeval timeout;
int val, i;

whiel (1)
{
switch (SYS.flag)
{
case 0 //============================================
SYS.fd = socket(AF_INET, SOCK_STREAM, 0);
sock.sin_family = AF_INET;
sock.sin_port = htons(4000);
sock.sin_addr.s_addr = INADDR_ANY;
bzero (&(sock.sin_zero), 8);
if (bind (SYS.fd, (struct sockaddr *)&sock, sizeof
(sock)) < 0)
{
switch (errno)
{
case EBADF printf ("1 "); break;
case ENOTSOCK printf ("2 "); break;
case EINVAL printf ("3 "); break;
case EADDRNOTAVAIL printf ("4 "); break;
case EADDRINUSE printf ("5 "); break;
default printf ("%d ", errno);
}

printf("Server Can't bind local address.\n");
close (SYS.fd);
return;
}
if (listen (SYS.fd, LISTENQ) == -1)
{
close(SYS.fd);
SYS.flag = NO_ACTION;
return;
}
SYS.flag = LISTEN;
break;

case 1 //=============================================
FD_ZERO(&rset);
FD_SET(SYS.fd, &rset);
timeout.tv_sec = 0;
timeout.tv_usec = 1000;
ret = select (SYS.fd + 1, &rset, NULL, NULL, &timeout);
if (ret < 0)
{
close(SYS.fd);
SYS.flag = 0;
return;
}

if (ret == 0) return;
if (FD_ISSET(SYS.fd, &rset))
{
fcntl (SYS.fd, F_SETFL, O_NDELAY);
len = sizeof (client);
SYS.cfd = accept (SYS.fd, (struct sockaddr *)&client,
&len);
fcntl (SYS.cfd, F_SETFL, 0);
SYS.flag = 2;
close (SYS.fd); // 이전 핸들러 제거
}
break;
case 2 //===============================================

close (SYS.cfd); // 이부분에서 강제종료시 문제생김
SYS.flag = 0;
break;

FD_ZERO (&readable);
FD_SET (SYS.cfd, &readable);
timeout.tv_sec = 0;
timeout.tv_usec = 100;
ret = select(SYS.cfd+1, &readable, NULL, NULL, &timeout);
if (ret < 0)
{
close (SYS.cfd);
SYS.flag = 0;
break;
}
ret = FD_ISSET(SYS.cfd, &readable);
if (ret < 0)
{
close (SYS.cfd);
SYS.flag = 0;
break;
}
if (ret == 0) break;
len = read (SYS.cfd, SYS.WORK, sizeof(SYS.WORK));
if (len <= 0)
{
close (SYS.cfd);
SYS.flag = 0;
break;
}
break;
}
}
}

익명 사용자의 이미지


클라이언트쪽이 연결되어 상태에서 서버가 그냥 close 해버리면..
님과 같은 상황이 벌어집니다.. 몇분 지나면 다시 bind가 되지요..^^
tcp/ip쪽을 점더 뒤져보시길..

익명 사용자의 이미지

그것은 TCP state 전이 상태가 변화면서 발생하는것입니다.

즉 강제로 종료하면 TIME-WAIT가 걸려있어..
TIME_WAIT시간 동안은 다시 바인딩이 안되지요...
(긍데 바인딩을 무한루프 돌리는게 이상하네여 ^^)

즉 TCP/IP의 상태 전이표를 한번 자세히 보시면 이해가 되시리라 생각이
듭니다..

그럼 즐프하세요,,

익명 사용자의 이미지

간단한 방법이 있제...

setsockopt를 사용하여 socket reuse flag를 Set하면 간단하게 위의
문제가 해졀 되지여.

열심히 하쇼..