如何检测断开连接的套接字C#?

时间:2011-04-15 17:51:08

标签: c# sockets

我一直在使用C#中的套接字客户端程序,并且想知道如何检测套接字的另一端何时“不正常”地断开连接,就像拔出网络电缆或硬重置一样。

我有以下这些函数来访问套接字并根据SO问题here和此MSDN article,检查断开连接套接字的最佳方法是发送一个1字节的消息长度为0.如果抛出异常且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设备。我在另一个线程中读到,不同的OS可能会在它们死亡时发送套接字关闭信号。也许Windows Mobile OS不会这样做??

2 个答案:

答案 0 :(得分:6)

如果远程计算机正常断开会话,则 Socket.Receive()方法将以0字节返回。你必须检测到它 要知道远程端已断开连接:

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

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

希望这有助于解决您的问题。

答案 1 :(得分:0)

我知道这已经很晚了,但我想出了一个狡猾的解决方案。

我不得不与第三方软件进行通信,该软件期望在发送的每个命令上都有回车符,否则会忽略它。

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

如果你正在编写服务器和客户端,你可以很容易地想出一个另一个忽略的checkdigit。

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

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;
}