【问题标题】:Why doesn't a zero-length Send() fail on a bad TCP socket connection?为什么零长度的 Send() 在 TCP 套接字连接错误时不会失败?
【发布时间】:2014-06-19 05:17:57
【问题描述】:

我正在尝试在 .NET 中编写一个非常简单的 TCP 服务器,它只为一个客户端处理一个连接,而我的挑战是检测半开连接。

根据这个无处不在的 MSDN 代码...

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

...我认为这样做的目的是发现任何现实世界的连接问题(例如拔掉远程客户端的网络电缆)并抛出所需的异常。

然而,我也明白发出 Send() 只会导致数据被放入套接字的底层发送缓冲区......所以很明显它不会仅仅因为出现问题而失败客户端。

我读到您需要执行后续 Receive() 才能实际获得零长度发送测试的结果。但是,我的服务器目前正在使用持续的 BeginReceive 方法,在这种方法中,一旦我真正接收到数据并对其进行处理,我就会启动 BeginSend(),然后发出另一个 BeginReceive()。

换句话说,在执行“MSDN 测试”时,我已经有一个有效的待处理接收。 不会以某种方式感知缺少 ACK 并发出错误信号吗?

谢谢

【问题讨论】:

  • 任何中间路由器都被允许丢弃这个数据包,因为它没有数据,所以我认为这个解决方案一般来说是不可靠的。也就是说,Send 成功完成后,client.Connected 的值是多少?
  • Stephen,拔掉对端网线,Send()返回成功后client.Connected的值为true。
  • 你从哪里读到这个关于后续接收的废话?它会收到什么?
  • 不幸的是我找不到链接,但无论如何,让我们暂时假设它是无稽之谈;那么我该如何避免半开连接问题呢?

标签: c# sockets tcp send


【解决方案1】:

证明连接仍然存在的软件明智的方法是向另一端发送消息,然后等待超时以获得响应。不只是建立了连接,而且对方通常都有响应。

与证明物理连接的方式没有什么不同

Google TCP/IP Heartbeat 以获得更多帮助。

【讨论】:

  • 所以...鉴于我的客户端是一个使用了数十年的硬件盒,它没有设置为响应心跳类型的消息,而是每半小时左右发送一次数据,我无法检测到半开连接?
  • 嗯,听起来你已经吃饱了,但我希望它有一些你可以使用的东西。状态请求或你在吗?,管理员登录,可以立即给你yeh/neh响应的东西
  • 我明白你在说什么,这是有道理的。谢谢
【解决方案2】:

使用 setsockopt 开启 TCP Keepalive。效果很好。

【讨论】:

    猜你喜欢
    • 2017-05-20
    • 1970-01-01
    • 2021-06-01
    • 2018-02-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-29
    相关资源
    最近更新 更多