C# 处理阻止.NET套接字的超时

C# 处理阻止.NET套接字的超时,c#,sockets,networking,C#,Sockets,Networking,使用Accept方法创建的TcpClient实例用于管理客户端连接。当我需要终止服务器线程时会出现问题,因为它在接收调用时被阻塞 因此,我在TcpClient ReceiveTimeout中设置了一个循环,以便每n毫秒循环一次以测试退出条件。结果是接收操作引发异常(SocketException),错误代码为SocketError.TimedOut。很好,我在想 问题在于属性返回false,但如MSDN文档中所述: Connected属性的值反映了截至最近一次操作的连接状态。如果需要确定连接的当

使用Accept方法创建的TcpClient实例用于管理客户端连接。当我需要终止服务器线程时会出现问题,因为它在接收调用时被阻塞

因此,我在TcpClient ReceiveTimeout中设置了一个循环,以便每n毫秒循环一次以测试退出条件。结果是接收操作引发异常(SocketException),错误代码为SocketError.TimedOut。很好,我在想

问题在于属性返回false,但如MSDN文档中所述:

Connected属性的值反映了截至最近一次操作的连接状态。如果需要确定连接的当前状态,请进行非阻塞的零字节发送调用。如果调用成功返回或抛出WAEWoldblock错误代码(10035),则套接字仍处于连接状态;否则,插座将不再连接

// .Connect throws an exception if unsuccessful
client.Connect(anEndPoint);

// This is how you can determine whether a socket is still connected.
bool blockingState = client.Blocking;
try
{
    byte [] tmp = new byte[1];

    client.Blocking = false;
    client.Send(tmp, 0, 0);
    Console.WriteLine("Connected!");
}
catch (SocketException e) 
{
    // 10035 == WSAEWOULDBLOCK
    if (e.NativeErrorCode.Equals(10035))
        Console.WriteLine("Still Connected, but the Send would block");
    else
    {
        Console.WriteLine("Disconnected: error code {0}!", e.NativeErrorCode);
    }
}
finally
{
    client.Blocking = blockingState;
}

Console.WriteLine("Connected: {0}", client.Connected);
因此,我所做的是:

try {
     // Receive operation on socket stream
     // Send operation on socket stream
} catch (SocketException e) {
    if (e.SocketErrorCode == SocketError.TimedOut) {
    try {
        IAsyncResult asyncResult;
        int sResult;

        asyncResult = mSocket.Client.BeginSend(new byte[] {}, 0, 0, SocketFlags.None, delegate(IAsyncResult result) { }, null);
        sResult = mSocket.Client.EndSend(asyncResult);
        Debug.Assert(asyncResult.IsCompleted == true);

        if (mSocket.Connected == false)
            throw new Exception("not more connected");  // Always thrown
    } catch (Exception e) {
             // ...
        }
}
但是,即使执行了aynch Send操作,属性mSocket.Connected始终为false,导致外部循环终止(其他线程调用Disconnect方法终止服务器线程)

我遗漏了什么?

您应该查看链接到的MSDN页面上的C示例。它有一个非常不同的方法实现来确定套接字是否仍然连接

// .Connect throws an exception if unsuccessful
client.Connect(anEndPoint);

// This is how you can determine whether a socket is still connected.
bool blockingState = client.Blocking;
try
{
    byte [] tmp = new byte[1];

    client.Blocking = false;
    client.Send(tmp, 0, 0);
    Console.WriteLine("Connected!");
}
catch (SocketException e) 
{
    // 10035 == WSAEWOULDBLOCK
    if (e.NativeErrorCode.Equals(10035))
        Console.WriteLine("Still Connected, but the Send would block");
    else
    {
        Console.WriteLine("Disconnected: error code {0}!", e.NativeErrorCode);
    }
}
finally
{
    client.Blocking = blockingState;
}

Console.WriteLine("Connected: {0}", client.Connected);

问题是,如果发生超时,TcpClient就会断开连接。所以你的方法行不通。 使用异步读/写函数或使用select

异步函数调用最简单的方法如下:

byte[] data = new byte[4096];
IASyncResult result = stream.BeginRead(data, 0, data.Length, null, null);
result.AsyncWaitHandle.WaitOne(<timeout value in ms>);
int bytes = stream.EndRead(result);

if (!result.IsCompleted)
  <timed out>
else
  <read data>
...
byte[]data=新字节[4096];
IASyncResult result=stream.BeginRead(数据,0,数据.Length,null,null);
result.AsyncWaitHandle.WaitOne();
int bytes=stream.EndRead(结果);
如果(!result.IsCompleted)
其他的
...

我也有同样的行为。发送例程不会引发异常,并且Connected属性仍设置为false。以后的例行电话(发送/接收)按照galbarm回答描述的方式进行。恭维您的第一个回答!但这正是我试图避免的。对于使用非阻塞套接字,我将重构服务器逻辑并使每个网络操作异步,而不会产生额外的线程。“问题是,如果发生超时,TcpClient就会断开连接”:写入的位置?在stdc非阻塞套接字中,超时后(使用select实现)未断开连接。我发布的代码使用异步BeginRead/EndRead函数。但它会阻止使用WaitOne。因此,您不必更改服务器逻辑。BeginRead不会阻止你。WaitOne阻塞,直到有数据或发生指定的超时。使用!完成result.IsCompleted以检查它是否超时或是否有可用数据。我不知道在哪里写入“如果发生超时,TcpClient将断开连接”。但我也有同样的问题。如果读取通过超时返回,则Connected为False。我对此没有做太多的研究,只是接受了C#不打算设置一个超时值并定期运行这个超时。我同意。然而,一种更简单的方法是在处理网络通信时避免服务器线程上的连续循环,从而不再需要超时功能。但是,如果未收到任何字节,则在指定的超时后将退出WaitOne,但EndRead将阻塞,直到至少收到一个字节或连接关闭。