1

我有一个简单的 Java 程序,它充当服务器,监听 UDP 数据包。然后我有一个通过 3g 发送 UDP 数据包的客户端。

我注意到偶尔会出现以下情况:我发送了一个数据包,几秒钟后仍未收到。然后我发送另一个数据包,突然它们都到达了。

我想知道是否有可能存在某种系统来等待一定数量的数据,而不是发送一个尺寸过小的数据包。在我的应用程序中,我每个数据包只发送大约 2-3 个字节的数据 - 尽管 UDP 标头和其他什么不会使消息变大一点。

我的应用程序的目的是尽可能快地从 A 到 B 获取这几个字节的数据。非常强调速度。这一切只是巧合吗?我想我可以增加数据包的大小,但似乎传输时间会增加,而且 3g 并不完全完美。

4

2 回答 2

2

由于评论变得相当冗长,最好将它们完全变成答案。

如果您的应用在检索到一定数量之前没有接收数据,那么很有可能在幕后进行了某种缓冲。一个很好的例子(不是说这直接适用于您)是,如果您或底层库正在使用InputStream.readLine()or InputStream.read(bytes),那么它将阻塞,直到它收到一个换行符或bytes返回之前的字节数。从您的程序似乎在达到某个阈值时检索所有数据这一事实来看,听起来就是这样。

调试它的一个好方法是使用 Wireshark。Wireshark 不关心您的程序——它分析发送到您的计算机和从您的计算机发送的原始数据包,并且可以告诉您问题出在发送方还是接收方。

如果您使用 Wireshark 并看到第一次发送的数据在第二次发送之前到达您的物理机器,那么问题出在您的接收端。如果您看到第一个数据包与第二个数据包同时到达,那么问题出在发件人身上。没有看到代码,很难说你在做什么,具体来说,是什么导致数据仅在收到超过 2-3 个字节后才显示 - 但在那之前,这种行为准确地描述了你所看到的.

于 2012-05-13T05:26:15.747 回答
1

这有几个可能的原因:

  1. 蜂窝数据网络并非“永远在线”。根据底层技术,在发送第一个数据包和实际建立 IP 连接之间可能会有相当长的延迟。这将在 IP 网络空闲一段时间后最为明显。

  2. 您的接收器可能没有正确检查套接字的可读性。无论您使用什么高级 API,都需要在下面调用以select()检查套接字是否可读。当数据报到达时,select() 应该解除阻塞并发出套接字描述符可读的信号。或者,但效率较低,您可以将套接字设置为非阻塞并通过读取对其进行轮询。轮询会在没有数据时浪费 CPU 时间,并将到达检测延迟到轮询间隔,但如果由于某种原因您无法腾出一个线程等待,则它可能很有用select()

  3. 我在上面说过,select()当数据到达时,应该在被监视的套接字上发出可读性信号,但是这种行为可以通过套接字的“接收低水位标记”来修改。默认值通常为 1,这意味着任何数据都表示可读性。但如果SO_RCVLOWAT设置得更高(通过setsockopt()或更高级别的等效项),则在超过指定数量的数据到达之前不会发出可读性信号。getsockopt()您可以使用环境中等效的 API 或任何 API检查该值。

第 1 项将导致第一个数据报实际延迟,但仅在 IP 网络空闲一段时间而不是一旦它启动时才有效。第 2 项和第 3 项只会让您的程序认为第一个数据报被延迟:接收方的数据包嗅探器将显示第一个数据报按时到达。

于 2012-05-14T15:54:22.433 回答