특정 포트의 서버와 상호 작용하는 작은 프로그램을 작성했습니다. 프로그램은 잘 작동하지만 :
프로그램이 예기치 않게 종료되면 해당 소켓 연결이 CLOSE_WAIT
상태 로 표시됩니다 . 프로그램을 실행하려고하면 중단되고 강제로 닫아야하므로 더 많은 CLOSE_WAIT
소켓 연결 이 축적 됩니다.
이러한 연결을 플러시하는 방법이 있습니까?
특정 포트의 서버와 상호 작용하는 작은 프로그램을 작성했습니다. 프로그램은 잘 작동하지만 :
프로그램이 예기치 않게 종료되면 해당 소켓 연결이 CLOSE_WAIT
상태 로 표시됩니다 . 프로그램을 실행하려고하면 중단되고 강제로 닫아야하므로 더 많은 CLOSE_WAIT
소켓 연결 이 축적 됩니다.
이러한 연결을 플러시하는 방법이 있습니까?
답변:
CLOSE_WAIT
프로그램이 여전히 실행 중이고 소켓을 닫지 않았 음을 의미합니다 (커널이 그렇게하기를 기다리고 있음). 추가 -p
할 netstat
PID를 얻기 위해, 다음 (더 강력하게 죽일 SIGKILL
필요한 경우). 그것은 당신의 CLOSE_WAIT
소켓을 제거해야합니다 . 를 사용 ps
하여 pid를 찾을 수도 있습니다 .
SO_REUSEADDR
서버 및 TIME_WAIT
소켓 용이므로 여기에는 적용되지 않습니다.
Crist Clark에 의해 설명 된대로 .
CLOSE_WAIT는 연결의 로컬 끝이 다른 쪽 끝에서 FIN을 받았지만 OS는 로컬 끝의 프로그램이 실제로 연결을 닫을 때까지 기다리고 있음을 의미합니다.
문제는 로컬 컴퓨터에서 실행중인 프로그램이 소켓을 닫지 않는다는 것입니다. TCP 튜닝 문제가 아닙니다. 연결은 프로그램이 연결을 열린 상태로 유지하는 동안 CLOSE_WAIT에 영원히있을 수 있습니다 (정확하게).
로컬 프로그램이 소켓을 닫으면 OS는 FIN의 ACK를 기다리는 동안 LAST_ACK로 전환하는 원격 끝으로 FIN을 보낼 수 있습니다. 수신되면 연결이 완료되고 연결 테이블에서 삭제됩니다 (엔드가 CLOSE_WAIT 인 경우 TIME_WAIT 상태 가 되지 않음 ).
close()
또는 closesocket()
사용중인 플랫폼에 따라.
최신 Tomcat 서버 (7.0.40)에서도 동일한 문제가 발생합니다. 며칠 동안 한 번 응답하지 않습니다.
열린 연결을 보려면 다음을 사용할 수 있습니다.
sudo netstat -tonp | grep jsvc | grep --regexp="127.0.0.1:443" --regexp="127.0.0.1:80" | grep CLOSE_WAIT
에서 언급 한 바와 같이 이 게시물에 , 당신은 사용할 수 있습니다/proc/sys/net/ipv4/tcp_keepalive_time
하여 값을 볼 . 값은 초 단위로 보이며 기본값은 7200 (예 : 2 시간)입니다.
변경하려면을 편집해야합니다 /etc/sysctl.conf
.
Open/create `/etc/sysctl.conf`
Add `net.ipv4.tcp_keepalive_time = 120` and save the file
Invoke `sysctl -p /etc/sysctl.conf`
Verify using `cat /proc/sys/net/ipv4/tcp_keepalive_time`
CLOSE_WAIT 연결이 너무 많으면 처음에는 코드에 문제가 있음을 의미하며 이는 좋은 방법이 아닙니다.
https://github.com/rghose/kill-close-wait-connections 에서 확인할 수 있습니다.
이 스크립트가하는 일은 연결이 기다리고 있던 ACK를 보내는 것입니다.
이것이 나를 위해 일한 것입니다.
또한 프로그램이 새 프로세스를 생성하면 해당 프로세스가 열려있는 모든 핸들을 상속 할 수 있다는 점도 주목할 가치가 있습니다. 자신의 프로그램이 종료 된 후에도 이러한 상속 된 핸들은 분리 된 자식 프로세스를 통해 여전히 살아있을 수 있습니다. 그리고 그들은 netstat에서 반드시 똑같이 표시되는 것은 아닙니다. 그러나 모두 똑같이이 자식 프로세스가 살아있는 동안 소켓은 CLOSE_WAIT에서 멈출 것입니다.
ADB를 실행하는 경우가있었습니다. ADB 자체는 아직 실행되지 않은 경우 서버 프로세스를 생성합니다. 이것은 처음에 모든 핸들을 상속했지만 조사 할 때 핸들을 소유 한 것으로 나타나지 않았습니다 (macOS와 Windows 모두에 해당됨-Linux에 대해서는 확실하지 않음).