如何检测一个断开的套接字c#

本文关键字:断开 套接字 一个 何检测 检测 | 更新日期: 2023-09-27 17:50:14

我一直在c#中工作套接字客户端程序,我想知道如何检测套接字的另一端何时"不优雅地"断开连接,如在网线拔出或硬复位中。

我有下面这些函数来访问套接字,根据这里的SO问题和这篇MSDN文章,检查套接字是否断开连接的最佳方法是发送长度为0的1字节消息。如果抛出异常且WSAEWOULDBLOCK不是错误码,则套接字断开连接。我已经尝试过了,但是在硬重置服务器连接后,客户端将调用Send(new byte[1], 0, 0, SocketFlags.None)并成功返回,之后Receive()命令返回WSAEWOULDBLOCK错误。

给了什么? ?

下面是我的代码。_socket设置为非阻塞模式:
private int nonBlockRecv(byte[] recvBytes, int offset, int size, SocketFlags sf)
{
    int bytesRecv = 0;
    while (true)
    {
        try
        {
            nonBlockSend(new byte[1], 0, 0, sf);
            bytesRecv = _socket.Receive(recvBytes, offset, size, sf);
            break;
        }
        catch (SocketException excp)
        {
            if (excp.ErrorCode != 10035) // WSAEWOULDBLOCK
                throw excp;
        }
    }
    return bytesRecv;
}
private int nonBlockSend(byte[] sendBytes, int offset, int size, SocketFlags sf)
{
    int bytesSent = 0;
    while (true)
    {
        try
        {
            _socket.Send(sendBytes, offset, size, sf);
            break;
        }
        catch (SocketException excp)
        {
            if (excp.ErrorCode != 10035) // WSAEWOULDBLOCK
                throw excp;
        }
    }
    return bytesSent;
}

编辑:这可能是有益的,但服务器是Windows Mobile设备。我在另一个线程读到,不同的操作系统可能能够发送套接字关闭信号,当他们死亡。也许Windows Mobile操作系统不这样做??

如何检测一个断开的套接字c#

如果远程计算机优雅地断开会话,则Socket.Receive()方法将返回0字节。你必须察觉到要知道远端已断开连接:

int recv = sock.Receive(data);
if (recv == 0)
{
    // Remote client has disconnected.
}
else
{
    // Remote client has sent data.
}

此外,即使出现SocketException,您也可以识别套接字断开的异常。

我知道这有点晚了,但我想出了一个巧妙的解决方案。

我必须与第三方软件进行通信,该软件希望在发送的每个命令上返回一个回车,否则它会忽略它。

在主阶段,我的客户端套接字处于接收第三方软件响应的循环中。我的解决方案并不理想,但基本的前提是,我在套接字上设置了一个接收超时,以便循环将尝试读取5秒,然后陷入catch,然后再次循环。在每次接收之前,我调用我自己的isconnected方法,它执行一个小的写操作,没有回车,所以它被第三方软件忽略,但如果网络掉线,它会给我一个可靠的故障切换。如果写失败,我所做的就是抛出一个LostConnectionException并从外部处理。

如果你同时编写服务器端和客户端代码,你可以很容易地提出一些对方忽略的校验数字。

这可能不完美,但对我来说是可靠的。

while (numberOfBytesRead == 0)
{          
    try
    {
        IsConnected();
        _socket.ReceiveTimeout = 5000;
        numberOfBytesRead = _socket.Receive(myReadBuffer, 0, myReadBuffer.Length, SocketFlags.None);
    }
    catch (Exception e)
    {
        if (e.GetType() == typeof (LostConnection))
        {
            Status = SocketStatus.offline;
            throw;
        }
    }
}

和isconnected方法看起来像这样

public bool IsConnected(Socket s)
{
    try
    {
        ASCIIEncoding encoder = new ASCIIEncoding();
        byte[] buffer = encoder.GetBytes("test");
        s.Send(buffer, 0, buffer.Length, SocketFlags.None);
    }
    catch (Exception)
    {
        throw new LostConnection();
    }
    return s.Connected;
}