TCP 소켓 연결에 "활성 유지"가 있습니까?


84

HTTP 연결 유지에 대해 들어 봤지만 지금은 원격 서버와 소켓 연결을 열고 싶습니다.
이제이 소켓 연결이 영원히 열려 있거나 HTTP 연결 유지와 유사한 시간 제한이 있습니까?


1
"http keepalive"가 일반적으로 소켓 킵 얼라이브와 관련이 없는지 확인하기 위해 추가 요청을 위해 연결을 열어 두는 HTTP / 1.1 기능에 대해 설명합니다. 끊어진 TCP 연결을 감지해야하기 때문에 (또는 일반적으로 제한된 시간 동안 만 소켓을 열린 상태로 유지) TCP keepalive 와만 관련이 있습니다.
eckes 2015 년

답변:


72

TCP 소켓은 닫힐 때까지 열려 있습니다.

즉, 실제로 데이터를 전송하지 않고 끊어진 연결 (라우터에서 끊어진 것과 같은 끊어짐 등)을 실제로 데이터를 전송하지 않고 감지하는 것은 매우 어렵 기 때문에 대부분의 응용 프로그램은 확인하기 위해 자주 일종의 핑 / 퐁 반응을 수행합니다. 연결은 실제로 살아 있습니다.


4
좋은 생각입니다. 당신은하지 않습니다 ,하지만 그렇게하지 않으면 누군가가 실제로 뭔가를하고 싶어까지, 당신은 깨진 링크를 감지하지 못할 수 있습니다. 실제로 달성하려는 목표에 따라 어느 것이 좋은 것일 수도 있고 아닐 수도 있습니다 (또는 중요하지 않을 수도 있습니다).
Matthew Scharley

1
@Pacerier : 완전히 프로토콜에 따라 다르기 때문에 프로토콜에 따라 다르지만 하나의 리터럴 "PING"및 "PONG"명령이 필요한 텍스트 기반 프로토콜의 경우 매우 일반적입니다.
Matthew Scharley 2012

4
@MatthewScharley :이 "핑퐁"은 표준 TCP 구현에서 이미 우리를 위해 구현되었으며 "keep-alive"라고합니다 (이 질문에 대한 다른 인기있는 답변 참조). 앱 수준에서 구현해야하는 이유가 있습니까?
Tim Cooper

7
@TimCooper : 정말 아니에요. 다른 답변에 대한 의견에서 강조했듯이 TCP 구현은 대부분의 응용 프로그램 수준 요구 사항에 유용하지 않습니다 . 요청시 하나를 보낼 수 없으며 대부분의 운영 체제에서 TCP 연결 유지 시간 제한은 시스템 전체 수준에서만 구성 할 수 있으며 응용 프로그램에 일반적으로 유용하기에는 너무 높게 설정됩니다.
매튜 Scharley

13
@Tim 애플리케이션 수준에서 연결 유지의 이유는 TCP 표준이 연결 유지 타이머를 2 시간 이상으로 설정하도록 권장하기 때문입니다. 이번에는 트래픽이없는 TCP 연결을 본 적이 없습니다. 따라서 TCP keep-alive 항목은 기본적으로 쓸모가 없습니다.
Robert

97

이제이 소켓 연결이 영원히 열려 있거나 HTTP 연결 유지와 유사한 시간 제한이 있습니까?

짧은 대답은 ' 아니오 '입니다. 영원히 열려 있지 않으며 몇 시간 후에 시간이 초과 될 것입니다. 따라서 있다 타임 아웃 그것은을 통해 적용됩니다 TCP 연결 유지 .

컴퓨터에서 Keep-Alive 제한 시간을 구성하려면 아래의 "TCP 제한 시간 변경"섹션을 참조하십시오. 그렇지 않으면 나머지 답변을 읽고 TCP Keep-Alive 작동 방식을 알아보십시오.

소개

TCP 연결은 연결의 각 끝에 하나씩 두 개의 소켓으로 구성됩니다. 한 쪽이 연결을 종료하려고 할 때 RST다른 쪽이 확인하고 소켓을 닫는 패킷을 보냅니다 .

그러나 그렇게 될 때까지 양측은 소켓을 무기한으로 열어 둡니다. 이렇게하면을 통해 다른 쪽 끝에 알리지 않고 의도적으로 또는 일부 오류로 인해 한쪽이 소켓을 닫을 가능성이 열립니다 RST. 이 시나리오를 감지하고 오래된 연결을 닫으려면 TCP Keep Alive 프로세스가 사용됩니다.

Keep-Alive 프로세스

Keep-Alives 작동 방식을 결정하는 세 가지 구성 가능한 속성이 있습니다. Linux에서는 1입니다 .

  • tcp_keepalive_time
    • 기본 7200 초
  • tcp_keepalive_probes
    • 기본값 9
  • tcp_keepalive_intvl
    • 기본 75 초

프로세스는 다음과 같이 작동합니다.

  1. 클라이언트가 TCP 연결을 엽니 다.
  2. 연결이 tcp_keepalive_time몇 초 동안 침묵 하면 하나의 빈 ACK패킷을 보냅니다 . 1
  3. 서버 ACK가 자체적으로 응답 했습니까 ?
    • 아니
      1. tcp_keepalive_intvl몇 초 동안 기다린 다음 다른 메시지를 보냅니다.ACK
      2. ACK전송 된 프로브 수가 같을 때까지 반복하십시오 tcp_keepalive_probes.
      3. 이 시점에서 응답이 수신되지 않으면 a를 보내고 RST연결을 종료하십시오.
    • : 2 단계로 돌아갑니다.

이 프로세스는 대부분의 운영 체제에서 기본적으로 활성화되어 있으므로 다른 쪽 끝이 2 시간 11 분 (7200 초 + 75 * 9 초) 동안 응답하지 않으면 작동하지 않는 TCP 연결이 정기적으로 정리됩니다.

Gotchas

2 시간 기본값

연결이 기본적으로 2 시간 동안 유휴 상태가 될 때까지 프로세스가 시작되지 않기 때문에 부실 TCP 연결이 정리되기 전에 매우 오랫동안 지속될 수 있습니다. 이는 데이터베이스 연결과 같은 값 비싼 연결에 특히 해로울 수 있습니다.

Keep-Alive는 선택 사항입니다.

RFC 1122 4.2.3.6 에 따르면 TCP Keep-Alive 패킷에 대한 응답 및 / 또는 릴레이 는 선택 사항입니다 .

구현자는 TCP 구현에 "keep-alive"를 포함 할 수 있지만이 관행은 보편적으로 받아 들여지지는 않습니다. 연결 유지가 포함 된 경우 응용 프로그램은 각 TCP 연결에 대해 해당 연결을 켜거나 끌 수 있어야하며 기본적으로 꺼져 있어야합니다.

...

데이터가없는 ACK 세그먼트는 TCP에 의해 안정적으로 전송되지 않는다는 점을 기억하는 것이 매우 중요합니다.

Keep-Alive 패킷은 데이터를 포함하지 않으며 엄격하게 필요하지 않으며 과도하게 사용되는 경우 인터 웹의 튜브가 막힐 위험이 있기 때문입니다.

그러나 실제로 는 대역폭이 저렴 해짐에 따라 시간이 지남에 따라 이러한 우려가 줄어 들었습니다. 따라서 Keep-Alive 패킷은 일반적으로 삭제되지 않습니다. 예를 들어 Amazon EC2 설명서 는 Keep-Alive에 대한 간접적 인 보증을 제공하므로 AWS로 호스팅하는 경우 Keep-Alive에 의존하는 것이 안전 할 가능성이 높지만 마일리지는 다를 수 있습니다.

TCP 시간 초과 변경

소켓 당

안타깝게도 TCP 연결은 OS 수준에서 관리되기 때문에 Java는 .NET과 같은 소켓 수준에서 제한 시간 구성을 지원하지 않습니다 java.net.Socket. 나는 몇 가지 시도를 발견했다 (3) 이 옵션을 구성 할 네이티브 코드를 호출하는 자바 소켓을 만들 수 있도록 JNI (Java Native Interface)를 사용하지만, 아무도 광범위한 지역 사회의 채택 또는 지원을 가지고있는 것 같습니다 없습니다.

대신 운영 체제 전체에 구성을 적용해야 할 수도 있습니다. 이 구성은 전체 시스템에서 실행되는 모든 TCP 연결에 영향을 미칩니다.

리눅스

현재 구성된 TCP Keep-Alive 설정은 다음 위치에서 찾을 수 있습니다.

  • /proc/sys/net/ipv4/tcp_keepalive_time
  • /proc/sys/net/ipv4/tcp_keepalive_probes
  • /proc/sys/net/ipv4/tcp_keepalive_intvl

다음과 같이 업데이트 할 수 있습니다.

# Send first Keep-Alive packet when a TCP socket has been idle for 3 minutes
$ echo 180 > /proc/sys/net/ipv4/tcp_keepalive_time
# Send three Keep-Alive probes...
$ echo 3 > /proc/sys/net/ipv4/tcp_keepalive_probes
# ... spaced 10 seconds apart.
$ echo 10 > /proc/sys/net/ipv4/tcp_keepalive_intvl

이러한 변경 사항은 다시 시작해도 지속되지 않습니다. 지속적으로 변경하려면 다음을 사용하십시오 sysctl.

sysctl -w net.ipv4.tcp_keepalive_time=180 net.ipv4.tcp_keepalive_probes=3 net.ipv4.tcp_keepalive_intvl=10

맥 OS X

현재 구성된 설정은 다음을 사용하여 볼 수 있습니다 sysctl.

$ sysctl net.inet.tcp | grep -E "keepidle|keepintvl|keepcnt"
net.inet.tcp.keepidle: 7200000
net.inet.tcp.keepintvl: 75000
net.inet.tcp.keepcnt: 8

참고로, 맥 OS X를 정의 keepidle하고 keepintvl초를 사용하는 리눅스에 반대 밀리 초 단위입니다.

sysctl재부팅시 이러한 설정을 유지하는 속성을 설정할 수 있습니다 .

sysctl -w net.inet.tcp.keepidle=180000 net.inet.tcp.keepcnt=3 net.inet.tcp.keepintvl=10000

또는에 추가 할 수 있습니다 /etc/sysctl.conf(파일이없는 경우 생성).

$ cat /etc/sysctl.conf
net.inet.tcp.keepidle=180000
net.inet.tcp.keepintvl=10000
net.inet.tcp.keepcnt=3

윈도우

확인할 Windows 컴퓨터가 없지만 레지스트리에서 각 TCP Keep-Alive 설정을 찾아야합니다.

\HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\TCPIP\Parameters

각주

1. 자세한 내용은를 참조하십시오 man tcp.

2.이 패킷은 "Keep-Alive"패킷이라고도하지만 TCP 사양 내에서는 일반 ACK패킷 일뿐 입니다. Wireshark와 같은 응용 프로그램은 소켓의 이전 통신을 참조하여 포함 된 시퀀스 및 승인 번호의 메타 분석을 통해 "Keep-Alive"패킷으로 레이블을 지정할 수 있습니다.

3. 기본 Google 검색에서 찾은 몇 가지 예는 lucwilliams / JavaLinuxNetflonatel / libdontdie 입니다.


매우 도움이되었습니다, 감사합니다! 추가 사항 : Windows의 경우 새 KeepAliveTime 값을 적용하려면 다시 시작해야합니다.
geld0r

AIX에서 현재 TCP Keep-Alive 설정은 $ no -a | grep tcp_keep명령을 사용하여 조회 할 수 있습니다 .
Jarek Przygódzki

55

SO_KEEPALIVE 소켓 옵션을 찾고 있습니다.

자바 소켓 API를 노출하는가 "연결 유지"를 통해 응용 프로그램 setKeepAlivegetKeepAlive방법.

편집 : SO_KEEPALIVE는 "실제"데이터를 보내지 않고 OS 네트워크 프로토콜 스택에서 구현됩니다. 연결 유지 간격은 운영 체제에 따라 다르며 커널 매개 변수를 통해 조정할 수 있습니다.

데이터가 전송되지 않기 때문에 SO_KEEPALIVE는 소켓이 연결된 서비스의 활성 상태가 아닌 네트워크 연결의 활성 상태 만 테스트 할 수 있습니다. 후자를 테스트하려면 서버에 메시지를 보내고 응답을받는 것과 관련된 무언가를 구현해야합니다.


4
내가 setKeepAlive (true); 간격은 무엇입니까? ... 또한 Java가 기본 간격으로 연결 유지 메시지를 계속 보내거나 프로그래밍 방식으로 수행해야합니까?
Kevin Boyd

3
unixguide.net/network/socketfaq/4.7.shtml SO_KEEPALIVE에 대한 설명이 있습니다. 그것은하지만 그것은 순전히 영업 이익이 원하는 게 아니에요 입니다 두 시간마다 응용 프로그램을 위해 많은 일을하지 않습니다 번,하지만 ... 내가 무엇을 제안하는 프로토콜 기반 옵션을 선택합니다.
Matthew Scharley

4
@MatthewScharley " 기본값 은 2 시간 이상 이어야합니다."라는 말은 2 시간 미만으로 허용된다는 의미입니다.
Pacerier

1
@MatthewScharley- "당신 말이 맞아요.하지만 그것은 구현에 따라 다릅니다 ..." . 2 시간 미만일 수없는 연결 유지 간격은 너무 쓸모가 없어서이를 구현하는 사람을 상상하기 어렵습니다.
Stephen C

2
@Daniel-대안 (Java에서)은 위에서 언급 했거나 다른 답변에서 언급했듯이 수동 유지 를 수행하는 것 입니다. 아니 꽤 있지만, 아마 기본의 OS 전체의 변화보다 시스템 서비스 나 다른 응용 프로그램을 중단.
Stephen C

34

TCP 킵 얼라이브와 HTTP 킵 얼라이브는 매우 다른 개념입니다. TCP에서 keepalive는 부실 연결을 감지하기 위해 전송되는 관리 패킷입니다. HTTP에서 keepalive는 지속적인 연결 상태를 의미합니다.

이것은 TCP 사양에서 가져온 것입니다.

Keep-alive 패킷은 간격 내 연결에 대해 수신 된 데이터 또는 확인 패킷이 없을 때만 전송되어야합니다. 이 간격은 구성 가능해야하며 기본값은 2 시간 이상이어야합니다.

보시다시피 기본 TCP 연결 유지 간격은 대부분의 응용 프로그램에서 너무 깁니다. 애플리케이션 프로토콜에 Keepalive를 추가해야 할 수도 있습니다.


2
애플리케이션에 맞게 TCP 연결 유지 간격을 수정할 수 있습니다. 예 : msdn.microsoft.com/en-us/library/dd877220%28VS.85%29.aspx
Dan Berindei

@ZZCoder "HTTP에서 킵 얼라이브는 지속적인 연결 상태를 의미합니다."라는 말의 의미를 자세히 설명해 주시겠습니까?
Pacerier

1
@Pacerier : HTTP/1.0각 요청 / 응답에서 서버에 다시 연결해야했습니다. 들어 HTTP/1.1그들이 도입 Keep-Alive이 더 많은 파일을 요청하고 '파이프 라인'을 허용 용이하게 응답을 처리 완료 후 연결을 죽이지에 서버를 실행하는 데 사용할 수있는 헤더를; 여러 요청을 보낸 다음 모든 데이터가 돌아올 때까지 기다립니다.
Matthew Scharley 2014 년

기본적으로 많은 HTTP 요청이 동일한 TCP-Connection을 재사용하거나 재사용해야 함을 의미합니다 (이러한 연결도 연결 유지가있을 수 있지만 HTTP로 측정되지 않으므로 본질적으로 다른 개념입니다).
Igor Čordaš

24

마스 쿼 레이 딩 NAT를 사용하는 경우 (요즘 대부분의 가정용 사용자가 그렇듯이) 외부 포트 풀이 제한되어 있으며 이러한 포트는 TCP 연결간에 공유되어야합니다. 따라서 위장 NAT는 특정 기간 동안 데이터가 전송되지 않으면 연결이 종료되었다고 가정하는 경향이 있습니다.

이 문제 및 기타 이러한 문제 (두 끝점 사이의 모든 문제)는 합리적인 유휴 기간 후에 데이터를 보내려고하면 연결이 더 이상 "작동"하지 않음을 의미 할 수 있습니다. 그러나 데이터 전송 을 시도 할 때까지이를 발견하지 못할 수 있습니다 .

킵 얼라이브를 사용 하면 연결이 중단 될 가능성이 줄어들고 끊어진 연결에 대해 더 빨리 알 수 있습니다.


아! 당신은 당신이 또한 고려해야합니다입니다, 여기에 좋은 점을 추가 그 사이 등등 ... NAT 라우터로 연결의 작동을 방해 할 수있는 것들
케빈 보이드

4
이것은 우리가 직접 구현하는 것보다 명심해야 할 것이 더 많다는 것을 상기시키는 좋은 요점입니다. 또한, Lemmings !!
Matthew Scharley

p2p 파일 공유는 둘 다 많은 포트를 씹고 많은 좀비 연결을 생성하므로 NAT가 유휴 연결을 제거해야 할 가능성이 높아집니다.
Artelius

4
반드시 TCP 연결은 src ip, src port, dest ip, dest port의 4 가지 요소로 식별됩니다. 따라서 대상 IP가 다른 한 동일한 외부 (소스) 포트를 재사용 할 수 있습니다.
Dan Berindei

1
아, 맞아요. 진짜 이유는 NAT가 메모리 제약과 조회 시간으로 인해 고정 된 크기의 열린 연결 테이블을 가지고 있기 때문이라고 생각합니다.
Artelius

4

다음은 킵 얼라이브에 대한 몇 가지 보충 문헌으로이를 훨씬 더 자세히 설명합니다.

http://www.tldp.org/HOWTO/html_single/TCP-Keepalive-HOWTO

Java는 실제 연결 유지 시간을 제어하는 ​​것을 허용하지 않기 때문에 Linux 커널 (또는 proc 기반 OS)을 사용하는 경우 예제를 사용하여 변경할 수 있습니다.


1

JAVA Socket – TCP 연결은 OS 수준에서 관리되며 java.net.Socket은 소켓 수준에서 Keepalive 패킷에 대한 시간 제한을 설정하는 내장 기능을 제공하지 않습니다. 하지만 자바 소켓에 대해 keepalive 옵션을 활성화 할 수는 있지만 오래된 tcp 연결 후 처리하는 데 기본적으로 2 시간 11 분 (7200 초)이 걸립니다. 이 원인 연결은 퍼지하기 전에 매우 오랫동안 사용할 수 있습니다. 그래서 이러한 옵션을 구성하기 위해 네이티브 코드 (c ++)를 호출하는 JNI (Java Native Interface)를 사용하는 몇 가지 솔루션을 찾았습니다.

**** Windows OS ****

Windows 운영 체제에서 keepalive_time 및 keepalive_intvl은 구성 할 수 있지만 tcp_keepalive_probes는 변경할 수 없습니다. 기본적으로 TCP 소켓이 초기화되면 연결 유지 시간 제한이 2 시간으로 설정되고 연결 유지 간격이 1 초로 설정됩니다. Keep-alive 제한 시간의 기본 시스템 전체 값은 밀리 초 단위의 값을 사용하는 KeepAliveTime 레지스트리 설정을 통해 제어 할 수 있습니다.

Windows Vista 이상에서 Keep-alive 프로브 (데이터 재전송) 수는 10으로 설정되며 변경할 수 없습니다.

Windows Server 2003, Windows XP 및 Windows 2000에서 연결 유지 프로브 수의 기본 설정은 5입니다. 연결 유지 프로브 수는 제어 할 수 있습니다. Windows의 경우 Winsock IOCTL 라이브러리는 tcp-keepalive 매개 변수를 구성하는 데 사용됩니다.

int WSAIoctl (SocketFD, // 소켓을 식별하는 설명자 SIO_KEEPALIVE_VALS, // dwIoControlCode (LPVOID) lpvInBuffer, // tcp_keepalive 구조체에 대한 포인터 (DWORD) cbInBuffer, // 입력 버퍼 길이 NULL, // 출력 버퍼 0, // 크기 출력 버퍼 (LPDWORD) lpcbBytesReturned, // 반환 된 바이트 수 NULL, // OVERLAPPED 구조체 NULL // 완료 루틴);

Linux OS

Linux는이를 사용하기 위해 TCP / IP 네트워킹을 활성화해야하는 킵 얼라이브에 대한 지원이 내장되어 있습니다. 프로그램은 setsockopt 인터페이스를 사용하여 소켓에 대한 연결 유지 제어를 요청해야합니다.

int setsockopt (int 소켓, int 레벨, int optname, const void * optval, socklen_t optlen)

각 클라이언트 소켓은 java.net.Socket을 사용하여 생성됩니다. 각 소켓의 파일 설명자 ID는 Java 리플렉션을 사용하여 검색합니다.


0

Microsoft Docs 에 따른 Windows의 경우

  • KeepAliveTime (REG_DWORD, 밀리 초, 기본적으로 7,200,000,000 = 2 시간을 의미하는 설정되지 않음)-tcp_keepalive_time과 유사
  • KeepAliveInterval (REG_DWORD, 밀리 초, 기본적으로 설정되지 않음 (1,000 = 1 초 의미))-tcp_keepalive_intvl과 유사
  • Windows Vista는 tcp_keepalive_probes와 유사하지 않으므로 값은 10으로 고정되며 변경할 수 없습니다.
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.