CLOSE_WAIT 소켓 연결을 제거하는 방법


92

특정 포트의 서버와 상호 작용하는 작은 프로그램을 작성했습니다. 프로그램은 잘 작동하지만 :

프로그램이 예기치 않게 종료되면 해당 소켓 연결이 CLOSE_WAIT상태 로 표시됩니다 . 프로그램을 실행하려고하면 중단되고 강제로 닫아야하므로 더 많은 CLOSE_WAIT 소켓 연결 이 축적 됩니다.

이러한 연결을 플러시하는 방법이 있습니까?


4
당신은 할 수 없습니다 (그리고해서는 안됩니다). CLOSE_WAIT는 상대방이이를 확인하기를 기다리는 연결이 닫히도록 TCP에서 정의한 상태입니다.
vonbrand 2014

1
unix.stackexchange.com/questions/10106/… 도 참조하십시오. ... 중복으로 투표하지 않을 것입니다. 질문을 주제에서 벗어난 것으로 종료 할 수 있기 때문입니다.
derobert apr

4
@vonbrand 아니요 그렇지 않습니다. 정반대입니다. 피어가 이미 닫은 연결 상태이며 로컬 응용 프로그램이 종료되기를 기다리고 있습니다.
Marquis of Lorne

Commons HttpClient를 사용하는 경우 nuxeo.com/blog/… 에는 많은 관련 정보가 있습니다. RFC 2616, 섹션 14 : 영구 연결을 지원하지 않는 HTTP / 1.1 애플리케이션은 모든 메시지에 "닫기"연결 옵션을 포함해야합니다.
Mayank Ahuja 2015-06-23

답변:


80

CLOSE_WAIT프로그램이 여전히 실행 중이고 소켓을 닫지 않았 음을 의미합니다 (커널이 그렇게하기를 기다리고 있음). 추가 -pnetstatPID를 얻기 위해, 다음 (더 강력하게 죽일 SIGKILL필요한 경우). 그것은 당신의 CLOSE_WAIT소켓을 제거해야합니다 . 를 사용 ps하여 pid를 찾을 수도 있습니다 .

SO_REUSEADDR서버 및 TIME_WAIT소켓 용이므로 여기에는 적용되지 않습니다.


2
글쎄요 ... 그 프로그램이 많은 연결을 열면 프로세스를 킬링하는 것이 최선이 아닐 수 있습니다. "CLOSE_WAIT"에 남아있는 사람 중 몇 개만 있습니다.이 경우 프로세스를 종료하는 것은 완전히 불가능하거나 적절하지 않을 수 있습니다 (프로그램은 여전히 ​​작동하고 다른 연결과 함께 서비스를 제공합니다). 보류중인 연결을 닫는 것이 훨씬 더 적절할 것입니다. 그러나 실제로는 일반적으로 로컬에서 connectino를 닫지 않는 프로그램 자체입니다 (CLOSE_WAIT는 다른 쪽 끝에서 'FIN'을 받았으며 프로그램은 로컬에서 연결을 닫아야 함). 버그 보고서는 적절할 수있다
올리비에 Dulac

41

Crist Clark에 의해 설명 된대로 .

CLOSE_WAIT는 연결의 로컬 끝이 다른 쪽 끝에서 FIN을 받았지만 OS는 로컬 끝의 프로그램이 실제로 연결을 닫을 때까지 기다리고 있음을 의미합니다.

문제는 로컬 컴퓨터에서 실행중인 프로그램이 소켓을 닫지 않는다는 것입니다. TCP 튜닝 문제가 아닙니다. 연결은 프로그램이 연결을 열린 상태로 유지하는 동안 CLOSE_WAIT에 영원히있을 수 있습니다 (정확하게).

로컬 프로그램이 소켓을 닫으면 OS는 FIN의 ACK를 기다리는 동안 LAST_ACK로 전환하는 원격 끝으로 FIN을 보낼 수 있습니다. 수신되면 연결이 완료되고 연결 테이블에서 삭제됩니다 (엔드가 CLOSE_WAIT 인 경우 TIME_WAIT 상태 가 되지 않음 ).


4
소켓을 닫는 방법 ??
Divyang Shah

1
열린 소켓에있는 핸들을 닫습니다. 사용 close()또는 closesocket()사용중인 플랫폼에 따라.
Remy Lebeau

8

최신 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`

4
대답은 혼란 스럽습니다. 응답하지 않는 상태가 며칠 동안 사라 졌다고 말했지만 .. 또한 활성 유지 시간을 120 초로 설정하려고합니다. 기본값 (7200 초)을 사용해도 며칠 동안 지속되지 않아야합니다.
fanchyna

8

CLOSE_WAIT 연결이 너무 많으면 처음에는 코드에 문제가 있음을 의미하며 이는 좋은 방법이 아닙니다.

https://github.com/rghose/kill-close-wait-connections 에서 확인할 수 있습니다.

이 스크립트가하는 일은 연결이 기다리고 있던 ACK를 보내는 것입니다.

이것이 나를 위해 일한 것입니다.


close-wait 소켓에 act를 보냅니다. 작동하지 않는 .. 작동한다면 왜?
Chinaxing 2015

OS가 이미 원격 호스트에 FIN을 보냈습니다. 원격 호스트는 소켓이 예상하는 ACK로 응답 할 수 없습니다.
mirage

네, 맞습니다 (커널 코드에서). 그러나 나는 또한 당신이 보내는 패킷의 SEQ, 즉 "10"에 대해 의심 스럽습니다. 커널은 그것을 확인하지 않습니까?
Chinaxing

아마 아닐 것입니다. 난 많은 난수로 시도 해봤는데 효과가있는 것 같았다.
mirage

4

ss명령으로 소켓을 강제로 닫을 수 있습니다 . 그만큼ss 명령은 소켓 통계를 덤프하는 데 사용되는 도구이며 netstat와 유사한 방식 (더 간단하고 빠름)으로 정보를 표시합니다.

CLOSE_WAIT 상태의 소켓을 종료하려면 이것을 실행하십시오 (루트 권한으로)

$ ss --tcp state CLOSE-WAIT --kill

3

Socket클라이언트와 서버 끝 모두 의 인스턴스가 명시 적으로를 호출 해야한다는 점을 언급해야합니다 close(). 끝 중 하나만 호출 close()하면 소켓은 CLOSE_WAIT 상태로 유지됩니다.


1

또한 프로그램이 새 프로세스를 생성하면 해당 프로세스가 열려있는 모든 핸들을 상속 할 수 있다는 점도 주목할 가치가 있습니다. 자신의 프로그램이 종료 된 후에도 이러한 상속 된 핸들은 분리 된 자식 프로세스를 통해 여전히 살아있을 수 있습니다. 그리고 그들은 netstat에서 반드시 똑같이 표시되는 것은 아닙니다. 그러나 모두 똑같이이 자식 프로세스가 살아있는 동안 소켓은 CLOSE_WAIT에서 멈출 것입니다.

ADB를 실행하는 경우가있었습니다. ADB 자체는 아직 실행되지 않은 경우 서버 프로세스를 생성합니다. 이것은 처음에 모든 핸들을 상속했지만 조사 할 때 핸들을 소유 한 것으로 나타나지 않았습니다 (macOS와 Windows 모두에 해당됨-Linux에 대해서는 확실하지 않음).

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.