tcp bind 에러 원인과 해결법과 SO_REUSEADDR
2019. 7. 22. 19:56ㆍ드론

TIME_WAIT는 연결이 중심이 되는 TCP에서 끊어진 연결과 새로운 연결을 구분짓기 위해서(데이터 무결성을 위해) 생겨났다. 소켓이 닫힌 후 일정 시간 동안 커널에서 해당 포트 바인드를 막음으로써 위와 같은 문제를 해결할 수 있다
약 90초 동안의 TIME_WAIT 시간을 가져서 bind를 막게 되는데, UNIX에서는 이 시간을 건드리지 말라고 한다. 하지만 복잡하지 않는 TCP 소스코드라면 소켓 설정을 달리해서 bind 에러를 막을 수 있다
int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);
level은 소켓, IP, TCP 레벨이 있으며, optname에 SO_REUSEADDR을 지정해 주면 같은 포트에 대해 다른 소켓이 bind()되는 것을 허락해 주기 때문에 bind()에러 없이 프로그램을 실행할 수 있다. 그리고 setsockopt에서는 optval에 옵션 값을 넣어주는데 실행을 시킬 것이기 때문에 1을 넣어서 전달하면 된다
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <string.h> | |
#include <stdlib.h> | |
#include <unistd.h> | |
#include <arpa/inet.h> | |
#include <sys/socket.h> | |
void error_handle(char *msg); | |
int main(int argc, char **argv) | |
{ | |
int serv_sock, cli_sock; | |
int opt; | |
struct sockaddr_in serv_addr, cli_addr; | |
socklen_t cli_addr_size; | |
char msg[256] = "Hello world!"; | |
if(argc != 2) { | |
printf("usage : %s <port>\n", argv[0]); | |
exit(1); | |
} | |
serv_sock = socket(PF_INET, SOCK_STREAM, 0); | |
if(serv_sock == -1) { | |
error_handle("socket() error"); | |
} | |
opt = 1; | |
setsockopt(serv_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); | |
memset(&serv_addr, 0, sizeof(serv_addr)); | |
serv_addr.sin_family = AF_INET; | |
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); | |
serv_addr.sin_port = htons(atoi(argv[1])); | |
if(bind(serv_sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) { | |
error_handle("bind() error"); | |
} | |
if(listen(serv_sock, 5) < 0) { | |
error_handle("listen() error"); | |
} | |
cli_addr_size = sizeof(cli_addr); | |
cli_sock = accept(serv_sock, (struct sockaddr *)&cli_addr, &cli_addr_size); | |
if(cli_sock < 0){ | |
error_handle("accept() error"); | |
} | |
write(cli_sock, msg, strlen(msg)); | |
close(cli_sock); | |
close(serv_sock); | |
return 0; | |
} | |
void error_handle(char *msg) | |
{ | |
fputs(msg, stderr); | |
fputc('\n', stderr); | |
exit(1); | |
} |
'드론' 카테고리의 다른 글
socket 함수의 3번째 인자 (0) | 2019.07.23 |
---|---|
send/recv partial Error 방지하는 법 (0) | 2019.07.23 |
SOCK_DGRAM은 read/write 사용할 수 없는 이유 (0) | 2019.07.22 |
동작 중인 포트 조회해서 지우기 (0) | 2019.07.22 |
TCP 네트워크 프로그래밍 - 1 (0) | 2019.07.22 |