TCP连接保持活动状态

6
我正在创建一款客户端/服务器应用程序。服务器已经设计好并准备好等待客户端的连接。现在,在客户端部分,我希望在整个应用程序的生命周期内保持连接处于活动状态,并且只有当主客户端应用程序关闭或关机,或者服务器关闭它时,连接才会关闭。
目前,每隔10秒钟服务器会关闭TCP连接。我尝试使用
socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.KeepAlive, true);

但这对我不起作用......以下是我的代码块

public TCPStreamDevice(string RemoteIPAddress, int RemotePort, string SourceIPAddress, int SourcePortNo)        
{
    mIpAddress = RemoteIPAddress;
    mPort = RemotePort;

    mClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    System.Net.IPEndPoint LocalEndPoint = new System.Net.IPEndPoint(System.Net.IPAddress.Parse(SourceIPAddress), SourcePortNo);

    mClient.Bind(LocalEndPoint);

    mDataReceivedCallback = new AsyncCallback(DataReceivedTCPCallback_Handler);
    mBuffer = new byte[1024];
    Description = new DeviceDescription();
}

在处理程序中,我有以下内容:
private void DataReceivedTCPCallback_Handler(IAsyncResult ar)
{
    try
    {
        Socket client = (Socket)ar.AsyncState;
        int bytesReceived = client.EndReceive(ar);

        if (bytesReceived > 0)
        {
            //to know transport level errors
            //EngineInterface.reponseReceived(mBuffer, false);

            ReceiveCallBackFunc(mBuffer, bytesReceived);

            client.BeginReceive(mBuffer, 0, 1024, SocketFlags.None, DataReceivedTCPCallback_Handler, client);
        }
        else
        {
            //disconnect
            /* when there is no datapacket  means no TCP connection is alive now (how can i keep Tcp alive here) */
        }
    }
}

1
很可能是服务器关闭了连接。当超时时间到达时,除了在10秒内发送一些数据外,你无法做任何事情。0字节的接收意味着另一端已经断开连接。 - Jeroen van Langen
有没有办法重新初始化TCP会话? - Balwinder SIngh
当需要时,您将不得不重新连接。这是高负载服务器的常见行为。 - Jeroen van Langen
2
即使您希望保持客户端应用程序的连接始终处于打开状态,也必须允许其关闭。网络并非100%可靠,任何假设它们是可靠的设计都是不好的设计。 - Brian O''Byrne
3个回答

10
在调用SetSocketOption()时,KeepAliveSocketOptionLevel.Tcp级别上无效,而应该使用SocketOptionLevel.Socket。请使用以下代码:SetSocketOption( SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true )

您还应该为套接字设置keepalivetimekeepaliveinterval设置。搜索SetSocketKeepAliveValuesSetTcpKeepAlive - Ruslan K.
1
@RuslanK。不行 - ServicePointManager.SetTcpKeepAlive 仅用于 HTTP 连接(ServicePointManager 是面向 HTTP 的)。 - Sebazzz

2
上面的评论和答案是有效的 - 听起来打开整个应用程序的套接字并期望一切正常工作是一个糟糕的设计选择 - 您应该建立某种故障转移机制,以防连接断开。
回到保持活动状态:您需要在服务器和客户端两端都需要它们,因此请检查双方的套接字设置。我认为保持活动状态的默认值为2小时 - 这是等待保持活动数据包的长时间,但可以更改。检查 Socket.IOControl 方法,并使用类似于此(非托管)结构的 IOControlCode.KeepAliveValues :http://msdn.microsoft.com/en-us/library/ms741621.aspx。有关控件代码的更多信息,请单击此处:http://msdn.microsoft.com/en-us/library/system.net.sockets.iocontrolcode.aspx

1
你代码中的注释(“当没有数据包时表示没有TCP连接”)是放在你从另一端接收到一个断开连接(0字节)数据包的地方。由于对方选择关闭它,所以无法保持那个连接活动状态。
如果连接由于网络问题而关闭,则会抛出异常,或者看起来连接有效但很安静。
保持活动机制总是与超时一起工作 - 超时强制执行“如果 x 秒内没有接收到数据,则关闭连接”,而保持活动仅发送虚拟数据包以防止超时发生。
通过自己实现协议(你正在操作 TCP/IP 层),只有在对方已经实现了超时的情况下才需要实现保持活动。

如何实现保持活动计时器?您能帮我吗?我尝试了一些教程中的保持活动方法,但它们都没有起作用。 - Balwinder SIngh
网络设备可能会在两个端点之间断开连接,这在传输尝试之前不会被任何一端检测到。请参阅:http://tldp.org/HOWTO/TCP-Keepalive-HOWTO/overview.html - Deantwo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接