I / O를 시도하지 않고 TCP 소켓이 피어에 의해 정상적으로 닫 혔음을 감지하는 것이 왜 불가능합니까?


92

최근 질문에 대한 후속 으로, TCP 소켓에서 읽기 / 쓰기를 시도하지 않고 Java에서 소켓이 피어에 의해 정상적으로 닫 혔음을 감지하는 것이 왜 불가능한지 궁금합니다. 이 관계없이 하나가 사전 NIO 사용하는지 여부의 경우 것 같다 Socket또는 NIO SocketChannel.

피어가 TCP 연결을 정상적으로 닫으면 연결 양쪽의 TCP 스택이 그 사실을 알고 있습니다. 서버 측 (종료를 시작하는 서버)은 state에서 끝나는 FIN_WAIT2반면 클라이언트 측 (종료에 명시 적으로 응답하지 않는 서버)은 state에서 끝납니다 CLOSE_WAIT. 왜의 방법이 아닌 Socket또는 SocketChannel기본 TCP 연결이 종료되었는지 여부를 확인하기 위해 즉, TCP 스택을 조회 할 수는? TCP 스택이 그러한 상태 정보를 제공하지 않는 것입니까? 아니면 비용이 많이 드는 커널 호출을 피하기위한 설계 결정입니까?

이 질문에 대한 답변을 이미 게시 한 사용자의 도움으로 문제의 원인을 알 수 있다고 생각합니다. 연결을 명시 적으로 닫지 않은 쪽은 TCP 상태 CLOSE_WAIT가되어 연결이 종료되는 과정에 있으며 쪽이 자체 CLOSE작업 을 실행할 때까지 기다립니다 . 나는 그것이 isConnected반환 true하고 isClosed반환 하는 것이 충분히 공정하다고 생각 false하지만, 왜 그런 것이 isClosing없는가?

다음은 pre-NIO 소켓을 사용하는 테스트 클래스입니다. 그러나 NIO를 사용하여 동일한 결과를 얻습니다.

import java.net.ServerSocket;
import java.net.Socket;

public class MyServer {
  public static void main(String[] args) throws Exception {
    final ServerSocket ss = new ServerSocket(12345);
    final Socket cs = ss.accept();
    System.out.println("Accepted connection");
    Thread.sleep(5000);
    cs.close();
    System.out.println("Closed connection");
    ss.close();
    Thread.sleep(100000);
  }
}


import java.net.Socket;

public class MyClient {
  public static void main(String[] args) throws Exception {
    final Socket s = new Socket("localhost", 12345);
    for (int i = 0; i < 10; i++) {
      System.out.println("connected: " + s.isConnected() + 
        ", closed: " + s.isClosed());
      Thread.sleep(1000);
    }
    Thread.sleep(100000);
  }
}

테스트 클라이언트가 테스트 서버에 연결되면 서버가 연결 종료를 시작한 후에도 출력이 변경되지 않습니다.

connected: true, closed: false
connected: true, closed: false
...

나는 언급하고 싶지 않다 : SCTP 프로토콜에는 이러한 "문제"가 없습니다. SCTP는 TCP와 같은 반 폐쇄 상태가 아닙니다. 즉, 한쪽은 데이터 전송을 계속할 수없고 다른 쪽 끝은 전송 소켓을 닫았습니다. 그것은 일을 더 쉽게 만들 것입니다.
Tarnay Kálmán

2
두 개의 사서함 (소켓)이 있습니다 ........................................... ...... 사서함은 RoyalMail (IP)을 사용하여 서로에게 메일을 보냅니다. TCP는 잊어 버립니다 .............................. .................... 모든 것이 훌륭하고 멋집니다. 사서함은 문제없이 전송하면서 서로에게 메일을주고받을 수 있습니다 (최근 지연 시간이 많음). ............. 한 사서함이 트럭에 치여 실패하면 다른 사서함은 어떻게 알 수 있습니까? 다음 번 실패한 사서함에서 메일 보내기 /
받기

소켓에서 읽거나 소켓에 쓰지 않으려는 경우 왜 신경 쓰나요? 소켓에서 읽거나 소켓에 쓰려는 경우 추가 검사를하는 이유는 무엇입니까? 사용 사례는 무엇입니까?
David Schwartz

2
Socket.close우아한 종가가 아닙니다.
user253751 2014 년

@immibis 소켓 수신 버퍼에 읽지 않은 데이터가 있거나 SO_LINGER를 엉망으로 만든 경우가 아니라면 가장 확실하게 우아한 닫기입니다.
Marquis of Lorne

답변:


29

저는 주로 Selector와 함께 소켓을 사용해 왔으며 Network OSI 전문가는 아니지만 shutdownOutput()소켓을 호출 하면 실제로 다른 쪽에서 Selector를 깨우는 네트워크 (FIN)를 전송합니다 (C에서도 동일한 동작). 언어). 여기에 감지 기능이 있습니다 . 실제로 시도 할 때 실패 할 읽기 작업을 감지합니다.

제공하는 코드에서 소켓을 닫으면 사용 가능한 데이터를 읽을 가능성없이 입력 및 출력 스트림이 모두 종료되어 손실됩니다. Java Socket.close()메서드는 출력 스트림에 남아있는 데이터 가 FIN 으로 전송된다는 점에서 "단계적"연결 해제 (처음에 생각했던 것과 반대)를 수행합니다. 으로 전송되어 종료를 알리는 . FIN은 일반 패킷이 1 처럼 다른 쪽에서 ACK됩니다 .

상대방이 소켓을 닫을 때까지 기다려야하는 경우 FIN을 기다려야합니다. 그리고 그것을 달성하기 위해, 당신은 할 필요가 감지 Socket.getInputStream().read() < 0하는 당신이해야 의미 하지 로는 것, 당신의 소켓 닫기 의 닫습니다InputStream .

내가 C에서, 그리고 지금은 자바에서했던 것에서, 이러한 동기화 된 닫기를 달성하는 것은 다음과 같이 이루어져야합니다 :

  1. 셧다운 소켓 출력 (다른 쪽 끝에 FIN을 보냅니다. 이것이이 소켓이 보낸 마지막 것입니다). 입력은 여전히 ​​열려 있으므로 read()리모컨을 감지 할 수 있습니다.close()
  2. InputStream다른 쪽에서 응답 -FIN을받을 때까지 소켓을 읽습니다 ( FIN을 감지하므로 동일한 단계적 연결 프로세스를 거치게됩니다). 버퍼 중 하나에 데이터가 포함되어있는 한 소켓을 실제로 닫지 않기 때문에 일부 OS에서 중요합니다. "유령"소켓이라고하며 OS에서 설명자 번호를 사용합니다 (최신 OS에서는 더 이상 문제가되지 않을 수 있음).
  3. (어느 쪽인지를 호출하여 소켓을 닫습니다 Socket.close()또는 폐쇄의 InputStreamOutputStream)

다음 Java 스 니펫에 표시된대로 :

public void synchronizedClose(Socket sok) {
    InputStream is = sok.getInputStream();
    sok.shutdownOutput(); // Sends the 'FIN' on the network
    while (is.read() > 0) ; // "read()" returns '-1' when the 'FIN' is reached
    sok.close(); // or is.close(); Now we can close the Socket
}

물론 양쪽 같은 방식으로 닫아야합니다. 그렇지 않으면 보내는 부분이 항상 while루프를 바쁘게 유지하기에 충분한 데이터를 보낼 수 있습니다 (예 : 보내는 부분이 데이터 만 보내고 연결 종료를 감지하기 위해 읽지 않는 경우). 그러나 당신은 그것에 대한 통제권이 없을 수도 있습니다).

@WarrenDew가 자신의 의견에서 지적했듯이 프로그램 (애플리케이션 계층)의 데이터를 폐기하면 애플리케이션 계층에서 비정상적인 연결 해제가 발생합니다. 모든 데이터가 TCP 계층 ( while루프) 에서 수신되었지만 폐기됩니다.

1 : " Fundamental Networking in Java "에서 : 그림 참조. 3.3 p. 45 및 전체 §3.7, pp 43-48


Java는 정상 종료를 수행합니다. 그것은 '잔인한'이 아닙니다.
론의 후작

2
@EJP, "graceful disconnection"은 TCP 수준에서 발생하는 특정 교환으로, 클라이언트는 서버와의 연결을 끊으려는 의지를 신호해야하며, 서버는 서버를 닫기 전에 나머지 데이터를 보냅니다. "남은 데이터 보내기"부분은 프로그램에서 처리해야합니다 (대부분의 경우 사람들은 아무 것도 보내지 않음). socket.close()이 클라이언트 / 서버 신호를 존중하지 않는 방식에서 호출 은 "잔인한"것입니다. 서버는 자신의 소켓 출력 버퍼가 꽉 찼을 때만 클라이언트 연결 끊김을 알립니다 (닫힌 다른 쪽에서 데이터를 확인하지 않기 때문입니다).
Matthieu 2013

자세한 내용은 MSDN 을 참조하십시오.
Matthieu 2013

Java는 응용 프로그램이 먼저 '남은 데이터 보내기'대신 Socket.close ()를 호출하도록 강제하지 않으며 먼저 종료를 사용하는 것을 방지하지 않습니다. Socket.close ()는 close (sd)가하는 일을합니다. Java는이 점에서 Berkeley Sockets API 자체와 다르지 않습니다. 사실, 대부분의 측면에서.
Marquis of Lorne

2
@LeonidUsov 그것은 단순히 잘못된 것입니다. Java read()는 스트림 끝에서 -1을 반환하고 여러 번 호출해도 계속 그렇게합니다. AC read()또는 recv()스트림 끝에서 0을 반환하고 호출 횟수에 관계없이 계속 수행합니다.
론의 후작

18

나는 이것이 소켓 프로그래밍 질문에 더 가깝다고 생각합니다. Java는 소켓 프로그래밍 전통을 따르고 있습니다.

에서 위키 백과 :

TCP는 한 컴퓨터의 한 프로그램에서 다른 컴퓨터의 다른 프로그램으로 바이트 스트림을 안정적으로 순서대로 전달합니다.

핸드 셰이크가 완료되면 TCP는 두 끝점 (클라이언트와 서버)을 구분하지 않습니다. "클라이언트"와 "서버"라는 용어는 대부분 편의를위한 것입니다. 따라서 "서버"는 데이터를 보내고 "클라이언트"는 다른 데이터를 서로에게 동시에 보낼 수 있습니다.

"닫기"라는 용어도 오해의 소지가 있습니다. FIN 선언 만 있습니다. "더 이상 보내지 않겠다"는 뜻입니다. 그러나 이것은 비행 중에 패킷이 없거나 다른 패킷이 더 이상 말할 수 없다는 것을 의미하지는 않습니다. 달팽이 메일을 데이터 링크 계층으로 구현하거나 패킷이 다른 경로를 이동 한 경우 수신자가 잘못된 순서로 패킷을 수신 할 수 있습니다. TCP는이 문제를 해결하는 방법을 알고 있습니다.

또한 프로그램으로서 버퍼에있는 내용을 계속 확인할 시간이 없을 수도 있습니다. 따라서 편의에 따라 버퍼에 무엇이 있는지 확인할 수 있습니다. 대체로 현재 소켓 구현은 그렇게 나쁘지 않습니다. 실제로 isPeerClosed ()가 있었다면 read를 호출 할 때마다해야하는 추가 호출입니다.


1
나는 그렇게 생각하지 않는다. 윈도우와 리눅스 모두에서 C 코드로 상태를 테스트 할 수있다 !!! 어떤 이유로 Java는 Windows와 Linux에있는 getsockopt 함수를 노출하는 것이 좋을 것처럼 일부 항목을 노출하지 않을 수 있습니다. 실제로 아래 답변에는 Linux 측에 대한 일부 Linux C 코드가 있습니다.
Dean Hiller

나는 'isPeerClosed ()'메소드를 갖는 것이 어떻게 든 모든 읽기 시도 전에 그것을 호출하도록 커밋한다고 생각하지 않습니다. 명시 적으로 필요할 때만 간단히 호출 할 수 있습니다. 소켓의 원격 부분이 닫혔는지 여부를 확인하려면 출력 스트림에 작성해야하지만 현재 소켓 구현이 그렇게 나쁘지 않다는 데 동의합니다. 그렇지 않은 경우에는 다른 쪽에서도 작성된 데이터를 처리해야하며 수직으로 향한 못에 앉아있는 것만큼이나 큰 즐거움입니다.)
Jan Hruby

1
그것은 않습니다 '더 이상 패킷이 비행이'평균. FIN은 비행 중 데이터 가 수신 된 수신 됩니다. 그러나 그것이 의미 하지 않는 것은 피어가 입력을 위해 소켓 닫았다는 것 입니다. 이를 감지 하려면 ** 뭔가를 보내고 * '연결 재설정'을 받아야합니다. FIN은 출력 중단을 의미했을 수 있습니다.
Marquis of Lorne

11

기본 소켓 API에는 이러한 알림이 없습니다.

송신 TCP 스택은 어쨌든 마지막 패킷까지 FIN 비트를 보내지 않을 것입니다. 따라서 송신 애플리케이션이 데이터가 전송되기 전에 논리적으로 소켓을 닫을 때 버퍼링 된 데이터가 많을 수 있습니다. 마찬가지로 네트워크가 수신 애플리케이션보다 빠르기 때문에 버퍼링 된 데이터 (모르겠습니다. 더 느린 연결을 통해 중계 할 수 있음)는 수신자에게 중요 할 수 있으며 수신 애플리케이션이 데이터를 버리는 것을 원하지 않을 것입니다. FIN 비트가 스택에 의해 수신 되었기 때문입니다.


내 테스트 예에서 (아마도 여기에 하나를 제공해야합니다 ...) 의도적으로 연결을 통해 전송 / 수신 된 데이터가 없습니다. 따라서 스택이 FIN (유예) 또는 RST (일부 비유 예 시나리오에서)를 수신한다고 확신합니다. 이것은 또한 netstat에 의해 확인됩니다.
Alexander

1
물론입니다. 버퍼링 된 것이 없으면 FIN이 즉시 전송되고 그렇지 않으면 빈 패킷 (페이로드 없음)으로 전송됩니다. 그러나 FIN 이후에는 연결의 끝에서 더 이상 데이터 패킷이 전송되지 않습니다 (전송 된 모든 항목은 여전히 ​​ACK됩니다).
Mike Dimmick

1
무슨 일이 일어나면 연결의 측면이 <code> CLOSE_WAIT </ code> 및 <code> FIN_WAIT_2 </ code>가되고이 상태에서 <code> isConcected () </ code> 및 <code>가됩니다. isClosed () </ code>는 여전히 연결이 종료되었음을 알 수 없습니다.
Alexander

제안 해 주셔서 감사합니다! 이제 문제를 더 잘 이해하고있는 것 같습니다. 질문을 좀 더 구체적으로 만들었습니다 (세 번째 단락 참조). 반 폐쇄 연결을 테스트 할 "Socket.isClosing"이없는 이유는 무엇입니까?
Alexander

8

지금까지 질문에 대한 완전한 답변이 없기 때문에 문제에 대한 현재 이해를 요약하고 있습니다.

TCP 연결이 설정되고 하나의 피어가 close()또는 shutdownOutput()해당 소켓을 호출 하면 연결의 다른 쪽 소켓이 CLOSE_WAIT상태 로 전환됩니다 . 원칙적으로 소켓이 CLOSE_WAIT호출하지 않고 상태 인지 여부를 TCP 스택에서 확인할 수 있습니다 read/recv(예 getsockopt(): Linux : http://www.developerweb.net/forum/showthread.php?t=4395 ). 가지고 다닐 수 있는.

Java의 Socket클래스는 BSD TCP 소켓에 필적하는 추상화를 제공하도록 설계된 것으로 보입니다. 아마도 이것이 TCP / IP 애플리케이션을 프로그래밍 할 때 사람들이 사용하는 추상화 수준이기 때문입니다. BSD 소켓은 INET (예 : TCP) 소켓 이외의 소켓을 지원하는 일반화이므로 소켓의 TCP 상태를 찾는 이식 가능한 방법을 제공하지 않습니다.

isCloseWait()BSD 소켓이 제공하는 추상화 수준에서 TCP 애플리케이션을 프로그래밍하는 데 익숙한 사람들은 Java가 추가 메서드를 제공 할 것이라고 기대하지 않기 때문에 이와 같은 방법 은 없습니다.


3
있습니다 자바는 이식성, 여분의 방법을 제공합니다. 플랫폼이 지원하지 않으면 false를 반환하는 isCloseWait () 메서드를 만들 수 있지만 지원되는 플랫폼에서만 테스트하면 얼마나 많은 프로그래머가 그 문제에 물 릴까요?
ephemient

1
나에게 이식 할 수있을 것 같은데… windows에는 msdn.microsoft.com/en-us/library/windows/desktop/…이 있고 Linux에는이 pubs.opengroup.org/onlinepubs/009695399/functions/…
Dean Hiller

1
프로그래머가 익숙한 것이 아닙니다. 소켓 인터페이스는 프로그래머에게 유용한 것입니다. 소켓 추상화는 TCP 프로토콜보다 더 많이 사용됩니다.
Warren Dew

isCloseWait()모든 플랫폼에서 지원되지 않기 때문에 Java와 같은 방법 은 없습니다.
Marquis of Lorne

ident (RFC 1413) 프로토콜을 사용하면 서버가 응답을 보낸 후 연결을 열어 두거나 더 이상 데이터를 보내지 않고 연결을 닫을 수 있습니다. Java ident 클라이언트는 다음 조회에서 3 방향 핸드 셰이크를 피하기 위해 연결을 열어 두도록 선택할 수 있지만 연결이 여전히 열려 있는지 어떻게 알 수 있습니까? 연결을 다시 열어 오류에 응답해야합니까? 아니면 프로토콜 설계 오류입니까?
david

7

(TCP) 소켓 연결의 원격 측이 닫혔는지 여부를 감지하는 것은 java.net.Socket.sendUrgentData (int) 메소드를 사용하여 수행 할 수 있으며 원격 측이 다운 된 경우 발생하는 IOException을 포착 할 수 있습니다. 이것은 Java-Java와 Java-C 사이에서 테스트되었습니다.

이것은 일종의 핑 메커니즘을 사용하도록 통신 프로토콜을 설계하는 문제를 방지합니다. 소켓에서 OOBInline을 비활성화 (setOOBInline (false))하면 수신 된 모든 OOB 데이터가 자동으로 삭제되지만 OOB 데이터는 계속 전송 될 수 있습니다. 원격 측이 닫히면 연결 재설정이 시도되고 실패하고 일부 IOException이 발생합니다. .

실제로 프로토콜에서 OOB 데이터를 사용하는 경우 마일리지가 다를 수 있습니다.


4

Java IO 스택은 갑작스러운 분해로 파괴 될 때 확실히 FIN을 보냅니다. 당신이 이것을 감지 할 수 없다는 것은 말이되지 않습니다. b / c 대부분의 클라이언트는 그들이 연결을 종료하는 경우에만 FIN을 보냅니다.

... 제가 NIO Java 클래스를 정말 싫어하기 시작한 또 다른 이유입니다. 모든 것이 약간의 엉덩이 인 것 같습니다.


1
또한 FIN이있을 때 읽기 (-1 반환)시에만 스트림이 끝나고 끝납니다. 그래서 이것이 내가 읽기 측에서 종료를 감지 할 수있는 유일한 방법입니다.

3
당신은 그것을 감지 할 수 있습니다. 읽을 때 EOS를 얻습니다. 그리고 Java는 FIN을 보내지 않습니다. TCP가 그렇게합니다. Java는 TCP / IP를 구현하지 않고 플랫폼 구현 만 사용합니다.
Marquis of Lorne

4

흥미로운 주제입니다. 확인하기 위해 방금 자바 코드를 파헤 쳤습니다. 내 발견에서 두 가지 뚜렷한 문제가 있습니다. 첫 번째는 TCP RFC 자체로, 원격으로 닫힌 소켓이 반이중으로 데이터를 전송할 수 있으므로 원격으로 닫힌 소켓은 여전히 ​​절반이 열려 있습니다. RFC에 따라 RST는 연결을 닫지 않으므로 명시적인 ABORT 명령을 보내야합니다. 그래서 Java는 반 폐쇄 소켓을 통해 데이터를 보낼 수 있습니다.

(두 끝점에서 닫힘 상태를 읽는 방법에는 두 가지가 있습니다.)

다른 문제는 구현에서이 동작이 선택 사항이라고 말합니다. Java는 이식성을 위해 노력하면서 최고의 공통 기능을 구현했습니다. (OS, 반이중 구현)의지도를 유지하는 것이 문제 였을 것입니다.


1
RFC 793 ( faqs.org/rfcs/rfc793.html ) 섹션 3.5 연결 닫기 에 대해 이야기하고 있다고 가정합니다 . 양측이 연결의 단계적 종료를 완료하고 데이터를 보내거나받지 않아야하는 상태가되기 때문에 문제를 설명하는지 잘 모르겠습니다.
Alexander

의존합니다. 소켓에 몇 개의 FIN이 표시됩니까? 또한 플랫폼 특정 문제 일 수 있습니다. Windows가 FIN으로 각 FIN에 응답하고 양쪽 끝에서 연결이 닫혀있을 수 있지만 다른 운영 체제가 이러한 방식으로 작동하지 않을 수 있으며 여기서 문제 2가 발생합니다
Lorenzo Boccaccia

1
아니요, 안타깝게도 그렇지 않습니다. isOutputShutdown 및 isInputShutdown은이 "검색"에 직면했을 때 모든 사람이 가장 먼저 시도하지만 두 메서드 모두 false를 반환합니다. 방금 Windows XP 및 Linux 2.6에서 테스트했습니다. 4 개 메소드의 반환 값은 읽기 시도 후에도 동일하게 유지됩니다
Alexander

1
기록을 위해 이것은 반이중이 아닙니다. 반이중은 한 번에 한 쪽만 전송할 수 있음을 의미합니다. 양측은 여전히 ​​보낼 수 있습니다.
rbp

1
isInputShutdown 및 isOutputShutdown 은 연결 의 로컬 끝을 테스트합니다.이 소켓에서 shutdownInput 또는 shutdownOutput을 호출했는지 여부를 확인하는 테스트입니다. 그들은 연결의 원격 끝에 대해 ​​아무것도 말하지 않습니다.
Mike Dimmick 2013-08-22

3

이것은 자바 (그리고 내가 살펴본 다른 모든 것)의 OO 소켓 클래스의 결함이다. 선택 시스템 호출에 접근 할 수 없다.

C의 정답 :

struct timeval tp;  
fd_set in;  
fd_set out;  
fd_set err;  

FD_ZERO (in);  
FD_ZERO (out);  
FD_ZERO (err);  

FD_SET(socket_handle, err);  

tp.tv_sec = 0; /* or however long you want to wait */  
tp.tv_usec = 0;  
select(socket_handle + 1, in, out, err, &tp);  

if (FD_ISSET(socket_handle, err) {  
   /* handle closed socket */  
}  

을 사용하여 동일한 작업을 수행 할 수 있습니다 getsocketop(... SOL_SOCKET, SO_ERROR, ...).
David Schwartz

1
오류 파일 설명자 세트는 닫힌 연결을 나타내지 않습니다. 선택 설명서를 읽으십시오 : 'exceptfds-이 세트는 "예외 조건"에 대해 감시됩니다. 실제로 그러한 예외적 인 조건은 하나만 일반적입니다. 즉, TCP 소켓에서 읽기위한 대역 외 (OOB) 데이터의 가용성입니다. ' FIN은 OOB 데이터가 아닙니다.
Jan Wrobel

1
'Selector'클래스를 사용하여 'select ()'시스템 호출에 액세스 할 수 있습니다. 그래도 NIO를 사용합니다.
Matthieu

1
다른쪽에 의해 종료 된 연결에 대해 예외는 없습니다.
David Schwartz

1
많은 플랫폼 을 포함하여 Java는, select () 시스템 호출에 대한 액세스를 제공합니다.
Marquis of Lorne

2

다음은 절름발이 해결 방법입니다. SSL 사용;) 그리고 SSL은 종료시 종료 핸드 셰이크를 수행하므로 소켓이 닫혔다는 알림을받습니다 (대부분의 구현은 적절한 핸드 셰이크 분해를 수행하는 것 같습니다).


2
Java에서 SSL을 사용할 때 소켓이 닫혔다는 것을 어떻게 "알림"을 받습니까?
Dave B

2

이 동작의 이유는 (Java에만 국한되지 않음) TCP 스택에서 상태 정보를 얻지 못하기 때문입니다. 결국 소켓은 다른 파일 핸들 일 뿐이며 실제로 시도하지 않고 읽을 실제 데이터가 있는지 확인할 수 없습니다 ( select(2)거기에 도움이되지 않고 차단하지 않고 시도 할 수 있다는 신호일뿐입니다).

자세한 내용은 Unix 소켓 FAQ를 참조하십시오 .


2
REALbasic 소켓 (Mac OS X 및 Linux에서)은 BSD 소켓을 기반으로하지만 RB는 다른 쪽 끝에서 연결이 끊어지면 오류 102를 제공합니다. 그래서 저는 원래 포스터에 동의합니다. 이것은 가능해야하며 Java (및 Cocoa)가 제공하지 않는 것은 절망적입니다.
Joe Strout

1
@JoeStrout RB는 I / O를 수행 할 때만 가능합니다. I / O를 수행하지 않고 연결 상태를 알려주는 API는 없습니다. 기간. 이것은 Java 결함이 아닙니다. 이는 의도적 인 설계 기능인 TCP에 '다이얼 톤'이 없기 때문입니다.
Marquis of Lorne

select() 차단하지 않고 읽을 수있는 데이터 또는 EOS가 있는지 알려줍니다. '차단없이 시도 할 수있는 신호'는 의미가 없다. 비 차단 모드 인 경우 언제든지 차단하지 않고 시도 할 수 있습니다 . select()소켓 수신 버퍼의 데이터 또는 보류중인 FIN 또는 소켓 전송 버퍼의 공간에 의해 구동됩니다.
Marquis of Lorne

@EJP 어때요 getsockopt(SO_ERROR)? 실제로 getpeername소켓이 여전히 연결되어 있는지 알려줍니다.
David Schwartz

0

쓰기에만 패킷 교환이 필요하므로 연결 손실을 확인할 수 있습니다. 일반적인 해결 방법은 KEEP ALIVE 옵션을 사용하는 것입니다.


페이로드를 작성하지 않고 FIN이 설정된 패킷을 전송하여 엔드 포인트가 정상적인 연결 종료를 시작할 수 있다고 생각합니다.
Alexander

@Alexander 물론 그렇습니다.하지만 연결이 적은 것을 감지 하는이 답변과 관련이 없습니다 .
론 후작

-3

반 개방형 Java 소켓을 처리 할 때 isInputShutdown ()을 살펴볼 수 있습니다. isOutputShutdown ()을 살펴볼 수 있습니다.


아니오. 그것은 당신이 무엇을 불렀는지를 알려줍니다. 동료가 무엇을 불렀는지가 아닙니다.
론의 후작

그 진술의 출처를 공유 하시겠습니까?
JimmyB

3
반대로 소스를 공유 하시겠습니까? 귀하의 진술입니다. 증거가 있으면 가져 가자. 나는 당신이 틀렸다고 주장합니다. 실험을하고 내가 틀렸다는 것을 증명하십시오.
Marquis of Lorne

3 년 후 실험이 없었습니다. QED
Marquis of Lorne
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.