예제의 프로그램을 실행하면 이상없이 자료 송수신이 잘됩니다. 그런데 문제는 server쪽입니다. 프로그램을 강제 종료하든 그냥 종료하든 다시 실행하면 bind() 에서 에러가 발생합니다.

프로그램에도 이상이 없는데 왜 이럴까? 또, 몇 초 있다가 다시 실행하면 아무 이상없이 실행 됩니다.

이유는 프로그램에서 소켓을 close() 함수를 이용하여 소켓을 소멸 시켜도 커널은 바로 속멸 시키지 않고 몇 초 정도 생명(?)을 유지시켜 줍니다. 이렇게 함으로써 클라이언트와 아직 처리되지 않는 전문을 마저 처리할 수 있도록 하기 위함입니다.

이와 같이 바로 죽이지 않고 대기 시키는 상태를 TIME_WAIT 상태라고 하는데, bind()된 소켓이 아직 죽지도 않았는데 같은 주소, 같은 포트로 또 다른 소켓이 bind() 요청을 해오니 커널에서는 에러를 낼 수 밖에 없습니다.

또한 bind() 에러가 발생한 상태에서 다시 bind() 요청을 하면 이전 소켓의 생명 시간은 다시 초기화가 되기 때문에 계속 bind()함수를 호출해 주면 이전 소켓은 더 오래 살아 남습니다. 어쩔 수 없이 이전 소켓의 TIME-WAIT 상태가 끝날 때까지 기다려야 합니다.

소켓 옵션에 SO_REUSEADDR 적용

프로그램을 작성하면서 매번 디버깅 때 마다 기다리고 있을 수 만은 없죠. 이럴 때 소켓의 옵션, 즉 속성을 바꾸어 줍니다.

int option;

server_socket = socket( PF_INET, SOCK_STREAM, 0);

option = 1; // SO_REUSEADDR 의 옵션 값을 TRUE 로
setsockopt(
server_socket, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(option) );

이렇게 SO_REUSEADDR을 지정해 주면 같은 포트에 대해 다른 소켓이 bind()되는 것을 허락해 주기 때문에 bind()에러 없이 프로그램을 실행할 수 있습니다.

출처 : http://forum.falinux.com/zbxe/?document_srl=406056