<p>回答我自己的问题。。。在</p>
<p>简单的回答是,仅使用TCP,客户机无法知道目标接收者是否真的收到了发送的字节。在</p>
<p>ie:客户端是否“高兴地”发送了字节并不重要。。。即使使用TCP,它们也可能永远不会到达,而且您肯定不知道它们何时到达预期的接收者。无论如何,如果不在应用程序层中构建一些确认,就不可能了。在</p>
<p>对于我的特殊情况,客户机发送的字节确实到达了服务器,但用了~30秒(!!!)此时客户端和服务器应用程序协议代码都已超时。在</p>
<p>客户端和服务器端日志(对于一个失败的连接)的视图如下:</p>
<ul>
<li><a href="http://static.inky.ws/image/1826/4f91b8a3733a8/image.jpg" rel="nofollow noreferrer">Client side TCP log</a></li>
<li><a href="http://static.inky.ws/image/1825/4f91b8a3733a8/image.jpg" rel="nofollow noreferrer">Server side TCP log</a></li>
</ul>
<p>这些图像是<a href="http://www.tcpdump.org/" rel="nofollow noreferrer">tcpdump</a>捕获文件中一个特定TCP流的<a href="http://www.wireshark.org/" rel="nofollow noreferrer">wireshark</a>视图。你可以看到发生了大量的重传。驱动这些重新传输的根本原因是什么?我完全不知道(但很想知道!)。在</p>
<p>数据在最后第2个条目(#974)到达服务器,大约在发送后30秒,其间有大量的重新传输尝试。如果对服务器端的#793感到好奇,这是我的应用层协议尝试向客户端发送一条消息,说“等待更多数据超时。。。它在哪里?”。在</p>
<p>除了固有的延迟之外,数据没有出现在服务器上的<code>tcpdump</code>日志中的原因之一似乎也是我对<code>tcpdump</code>的使用。简而言之:在查看捕获文件(使用<code>-w</code>开关创建的)之前,请确保在<code>tcpdump</code>捕获中退出Ctrl-C,因为它似乎会对您在文件中看到的内容产生很大的影响。我想这是一个刷新/同步问题,但我在猜测。但是,如果没有Ctrl-C,我肯定会丢失数据。在</p>
<p><strong>更多详细信息供将来参考…</strong></p>
<p>尽管您经常读到/听到TCP将:</p>
<ol>
<li>保证您的数据包会到达(vs<a href="http://en.wikipedia.org/wiki/User_Datagram_Protocol" rel="nofollow noreferrer">UDP</a>,但不会)</li>
<li>保证你的包裹会按顺序到达</li>
</ol>
<p>显然,第一个事实上根本不是真的。TCP将尽最大努力将您的字节发送给目标接收者(包括长时间重试),但这并不能保证,<a href="http://linux.die.net/man/2/send" rel="nofollow noreferrer">send man page</a>是否为<code>send</code>返回值指明“一旦成功,这些调用将返回发送的字符数”。后者是<em>而不是</em>是真的,具有高度误导性(见下文)。在</p>
<p>其根源主要来自于各种套接字调用(尤其是<code>send</code>)的行为方式以及它们如何与操作系统的TCP/IP堆栈交互。。。在</p>
<p>在TCP交换的发送端,进程非常简单。首先你<code>connect()</code>,然后你<code>send()</code>。在</p>
<p><code>connect()</code>成功返回肯定意味着您能够建立到服务器的连接,因此您至少知道此时服务器在那里并且正在侦听(即:三部分的TCP打开握手是成功的)。在</p>
<p>对于'send',虽然调用的文档指出返回值(如果为正)是“发送的[bytes]个数”,但这完全是错误的。返回值告诉您的只是底层操作系统中的TCP堆栈接受到其传出缓冲区的字节数。在这之后,操作系统将尽力将这些字节传递给您最初建立连接的接收者。但这可能永远不会发生,所以这并不意味着你可以指望那些被发送的字节!有些令人惊讶的是,甚至没有真正的方法来确定这是否发生了(或没有!)至少在TCP套接字层,即使TCP已经内置了ACK消息。要验证发送字节的完整接收,需要添加某种应用层的确认。nos在另一个问题中有一个关于这个的问题。在</p>
<p><strong>附录…</strong></p>
<p>我在这里留下的一个有趣的难题是,我是否需要在应用层协议中构建一些重试功能。目前看来,在服务器等待数据超时的情况下,关闭连接并用相同的请求打开一个新的连接是有益的。这似乎是因为低级TCP重试没有成功,但同时还有其他客户端线程及时通过。不过,这感觉非常错误。。。您可能认为TCP重试应该足够了。但事实并非如此。我需要找出TCP问题的根本原因来解决这个问题。在</p>