TCP_NODELAY如何影响连续的write()调用?

5

TCP_NODELAY是一种选项,可以快速发送TCP数据包,无论它们的大小如何。这是在速度至关重要时非常有用的选项,但我想知道它对以下内容会产生什么影响:

Socket socket = [some socket];
socket.setTcpNoDelay(true);
OutputStream out = socket.getOutputStream();
out.write(byteArray1);
out.write(byteArray2);
out.write(byteArray3);
out.flush();

我尝试找到SocketOutputStream上flush操作的实际作用,但据我所知,它并没有做任何事情。我曾希望它能告诉套接字“立即发送所有缓冲数据”,但很不幸,它无法做到。
我的问题是:这三个字节数组会被一起发送吗?我知道您对TCP如何构建网络数据包没有太多控制权,但有没有办法告诉套接字(至少尝试)将这些字节数组打包在一起,以避免网络开销?手动打包字节数组并在一次调用中发送它们是否有所帮助?

4
"TCP_NODELAY在速度很重要的时候很有用。" 不是. 当响应能力很重要(尽快发送和接收字节)时,它非常有用。TCP_NODELAY可以通过相对低效地发送聚合数据来减少总体吞吐量。缓冲区很好:在任何时候和任何地方都要使用。依我之见... - paulsm4
2
建议:获取wireshark的副本,并跟踪实际发送的数据包,以测试几个套接字程序。 - paulsm4
是的,那就是我想表达的意思。;-) 我知道这样做效率低下,但在我的情况下,“响应能力”比等待足够的数据更重要。然而,对于这个问题,我想要优化它,因为发送单字节数组没有多大意义,重要的是它们所有内容的总和。 - AyCe
@AyCe:然后一次性发送所有数据。将它们组合起来需要额外的几微秒,这是假设缓冲区不小的情况下。与网络流量所需的时间相比,这点时间微不足道。 - cHao
@cHao 这是我目前的方法,但我想知道是否有更好的方法。搜索没有得到任何结果,所以我问了这个问题。 - AyCe
显示剩余6条评论
2个回答

8
我的问题是:这三个字节数组是否在一个数据包中发送?
由于您已禁用Nagle算法,几乎可以确定不是在同一个数据包内发送,但不能百分之百确定。
我知道您无法控制TCP如何构造网络数据包,但是否有办法告诉套接字(至少尝试)将这些字节数组打包?
是的。不要禁用Nagle算法。
这样可以避免网络开销吗?手动打包字节数组并在一次write调用中发送会有帮助吗?
是的,或者更简单地,只需在套接字输出流中包装一个BufferedOutputStream,在您想要发送数据时调用flush(),与您现有的代码相同。 您是正确的,flush()在套接字输出流上没有任何作用,但它会刷新BufferedOutputStream。

正如我已经在评论中所述,我的应用需要TCP_NODELAY功能,因此禁用不是我的选择。实际上,我已经使用了BufferedOutputStream来发送数据,这是否保证只有在调用flush()时才会发送数据呢? - AyCe
是的,如果BufferedOutputStream缓冲区足够大以容纳所有待处理数据(默认为8k),那么可以这样做。但是,如果您期望一次性接收所有数据,请再考虑一下。没有这样的保证。您仍然需要在接收方循环,直到获得所需的所有内容,或者如果您知道预期长度,则使用DataInputStream.readFully() - user207421
1
好的,很好!当然我知道我不能像使用UDP那样接收它作为“数据包”。所有这些字节数组都是单个消息,但只有在接收到它们中的最后一个时才有意义。因此,将它们作为单个数据包发送是毫无意义的。 - AyCe

2

手动打包字节数组并在一次写入中发送它们是否有帮助?

是的,将它们全部发送到一个write调用中。这将最大化你的字节被发送到一个数据包的机会。

当然,由于涉及太多变量 - 不同的操作系统和许多不同的网络设备,你永远无法知道,但如果你给操作系统打包所有内容的能力,它通常会尝试着一起发送。

如果你禁用了Nagle算法并进行单独的系统调用(记住,操作系统控制套接字,而不是你的应用程序或Java),那么你就要求操作系统单独发送它们。操作系统不知道你即将再次使用write调用来发送更多数据。


谢谢提供信息!我正在合并字节数据包,看起来效果不错。 - AyCe
如果您认为这个答案比其他答案更好地回答了您的问题,我会很感激您能够切换接受的答案。 - xaxxon
1
你的回答很好,你解释了操作系统/Java对套接字的分离,并且在回答我的主要问题时间接地回答了我的次要问题(即这三个字节数组是否可能在一个数据包中发送)。EJP也回答了两个问题,但还建议使用“BufferedOutputStream”,所以我觉得那个答案更完整 :) - AyCe
@AyCe 好的,没问题。 - xaxxon
你正在“请求”操作系统单独发送它们,但仍不能保证它会这样做。 - user207421

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接