2010-08-18 5 views
1

죽은 TCP 연결을 감지하지 못하는 Socket.SendAsync 메서드에 문제가 있습니다. 내 클라이언트/서버 응용 프로그램에서 서버는 정기적 인 간격으로 연결된 클라이언트에게 하트 비트를 전송합니다.Socket.SendAsync가 죽은 TCP 연결을 감지하지 못합니다.

내가 겪고있는 문제는 클라이언트가 더 이상 클라이언트가 죽지는 않지만 SendAsync 메서드의 콜백이 "SocketError.Success"를 나타내며 Socket.Connected 속성이 true인데 클라이언트가 더 이상 " 살아 있는". 따라서 서버에 하트 비트 데이터가 제대로 전송되고 클라이언트가 여전히 살아있는 것처럼 보입니다.

매번이 문제가 발생합니다. 클라이언트 측 PC는 절전 모드 또는 최대 절전 모드로 설정되어 있습니다. 클라이언트가 VMWare 인스턴스에서 실행 중이고 해당 인스턴스가 일시 중단 된 경우. 클라이언트가 윈도우 작업 관리자에서 사망, 응용 프로그램을 종료 할 때 나는

internal void InternalSendAsync(ByteDataChunk chunk) 
    { 
     asyncSendArgs.SetBuffer(chunk.Buffer, 0, chunk.Offset); 
     asyncSendArgs.UserToken = chunk; 
     Socket.SendAsync(asyncSendArgs); 
    } 

    private void SendCompleted(object sender, SocketAsyncEventArgs args) 
    { 
     if (args.SocketError != SocketError.Success || !Socket.Connected) 
     { 
      InternalDisconnect(args.SocketError); 
      return; 
     } 

     // all is good & do some other stuff 
    } 

누구 여기에 무슨 일이 일어나고 있는지 어떤 생각을 가지고 있으며, 등이 문제가 표시되지 않는 SendCompleted 방법에도 불구하고 소켓 오류를 반환하지 않는 이유 클라이언트는 오래 전에 죽었습니다 (이전에 여러 시간 동안 서버를 실행 시켰고 죽은 소켓이 감지되지 않았습니다)?

감사합니다,

MSDN에서

답변

3

: 의 성공적인 완료는가 SendAsync 방법은 데이터가 성공적으로 전달했다 를 표시하지 않는

참고.

IMO는 네트워킹에있어 가장 어려운 부분 중 하나입니다. 클라이언트가 데이터를 가지고 있는지 확실하지 않을 수 있습니다. 하트 비트 시스템을 구현하는 경우 클라이언트가 하트 비트를 에코 백으로 리턴하여 그것이 아직 살아 있음을 증명해야합니다.

프로세스를 일시 중단하거나 최대 절전 모드로 전환 할 때 실행중인 컴퓨터를 종료해도 소켓이 닫히지 않는다고 생각합니다.

+0

오른쪽 - 이것은 일반적인 접근 방식입니다. 클라이언트가 초 안에 하트 비트에 응답하지 않은 경우 클라이언트가 죽었다 고 가정하고 연결을 끊습니다. – caf

+0

이 방법을 사용하는 것이 좋겠지 만, 호스트가 절전/최대 절전 모드로 전환 된 경우에도 항상 이후에 보내기 오류가 발생하여 동기 전송과 관련하여이 문제를 보지 못했습니다. – TJF

0

실제로 하트 비트가 전송됩니까? 내 의심은 Naggle algorithm 일 것이다. wireshark을 빼고 전선에서 흐르는 물체를 확인하십시오. SocketOptionName.NoDelay으로 Nagle을 비활성화 할 수 있습니다. MSDN :

BeginSend 메서드가 성공적으로 완료되었다는 것은 기본 시스템에 네트워크 전송을위한 데이터를 저장할 공간이 있음을 의미합니다. 응용 프로그램에서 모든 바이트를 원격 호스트에 즉시 보내려는 경우, SetSocketOption을 사용하여 SocketOptionName.NoDelay을 활성화 할 수 있습니다. 네트워크 효율성을위한 버퍼링에 대한 자세한 내용은 MSDN의 Nagle 알고리즘을 참조하십시오.
+0

Nagle은 아무것도 Nagle 켜져있는 경우에도 데이터가 일정한 시간 간격 (일반적으로 200 - 500ms) 후에 전송됩니다 – TJF

+0

. NET 비동기 레이어가 자체 버퍼링을하는지 궁금해. –

0

Socket.Connected 속성을 무시하십시오. 그것은 거의 쓸모가 없습니다. 예제 코드에서 Socket.Connected이 true이거나 오류 코드가없는 경우 모두 정상이라고 가정합니다. 내가 할 첫 번째 일은 Socket.Connected 부분을 제거하는 것입니다.

정기적 인 하트 비트 전송과 함께 뛰어난 비동기 읽기를 항상 유지하는 것이 좋습니다. 소켓이 더 이상 연결되어 있지 않으면 읽기 또는 쓰기로 인해 오류가 발생합니다.

송신은 지수 백 오프와 함께 여러 번 시간 초과되어야합니다. 따라서 상대방이 사라지는 것을 감지하는 데 시간이 걸립니다 (프로그램이 종료 될 경우 OS는 연결이 더 이상 실행 가능하지 않다고 즉시 응답합니다). 그래도 몇 시간 가까이 있지 않아야합니다. 처음에는 몇 분 (네트워크 연결이 느린 경우). 내 소켓은 1 초 이내에 끊어진 연결을 정기적으로 감지합니다.

+0

정확히 내가하고있는 일이고 클라이언트 시스템이 잠자기 된 경우 쓰기가 오류를 발생시키지 않는 이유를 중심으로 한 질문입니다. SendAsync 메서드를 통해 몇 시간 동안 해당 소켓에 쓸 수 있으며 클라이언트가 일시 중단 된 경우 절대로 오류가 발생하지 않지만 오류가 발생하면 예를 들어 오류가 발생합니다. 클라이언트가 죽었습니다 – TJF

+0

당신의 코드는'Socket.Connected'가 참이면 연결이 여전히 유효하다고 가정하고 있습니다. 그건 잘못된 것입니다. 체크의'Socket.Connected' 부분을 제거하고 (체크의 에러 부분 만 남겨둔다), 그것이 작동하는지 확인하십시오. –

+0

맞아요, 여기에 코드를 게시 할 때 생산 코드가 다른 일부 작업을 수행함에 따라 오류가 발생했습니다.이를 단축하고 여기에 게시 할 때 잘못 입력했습니다. 생산 코드는 || ! Socket.Connected – TJF

0

Wireshark 또는 이와 유사한 것을 사용하여 네트워크에서 어떤 현상이 발생 했습니까? 클라이언트의 TCP 서브 시스템이 패킷을 수신 확인하지 않으면 소켓 오류가 발생한다고 생각할 수 있습니다. 어쩌면 클라이언트가 포트를 열어두고 패킷을 확인하는 중일 수 있습니다. 그렇다면 클라이언트에서 해결하려고 시도하거나 니콜라이가 말한 것을 할 수 있습니다.

+0

캡쳐에서 PSH, ACK, 3 번의 재전송, 그 이후의 아무 것도 없습니다. 이호, ACK가 수신되지 않았기 때문에 소켓에서 타임 아웃 예외를 수신해야하지만 그렇지 않습니까? – TJF

관련 문제