TCP 옵션 SO_LINGER (영)-필요한 경우
옵션의 공식적인 의미를 이해한다고 생각합니다. 지금 처리중인 일부 레거시 코드에서는이 옵션이 사용됩니다. 고객이 측면에서 가까운 연결에서 FIN에 대한 응답으로 RST에 대해 불평합니다.
언제 사용해야하는지 모르겠 기 때문에 안전하게 제거 할 수 있을지 모르겠습니다.
옵션이 언제 필요한지 예를 들어 주시겠습니까?
SO_LINGER
시간 제한을 0 으로 설정하는 일반적인 이유 TIME_WAIT
는 서버에서 사용 가능한 모든 리소스를 묶어 상태 에있는 많은 수의 연결을 방지 하기위한 것입니다.
TCP 연결이 완전히 닫히면 닫기를 시작한 끝 ( "활성 닫기")은 연결 TIME_WAIT
이 몇 분 동안 유지 된 상태로 끝납니다 . 따라서 프로토콜이 서버 가 연결 닫기를 시작하고 매우 많은 수의 단기 연결을 포함하는 경우이 문제에 취약 할 수 있습니다.
그러나 이것은 좋은 생각이 아닙니다. TIME_WAIT
(이전 연결에서 나온 패킷이 새로운 연결을 방해하지 않도록하기위한) 이유가 있습니다. 가능한 경우 클라이언트가 연결 닫기를 시작하는 프로토콜로 프로토콜을 다시 디자인하는 것이 좋습니다.
제 제안에 대해서는 마지막 섹션 "시간 제한이 0 인 SO_LINGER를 사용하는 경우" 를 읽어보십시오 .
우리가 그것에 대해 조금 강의하기 전에 :
- 정상적인 TCP 종료
TIME_WAIT
FIN
,ACK
및RST
정상적인 TCP 종료
일반적인 TCP 종료 시퀀스는 다음과 같습니다 (간단).
우리는 A와 B의 두 동료가 있습니다.
- 전화
close()
- A
FIN
가 B 에게 전송 - A
FIN_WAIT_1
상태가 됨
- A
- B 수신
FIN
- B는
ACK
A 에게 보냅니다 - B가
CLOSE_WAIT
상태가 됨
- B는
- A 수신
ACK
- A
FIN_WAIT_2
상태가 됨
- A
- B 호출
close()
- B는
FIN
A 에게 보냅니다 - B가
LAST_ACK
상태가 됨
- B는
- A 수신
FIN
- A
ACK
가 B 에게 전송 - A
TIME_WAIT
상태가 됨
- A
- B 수신
ACK
- B
CLOSED
상태가 됨 – 즉 소켓 테이블에서 제거됨
- B
TIME_WAIT
따라서 종료를 시작하는 피어 (즉, close()
먼저 호출) 는 TIME_WAIT
상태가됩니다.
TIME_WAIT
주가 우리의 친구 인 이유를 이해하려면 Stevens 등의 "UNIX 네트워크 프로그래밍"제 3 판 (43 페이지)의 2.7 절을 읽으십시오.
그러나 TIME_WAIT
서버의 상태에있는 소켓 이 많으면 결국 새 연결이 허용되지 않을 수 있으므로 문제가 될 수 있습니다 .
이 문제를 해결하기 위해을 호출하기 전에 시간 초과 0으로 SO_LINGER 소켓 옵션을 설정하라는 제안을 많이 보았습니다 close()
. 그러나 이것은 TCP 연결이 오류와 함께 종료되는 원인이되므로 나쁜 해결책입니다.
대신 연결 종료가 항상 클라이언트 측에서 시작되도록 애플리케이션 프로토콜을 설계하십시오. 클라이언트가 남은 모든 데이터를 언제 읽었는지 항상 알고 있으면 종료 시퀀스를 시작할 수 있습니다. 예를 들어, 브라우저는 Content-Length
모든 데이터를 읽었을 때 HTTP 헤더에서이를 인식하고 닫기를 시작할 수 있습니다. (HTTP 1.1에서는 재사용을 위해 잠시 열린 상태로 유지 한 다음 닫습니다.)
서버가 연결을 닫아야하는 경우 서버가 클라이언트에게을 호출하도록 요청하도록 애플리케이션 프로토콜을 설계합니다 close()
.
시간 초과 0과 함께 SO_LINGER를 사용하는 경우
다시 말하지만, "UNIX 네트워크 프로그래밍"3 판 페이지 202-203에 따르면 SO_LINGER
호출 전에 시간 초과 0으로 설정 close()
하면 정상적인 종료 시퀀스 가 시작 되지 않습니다 .
대신,이 옵션을 설정하고 호출하는 피어 는 오류 조건을 나타내는 (연결 재설정)을 close()
보내며 RST
이것이 다른 쪽에서 인식되는 방식입니다. 일반적으로 "피어에 의한 연결 재설정"과 같은 오류가 표시됩니다.
Therefore, in the normal situation it is a really bad idea to set SO_LINGER
with timeout 0 prior to calling close()
– from now on called abortive close – in a server application.
However, certain situation warrants doing so anyway:
- If the a client of your server application misbehaves (times out, returns invalid data, etc.) an abortive close makes sense to avoid being stuck in
CLOSE_WAIT
or ending up in theTIME_WAIT
state. - If you must restart your server application which currently has thousands of client connections you might consider setting this socket option to avoid thousands of server sockets in
TIME_WAIT
(when callingclose()
from the server end) as this might prevent the server from getting available ports for new client connections after being restarted. - On page 202 in the aforementioned book it specifically says: "There are certain circumstances which warrant using this feature to send an abortive close. One example is an RS-232 terminal server, which might hang forever in
CLOSE_WAIT
trying to deliver data to a stuck terminal port, but would properly reset the stuck port if it got anRST
to discard the pending data."
I would recommend this long article which I believe gives a very good answer to your question.
When linger is on but the timeout is zero the TCP stack doesn't wait for pending data to be sent before closing the connection. Data could be lost due to this but by setting linger this way you're accepting this and asking that the connection be reset straight away rather than closed gracefully. This causes an RST to be sent rather than the usual FIN.
Thanks to EJP for his comment, see here for details.
Whether you can remove the linger in your code safely or not depends on the type of your application: is it a „client“ (opening TCP connections and actively closing it first) or is it a „server“ (listening to a TCP open and closing it after the other side initiated the close)?
If your application has the flavor of a „client“ (closing first) AND you initiate & close a huge number of connections to different servers (e.g. when your app is a monitoring app supervising the reachability of a huge number of different servers) your app has the problem that all your client connections are stuck in TIME_WAIT state. Then, I would recommend to shorten the timeout to a smaller value than the default to still shutdown gracefully but free up the client connections resources earlier. I would not set the timeout to 0, as 0 does not shutdown gracefully with FIN but abortive with RST.
If your application has the flavor of a „client“ and has to fetch a huge amount of small files from the same server, you should not initiate a new TCP connection per file and end up in a huge amount of client connections in TIME_WAIT, but keep the connection open and fetch all data over the same connection. Linger option can and should be removed.
If your application is a „server“ (close second as reaction to peer‘s close), on close() your connection is shutdown gracefully and resources are freed up as you don‘t enter TIME_WAIT state. Linger should not be used. But if your sever app has a supervisory process detecting inactive open connections idleing for a long time („long“ is to be defined) you can shutdown this inactive connection from your side - see it as kind of error handling - with an abortive shutdown. This is done by setting linger timeout to 0. close() will then send a RST to the client, telling him that you are angry :-)
참고URL : https://stackoverflow.com/questions/3757289/tcp-option-so-linger-zero-when-its-required
'developer tip' 카테고리의 다른 글
C # /. NET에서 로컬 컴퓨터의 FQDN을 찾는 방법은 무엇입니까? (0) | 2020.09.20 |
---|---|
iOS에서 문자열을 하위 문자열로 분할하는 방법은 무엇입니까? (0) | 2020.09.20 |
고정 너비 텍스트 파일 읽기 (0) | 2020.09.20 |
키워드 'const'는 값을 변경 불가능하게 만들지 않습니다. (0) | 2020.09.20 |
WPF Textblock, Text 속성의 줄 바꿈 (0) | 2020.09.20 |