2009-09-02 2 views
8

하나의 클라이언트 만 받아 들일 수있는 C#으로 서버를 개발 중이며 다른 클라이언트가 연결 요청을 받아들이려면이 클라이언트의 연결이 끊어졌을 때를 알아야합니다..NET에서 클라이언트 연결 끊김을 검색하는 최선의 방법은 무엇입니까?

나는 지속적으로 연결 요청을 수신하고 Socket.BeginAccept으로 클라이언트를 수락하거나 거부하는 첫 번째 소켓을 사용하고 있습니다. 클라이언트가 받아 들여지면 Socket.EndAccept에 의해 반환 된 새로운 소켓은 클라이언트와 서버 사이의 통신에 사용됩니다. 그런 다음 서버는 Socket.Begin/EndReceive을 사용하여 클라이언트의 명령을 기다리고 응답을 보냅니다. 서버는 텔넷 형 프로토콜을 사용합니다. 즉, 각 명령과 각 응답 행은 \r\n으로 끝나야합니다.

클라이언트의 연결이 끊어 졌는지 확인하기 위해 빈 메시지 ("\r\n")를 클라이언트에 500ms마다 보내는 타이머를 설치했습니다. 클라이언트가 단절된 경우 Socket에 의해 예외가 throw됩니다. 이 예외는 현재 세션을 닫고 새 연결을 허용하는 서버에 의해 포착됩니다. 이 솔루션은 강력하지만 네트워크를 통한 불필요한 트래픽을 의미하므로 실제 응답을 얻기 전에 더미 메시지를 필터링해야하는 클라이언트가 올바르게 처리해야합니다.

빈 버퍼 (Socket.Send(new byte[1], 0, 0))를 보내려고했지만 서버 -> 클라이언트 방향으로 작동하지 않는 것 같습니다.

또 다른 해결책은 Socket.EndReceive이 0 바이트를 반환하는 경우를 처리하는 것일 수 있습니다. 그것은 "유휴"시간 동안 발생하는 단절의 경우에 잘 작동합니다. 그러나 메시지 전송 중에 클라이언트의 연결이 끊어지면 서버는 항상 메시지를 보지 않고 무기한 대기합니다.

이 문제에 관해 여러 스레드와 질문을 보았지만 좋은 솔루션을 본 적이 없습니다.

제 질문은 : 닷넷에서 단절을 감지하는 가장 좋은 방법은 무엇입니까?

답변

4

유일하게 다른 옵션은 TCP가 keep-alive를 너무 자주 보내도록하는 것입니다. TCP는 keep-alive를 매번 보내지 만, 지금은 당신이 지금하고있는 것과 같은 폴링이지만 TCP 레이어에서 처리되므로 프로토콜이 아닙니다. 알 필요가 없다.

그러나 다른 클라이언트에게 무언가를 보내지 않고 응답을 얻지 못하면 폴링이 연결되어 있는지 여부를 알 수 없습니다.

활성 상태로 인해 원격 서버가 세션을 중단시키지 않도록 표준 NAPT와 같은 상태 보존 형 패킷 검사를 통해 통신 할 때에도 연결 유지가 필요할 수 있습니다.

+0

확인, 내 소켓에 KeepAlive를 사용할 수 있도록 코드를 추가했습니다. 그러나 나는 지금 무엇을 기대하고 있나? 클라이언트가 연결을 끊었을 때 아무 일도 일어나지 않습니다 ... 나는 예외를 어딘가에서받을 것으로 예상됩니다 ... 정기적으로 읽거나 쓸까요? – cedrou

+1

Begin/EndReceive를 사용 했는데도? 그렇다면 BeginReceive는 콜백을 실행해야하며 결과를 얻기 위해 EndReceive를 호출 할 때 예외가 발생해야합니다. 그렇지 않으면 스트림 0 바이트를 읽습니다. –

+0

그래, 지금 예외가 생겼어. 고마워. – cedrou

3

아래의 방법을 사용하여 클라이언트가 아직 연결되어 있는지 확인할 수 있습니다. 이

public static bool IsConnected(this TcpClient client) 
{ 
    try 
    { 
     bool connected = !(client.Client.Poll(1, SelectMode.SelectRead) && client.Client.Available == 0); 

     return connected; 
    } 
    catch 
    { 
     return false; 
    } 
} 

answer 내가 내 코드를 가지고 어떻게 테스트 소켓입니다.

+2

이 방법은 클라이언트가 연결을 명시 적으로 닫은 경우 제대로 작동하지만 연결이 끊어진 경우에는 작동하지 않습니다 (예를 들어 케이블이 분리되어 있음). – cedrou

+0

살아있는 곳이 어디 있는지, OS와 TCP 프로토콜은 클라이언트에게주기적인 메시지를 처리하여 그것이 살아 있는지 확인하고 소켓을 폴링하면 로컬 상태를 검사합니다. keep alive가 실패하면 소켓은 더 이상 연결이 없다고보고해야합니다. –

+0

비동기 Begin/EndReceive를 사용할 때 소켓이 연결 유지에 실패 할 때 오류로 콜백을 받아야하므로 폴링이 필요하지 않습니다. –

0

클라이언트를 제어 할 수 있습니까? 그렇다면 서버가 연결을 끊었다 고 말하는 특수 패킷을 클라이언트가 보내도록 한 다음 소켓을 분리하십시오.

클라이언트가 실제로 연결이 끊어진 경우 (Socket.Shutdown() 또는 Socket.Close() 사용) 또는 클라이언트가 엄청난 시간 동안 유휴 상태인지 여부를 감지하려고합니까? 꺼내지?

어느 경우 든 클라이언트가 서버에 주기적으로 메시지를 보냅니다.서버는 마지막 하트 비트를 추적 할 수 있으며, 클라이언트가 하트 비트를 3 회 이상 누락하면 클라이언트의 연결을 끊을 수 있습니다. 네, 여분의 데이터가 필요하지만 그것은 사물의 웅장한 계획에서 그리 나쁘지 않습니다. 좋은 시간에 하트 비트를 보내도록 클라이언트를 조정하면 클라이언트가 살아 있는지 알 수 있고 하트 비트간에 너무 길지 않으므로 매우 좋은 시스템을 가질 수 있습니다.