반응형
setsockopt(SO_REUSEADR)를 사용하는 방법
나는 산딸기 파이에서 내 http 서버를 운영하고 있다.문제는 프로그램을 중지하고 다시 시작하면 포트를 더 이상 사용할 수 없다는 겁니다.가끔 많은 요청을 받을 때도 같은 문제가 생긴다.
오류가 발생해도 포트를 계속 사용할 수 있도록 SO_REUSEADR을 사용하고 싶지만 설정 운이 없었다.아래는 내 암호야.
내가 받는 오류는 "Binding on binding:이미 사용 중인 주소".
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
void error(const char *msg)
{
perror(msg);
exit(1);
}
int main(int argc, char *argv[])
{
printf("Starting Listener\n");
int sockfd, newsockfd, portno;
socklen_t clilen;
char buffer[256];
struct sockaddr_in serv_addr, cli_addr;
int n;
if (argc < 2) {
fprintf(stderr,"ERROR, no port provided\n");
exit(1);
}
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
bzero((char *) &serv_addr, sizeof(serv_addr));
portno = atoi(argv[1]);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);
if (bind(sockfd, (struct sockaddr *) &serv_addr,
sizeof(serv_addr)) < 0)
error("ERROR on binding");
printf("about to listen\n");
listen(sockfd,5);
printf("finished listening\n");
clilen = sizeof(cli_addr);
printf("About to accept\n");
int i;
for(i=0; i<100; i++){
newsockfd = accept(sockfd,
(struct sockaddr *) &cli_addr,
&clilen);
if (newsockfd < 0)
error("ERROR on accept");
bzero(buffer,256);
n = read(newsockfd,buffer,255);
if (n < 0) error("ERROR reading from socket");
printf("Here is the message: %s\n",buffer);
n = write(newsockfd,"I got your message",18);
if (n < 0) error("ERROR writing to socket");
close(newsockfd);
}
close(sockfd);
return 0;
}
다음 이후:
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
표준 C99 복합 리터럴 지원을 사용하여 다음을 추가할 수 있다.
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &(int){1}, sizeof(int)) < 0)
error("setsockopt(SO_REUSEADDR) failed");
또는 :
int enable = 1;
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)) < 0)
error("setsockopt(SO_REUSEADDR) failed");
libc 릴리즈에 따라 소켓(7) 설명서에 설명된 대로 SO_REUSEADDR과 SO_REUSEPORT 소켓 옵션을 모두 설정해야 할 수 있다.
SO_REUSEPORT (since Linux 3.9) Permits multiple AF_INET or AF_INET6 sockets to be bound to an identical socket address. This option must be set on each socket (including the first socket) prior to calling bind(2) on the socket. To prevent port hijacking, all of the processes binding to the same address must have the same effective UID. This option can be employed with both TCP and UDP sockets.
이 소켓 옵션은 커널 3.9와 함께 나타나고 라즈베리는 3.12.x를 사용하므로 SO_REUSEPORT를 설정해야 한다.
다음과 같이 바인드를 호출하기 전에 두 가지 옵션을 설정할 수 있다.
int reuse = 1;
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse, sizeof(reuse)) < 0)
perror("setsockopt(SO_REUSEADDR) failed");
#ifdef SO_REUSEPORT
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, (const char*)&reuse, sizeof(reuse)) < 0)
perror("setsockopt(SO_REUSEPORT) failed");
#endif
SO_LINGER 옵션(시간 초과 0)을 사용해야 할 것 같아.이 경우 프로그램을 닫은 후 바로 연결이 닫히고 다음 다시 시작하면 다시 바인딩할 수 있다.
예:
linger lin;
lin.l_onoff = 0;
lin.l_linger = 0;
setsockopt(fd, SOL_SOCKET, SO_LINGER, (const char *)&lin, sizeof(int));
정의 참조: http://man7.org/linux/man-pages/man7/socket.7.html
SO_LINGER
Sets or gets the SO_LINGER option. The argument is a linger
structure.
struct linger {
int l_onoff; /* linger active */
int l_linger; /* how many seconds to linger for */
};
When enabled, a close(2) or shutdown(2) will not return until
all queued messages for the socket have been successfully sent
or the linger timeout has been reached. Otherwise, the call
returns immediately and the closing is done in the background.
When the socket is closed as part of exit(2), it always
lingers in the background.
SO_LINGER에 대한 자세한 정보: TCP 옵션 SO_LINGER(0) - 필요한 경우
참조URL: https://stackoverflow.com/questions/24194961/how-do-i-use-setsockoptso-reuseaddr
반응형
'programing' 카테고리의 다른 글
Enum과 Define 문 간의 차이 (0) | 2022.04.26 |
---|---|
String을 사용하는 것이 더 좋은 습관인가?문자열 위에 형식 자바에서 연결하시겠습니까? (0) | 2022.04.26 |
Vuex에서 Interval을 지우는 방법 (0) | 2022.04.26 |
요소 ui el 선택 옵션 워드랩 (0) | 2022.04.26 |
Unix에 대한 재귀 mkdir() 시스템 호출 (0) | 2022.04.26 |