2016-05-27 2 views
2

При кодировании клиента/сервера Socket я решил реализовать HeartBeat, чтобы узнать, жив ли клиент, но затем искал другие способы сделать это и заметил этот фрагмент кода, который, похоже, делает именно это из описания:Как работает расширение Socket Keep-Alive? C#

public static class SocketExtensions 
{ 
    /// <summary> 
    ///  A structure used by SetKeepAliveEx Method 
    /// </summary> 
    [StructLayout(LayoutKind.Sequential)] 
    internal struct TcpKeepAlive 
    { 
     internal uint onoff; 
     internal uint keepalivetime; 
     internal uint keepaliveinterval; 
    }; 

    /// <summary> 
    ///  Sets the Keep-Alive values for the current tcp connection 
    /// </summary> 
    /// <param name="socket">Current socket instance</param> 
    /// <param name="keepAliveInterval">Specifies how often TCP repeats keep-alive transmissions when no response is received. TCP sends keep-alive transmissions to verify that idle connections are still active. This prevents TCP from inadvertently disconnecting active lines.</param> 
    /// <param name="keepAliveTime">Specifies how often TCP sends keep-alive transmissions. TCP sends keep-alive transmissions to verify that an idle connection is still active. This entry is used when the remote system is responding to TCP. Otherwise, the interval between transmissions is determined by the value of the keepAliveInterval entry.</param> 
    public static void SetKeepAliveEx(this Socket socket, uint keepAliveInterval, uint keepAliveTime) 
    { 
     var keepAlive = new TcpKeepAlive 
     { 
      onoff = 1, 
      keepaliveinterval = keepAliveInterval, 
      keepalivetime = keepAliveTime 
     }; 
     int size = Marshal.SizeOf(keepAlive); 
     IntPtr keepAlivePtr = Marshal.AllocHGlobal(size); 
     Marshal.StructureToPtr(keepAlive, keepAlivePtr, true); 
     var buffer = new byte[size]; 
     Marshal.Copy(keepAlivePtr, buffer, 0, size); 
     Marshal.FreeHGlobal(keepAlivePtr); 
     socket.IOControl(IOControlCode.KeepAliveValues, buffer, null); 
    } 
} 

Кажется, что эта работа намного проще, чем реализация HeartBeat, хотя я не совсем понимаю, как это работает, похоже, что-то делает с неуправляемым кодом? И если да, то почему?

Объяснение будет оценено, спасибо!

ответ

1

KeepAlive является частью протокола TCP. Включив KeepAlive, ОС будет периодически отправлять пустые пакеты другой стороне и ждать ACK. Если ACK не получен в течение требуемого периода ожидания, соединение считается сломанным, и приложение может быть уведомлено.

Однако KeepAlive обычно не требуется, если у вас нет гнезда только для приема, или ваше соединение будет оставаться бездействующим в течение длительных периодов времени.

В гнезде только для приема вы не отправляете никаких данных, поэтому единственный способ обнаружить сломанное соединение - отправить нулевой пакет и дождаться ACK.

Если у OTOH есть двунаправленный сокет, каждый раз, когда вы отправляете данные другой стороне, вы также проверяете, было ли соединение отключено, поэтому нет необходимости в KeepAlive. Обратите внимание, что если вы отправляете данные только в ответ на другой конец отправки данных, вам по-прежнему нужен KeepAlive, потому что вы, возможно, никогда не попадете на «отправку» части вашего протокола.

Кроме того, как отметил Remy Lebeau в своем комментарии, соединение, которое может быть бездействующим в течение длительного времени, может потребовать KeepAlive, поскольку некоторые маршрутизаторы/брандмауэры закрывают незанятые соединения через некоторое время.

+1

"* Однако KeepAlive требуется только в том случае, если у вас есть приемный разъем *" - это неверно. Существуют и другие причины использования Keepalive, такие как поддержание соединения в режиме ожидания, пока он долгое время простаивает (подумайте о подключении FTP-команды, которое не работает во время длительной передачи по соединению данных). Некоторые маршрутизаторы/межсетевые экраны закрывают незанятые соединения через некоторое время, поэтому Keepalive можно использовать для решения этой проблемы. –

+0

@RemyLebeau: Вы правы, спасибо, что подняли его. Я отредактировал свой ответ для полноты –

Смежные вопросы