소켓을 사용하여 무언가를 테스트하고 있는데 이상한 상황에 직면했습니다.
나는 C로 매우 간단한 TCP 서버를 작성했고 여러 연결 시도가 동시에 허용될 때 어떤 일이 일어나는지 확인하기 위해 accept() 후에 서버를 차단했습니다.
다음은 서버 코드에서 발췌한 내용입니다.
//listen()
if( (listen(sock,5)) == -1) {
perror("listen");
exit(-1);
}
//accept()
if( (cli = accept(sock, (struct sockaddr *) &client, &len)) == 1 ){
perror("accept");
exit(-1);
}
printf("entrez un int : ");
scanf("%d",&toto);
서버가 사용자에게 정수를 입력하라고 요청할 때 텔넷을 사용하여 여러 클라이언트를 연결하려고 합니다.
Bastion이 첫 번째이고 모든 것이 잘됩니다.
root@[...] :/home/[...]/workspace/sockets# netstat -antp | grep 10003
tcp 0 0 0.0.0.0:10003 0.0.0.0:* LISTEN 25832/toto
tcp 0 0 127.0.0.1:10003 127.0.0.1:51166 ESTABLISHED 25832/toto
tcp 0 0 127.0.0.1:51166 127.0.0.1:10003 ESTABLISHED 25845/telnet
그러나 첫 번째 연결 이후에는 몇 가지 연결이 있으며 이를 소유한 프로세스와 해당 PID를 볼 수 없습니다.
root@[...] :/home/[...]/workspace/sockets# netstat -antp | grep 10003
tcp 0 0 0.0.0.0:10003 0.0.0.0:* LISTEN 25832/toto
tcp 0 0 127.0.0.1:10003 127.0.0.1:51166 ESTABLISHED 25832/toto
tcp 0 0 127.0.0.1:51166 127.0.0.1:10003 ESTABLISHED 25845/telnet
tcp 0 0 127.0.0.1:10003 127.0.0.1:51168 ESTABLISHED -
tcp 0 0 127.0.0.1:51168 127.0.0.1:10003 ESTABLISHED 25852/telnet
세 번째:
root@[...] :/home/[...]/workspace/sockets# netstat -antp | grep 10003
tcp 0 0 0.0.0.0:10003 0.0.0.0:* LISTEN 25832/toto
tcp 0 0 127.0.0.1:10003 127.0.0.1:51166 ESTABLISHED 25832/toto
tcp 0 0 127.0.0.1:51166 127.0.0.1:10003 ESTABLISHED 25845/telnet
tcp 0 0 127.0.0.1:10003 127.0.0.1:51172 ESTABLISHED -
tcp 0 0 127.0.0.1:10003 127.0.0.1:51168 ESTABLISHED -
tcp 0 0 127.0.0.1:51168 127.0.0.1:10003 ESTABLISHED 25852/telnet
tcp 0 0 127.0.0.1:51172 127.0.0.1:10003 ESTABLISHED 25860/telnet
며칠 후 netstat -antpe를 루트로 사용하여 다시 시도했는데 이것이 내가 얻은 것입니다.
root@[...] :/home/[...]/workspace/sockets# netstat -antpe | grep 10003
tcp 0 0 0.0.0.0:10003 0.0.0.0:* LISTEN 1000 327680 22399/toto
tcp 0 0 127.0.0.1:33286 127.0.0.1:10003 ESTABLISHED 1000 417202 22884/telnet
tcp 0 0 127.0.0.1:10003 127.0.0.1:33046 ESTABLISHED 0 0 -
tcp 0 0 127.0.0.1:10003 127.0.0.1:33286 ESTABLISHED 0 0 -
tcp 0 0 127.0.0.1:33044 127.0.0.1:10003 ESTABLISHED 1000 332810 22402/telnet
tcp 0 0 127.0.0.1:33046 127.0.0.1:10003 ESTABLISHED 1000 331200 22410/telnet
tcp 0 0 127.0.0.1:10003 127.0.0.1:33044 ESTABLISHED 1000 332801 22399/toto
프로세스나 연결의 inode가 0이 될 수 있는 이유는 무엇입니까? 무슨 일인지 설명해 줄 수 있는 사람이 있나요?
답변1
서버 코드는 accept()
한 번만 호출됩니다. 따라서 첫 번째 연결 시도만 효과적으로 승인되고 나머지 클라이언트 연결은 커널 공간의 연결 요청 대기열에 남아 있습니다. 다시 호출 되면 accept()
다음 클라이언트 연결이 대기열에서 검색됩니다.
클라이언트 연결이 커널 공간에 남아 있는 동안에는 참여하는 모든 소켓 설명자에서 옵션을 활성화하는 경우 여러 프로세스 또는 스레드가 고유한 주소 및 포트 쌍의 연결을 합법적으로 허용할 수 있으므로 어떤 프로세스도 클라이언트 연결을 소유하지 않습니다 SO_REUSEPORT
.
SO_REUSEPORT
호출 전에 다음 코드 조각을 추가 하고 여러 서버를 실행하여 bind()
이 옵션을 직접 테스트 할 수 있습니다 . 커널이 그들 사이에 요청을 분배한다는 것을 알게 될 것입니다.
{
int enabled = -1;
if (setsockopt (sockd, SOL_SOCKET, SO_REUSEPORT,
(void*) &enabled, sizeof (enabled)) < 0) {
perror ("setsockopt");
}
}
참조 출처 man 2 accept
:
이것수락 (sockfd)시스템 호출은 연결 기반 소켓 유형(SOCK_STREAM, SOCK_SEQPACKET)과 함께 사용됩니다. 청취 소켓의 보류 중인 연결 큐에서 첫 번째 연결 요청을 가져옵니다.양말, 연결된 새 소켓을 생성하고 소켓을 참조하는 새 파일 설명자를 반환합니다. 새로 생성된 소켓은 수신 대기 상태가 아닙니다. 원래 소켓양말이 호출의 영향을 받지 않습니다.
참조 출처 man 7 socket
:
SO_REUSEPORT(리눅스 3.9부터)
여러 AF_INET 또는 AF_INET6 소켓을 동일한 소켓 주소에 바인딩할 수 있습니다. 이 옵션은 호출하기 전에 모든 소켓(첫 번째 소켓 포함)에 설정되어야 합니다.바인딩(2)소켓에. 포트 하이재킹을 방지하려면 동일한 주소에 바인딩된 모든 프로세스는 동일한 유효 UID를 가져야 합니다. 이 옵션은 TCP 및 UDP 소켓에 사용할 수 있습니다.
TCP 소켓의 경우 이 옵션을 사용하면수락(2)다중 스레드 서버의 로드 분산은 각 스레드에 대해 서로 다른 수신기 소켓을 사용하여 향상될 수 있습니다. 이는 단일 accept(2) 스레드를 사용하여 연결을 분산하거나 여러 스레드를 사용하여 경쟁하는 것과 같은 기존 기술에 비해 향상된 로드 분산을 제공합니다.수락(2)같은 콘센트에서.
UDP 소켓의 경우 이 옵션을 사용하면 여러 프로세스가 동일한 소켓에서 데이터그램을 수신하기 위해 경쟁하는 기존 기술보다 여러 프로세스(또는 스레드)에 들어오는 데이터그램을 더 효과적으로 배포할 수 있습니다.