2016-06-30 1 views
0

나는 서버와 많은 클라이언트를 가지고 있습니다. 서버는 클라이언트가 비정상적으로 연결을 끊을 때 (TCP FIN을 보내지 않음) 연결을 끊거나이 클라이언트와 관련된 다른 일회용 객체가 없도록해야합니다.끊어진 연결 감지

어쨌든, 나는 this을 읽고 링크 된 블로그의 "최악의 경우를 가정하는 명시 적 타이머"라는 애플리케이션 프로토콜에 "keepalive 메시지"(헤더 바이트 만 포함)를 추가하는 것으로 결정했습니다.

클라이언트가 연결되면 (btw는 TcpListener와 TcpClient를 사용 중입니다) 서버는 30 초를 카운트하는 System.Threading.Timer를 시작합니다. 서버는 클라이언트로부터 무언가를 받으면 타이머를 다시 설정합니다. 타이머가 0에 도달하면 사용자를 연결 해제하고 처분해야하는 모든 것을 처리합니다. 또한 클라이언트 응용 프로그램에는 타이머가 있으며 사용자가 15 초 동안 아무 것도 보내지 않으면 (서버 값의 절반, 확실하게) 킵 얼라이브 메시지를 보냅니다.

제 질문은이 문제를 해결하는 더 쉬운 방법입니까? TcpClient의 일부 옵션일까요? 내가 TcpClient.ReceiveTimeout와 함께했지만 ReadAsync와 함께 작동하지 않는 것 같습니다.

+0

스티븐은 지적하고 있듯이 응용 프로그램 프로토콜에서 하트 비트 메시지를 사용하는 것이 연결이 활성 상태이고 두 응용 프로그램이 올바르게 작동하는지 확인하는 유일한 확실한 방법입니다. 많은 엔지니어가 응용 프로그램 스레드가 실패한 경우에도 계속 작동하는 하트 비트 스레드를 만들었습니다. 하트 비트가 솔루션의 운영 구조의 일부를 형성하는지 확인해야합니다. 그것의 사소한 문제. – Jim

+0

비동기 소켓 작업에 대해서는이 코드를 사용했습니다.이 코드는 성공적으로 사용되었습니다. http://blogs.msdn.com/b/pfxteam/archive/2011/12/15/10248293.aspx 'SocketAwaitable' – Jim

+0

감사! 나는이 코드를 시도 할 것이지만, "당신은 하트 비트가 솔루션의 운영 구조의 일부를 형성하도록해야한다"는 의미를 이해하지 못했습니다. – vlada

답변

1

As Stephen points out 응용 프로그램 프로토콜에서 하트 비트 메시지를 사용하는 것이 연결이 작동하고 두 응용 프로그램이 올바르게 작동하는지 확인하는 유일한 확실한 방법입니다. 많은 엔지니어가 응용 프로그램 스레드가 실패한 경우에도 계속 작동하는 하트 비트 스레드를 만들었습니다.

here 클래스를 사용하면 비동기 소켓 질문이 해결됩니다.

public sealed class SocketAwaitable : INotifyCompletion 
{ 
    private readonly static Action SENTINEL =() => { }; 

    internal bool m_wasCompleted; 
    internal Action m_continuation; 
    internal SocketAsyncEventArgs m_eventArgs; 

    public SocketAwaitable(SocketAsyncEventArgs eventArgs) 
    { 
     if (eventArgs == null) throw new ArgumentNullException("eventArgs"); 
     m_eventArgs = eventArgs; 
     eventArgs.Completed += delegate 
     { 
      var prev = m_continuation ?? Interlocked.CompareExchange(
       ref m_continuation, SENTINEL, null); 
      if (prev != null) prev(); 
     }; 
    } 

    internal void Reset() 
    { 
     m_wasCompleted = false; 
     m_continuation = null; 
    } 

    public SocketAwaitable GetAwaiter() { return this; } 

    public bool IsCompleted { get { return m_wasCompleted; } } 

    public void OnCompleted(Action continuation) 
    { 
     if (m_continuation == SENTINEL || 
      Interlocked.CompareExchange(
       ref m_continuation, continuation, null) == SENTINEL) 
     { 
      Task.Run(continuation); 
     } 
    } 

    public void GetResult() 
    { 
     if (m_eventArgs.SocketError != SocketError.Success) 
      throw new SocketException((int)m_eventArgs.SocketError); 
    } 
}