替代NetworkStream.Read的方法,指示远程主机已关闭连接?

5

关于使用 TcpClient 类处理 TCP/IP 连接,除了等待 NetworkStream.Read 方法返回 0 之外,是否有其他检查远程主机是否已关闭连接的替代方法?


你不想等待吗?使用BeginRead()。EndRead()会抛出异常。 - Hans Passant
@nobugz:除了捕获异常,还有其他的选择吗? - Lopper
请记住,您仅会收到远程主机正常关闭连接时的通知。结果通常是您希望在一段时间内没有活动后关闭连接,因此需要设置超时。根据您使用的协议,您还可以偶尔向主机发送消息,因为写操作将使您能够快速确定主机是否仍然保持连接处于打开状态或非正常关闭连接。 - Phil
@HansPassant 不,使用 BeginRead()EndRead() 时不会抛出异常。 - Dio F
1个回答

6

您可以在 TcpClient.Client 上使用 IOControlCode.KeepAliveValues 来确保至少在指定的时间间隔内进行保持活动检查,然后检查 TcpClient.Client.Connected 属性。

以下是使用示例:

struct tcp_keepalive
{
    public int OnOff;
    public int KeepAliveTime;
    public int KeepAliveInterval;

    public unsafe byte[] Buffer
    {
        get
        {
            var buf = new byte[sizeof(tcp_keepalive)];
            fixed(void* p = &this) Marshal.Copy(new IntPtr(p), buf, 0, buf.Length);
            return buf;
        }
    }
};

static void KeepAliveTest()
{
    using(var c = new TcpClient())
    {
        c.Connect("www.google.com", 80);
        var s = c.Client;
        var ka = new tcp_keepalive();
        ka.OnOff = 1; // enable
        ka.KeepAliveTime = 1000 * 60; // 60 seconds of inactivity allowed
        ka.KeepAliveInterval = 1000; // 1 second interval on keep-alive checks (default)
        s.IOControl(IOControlCode.KeepAliveValues, ka.Buffer, null);
        var ns = c.GetStream();
        Console.WriteLine("Connected to " + s.RemoteEndPoint);
        while(true)
        {
            SocketError se;
            s.Blocking = false;
            s.Receive(new byte[0], 0, 0, SocketFlags.Peek, out se);
            s.Blocking = true;
            if(!s.Connected)
            {
                // se==SocketError.ConnectionReset||SocketError.NetworkReset if the connection was closed because of a keep-alive check
                Console.WriteLine("Socket disconnected: " + se);
                break;
            }
            // do other stuff
            if(ns.DataAvailable) ns.Read(new byte[100], 0, 100);
            else Thread.Sleep(10);
        }
    }
}

1
IOControlCode.KeepAliveValues是使用字节作为Socket.IOControl方法的第二个参数进行设置的。要使用多少字节,以及该值是以秒还是毫秒为单位设置的?似乎无法从以下MSDN网站中找到上述问题的答案。http://msdn.microsoft.com/en-us/library/8a3744sh.aspx - Lopper
SIO_KEEPALIVE_VALS文档位于http://msdn.microsoft.com/en-us/library/dd877220(VS.85).aspx。 - Pent Ploompuu

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