我有一个简单的Java程序,它充当服务器,监听UDP数据包。然后我有一个客户端发送超过3g的UDP数据包。
我注意到的东西偶尔会出现以下情况:我发送一个数据包,几秒钟后仍然没有收到。然后我发送另一个数据包突然他们都到了。
我想知道是否有可能某种系统等待一定数量的数据而不是发送一个不足的数据包。在我的应用程序中,我每个数据包只发送大约2-3个字节的数据 - 虽然UDP标头和什么不会使消息大量增加。
我的应用程序的目标是尽可能快地从A到B获取这几个字节的数据。非常强调速度。这一切只是巧合吗?我想我可以增加数据包的大小,但似乎传输时间会增加,3g并不完美。
答案 0 :(得分:2)
由于评论相当冗长,最好将它们变成一个完整的答案。
如果您的应用在检索到某个数量之前没有接收数据,那么很可能在幕后进行某种缓冲。一个很好的例子(不是说这直接适用于您)是,如果您或基础库使用InputStream.readLine()
或InputStream.read(bytes)
,那么它将阻塞,直到它收到换行符或bytes
号码返回之前的字节数。从你的程序似乎在达到某个阈值时检索所有数据这一事实来看,听起来就是这种情况。
调试这个的好方法是使用Wireshark。 Wireshark不关心您的程序 - 它分析发送到您的计算机或从您的计算机发送的原始数据包,并可以告诉您该问题是发送者还是接收者。
如果您使用Wireshark并且看到第一次发送的数据在第二次发送之前到达您的物理计算机,则问题出在您的接收端。如果您看到第一个数据包与第二个数据包同时到达,则问题在于发送者。在没有看到代码的情况下,很难说你正在做什么以及什么,特别是导致数据仅在收到超过2-3个字节后才显示 - 但在此之前,这种行为准确描述了你所看到的
答案 1 :(得分:1)
有几个可能的原因:
移动数据网络不是“永远在线”。根据底层技术,在发送第一个数据包和实际建立IP连接之间可能存在很大的延迟。在IP网络空闲一段时间后,这将是最明显的。
您的接收器可能无法正确检查插座是否可读。无论您使用的是哪种高级API,都需要调用select()
来检查套接字是否可读。当数据报到达时,select()
应该解除阻塞并发出信号表明套接字描述符是可读的。或者,但效率较低,您可以将套接字设置为非阻塞并使用读取轮询它。轮询会在没有数据的情况下浪费CPU时间并延迟检测到达轮询间隔,但如果由于某种原因您无法在[{1}}上等待线程等待,则可能很有用。
我在上面说过select()
应该在数据到达时发出监视套接字的可读性信号,但是这种行为可以通过套接字的“接收低水位线”来修改。默认值通常为1,表示任何数据都表示可读性。但是,如果将select()
设置得更高(通过SO_RCVLOWAT
或更高级别的等效项),则在超过指定数量的数据到达之前,不会发出可读性信号。您可以使用setsockopt()
或您环境中的等效API检查值。
第1项会导致第一个数据报实际被延迟,但只有当IP网络空闲了一段时间而不是一旦它处于活动状态时。第2项和第3项只会让你的程序看到第一个数据报被延迟:接收器上的数据包嗅探器会显示第一个数据报准时到达。