I'm using Java DatagramSocket class to send a UDP data gram to an endpoint. The datagram must arrive at the endpoint in 60ms intervals.
我正在使用Java DatagramSocket类将UDP数据报文发送到端点。数据报必须以60ms的间隔到达端点。
I'm finding that DatagramSocket.Send can often take > 1 ms (close to 2) to package and send packets no greater than 56 bytes. This causes my packets to be delivered at 62 ms intervals, rather than 60ms intervals.
我发现DatagramSocket.Send通常需要> 1 ms(接近2)才能打包并发送不超过56个字节的数据包。这导致我的数据包以62 ms的间隔传送,而不是以60 ms的间隔传送。
This is on a windows vista machine. Here is how I'm measuring the time:
这是在Windows Vista机器上。以下是我测量时间的方法:
DatagramPacket d = new DatagramPacket(out, out.length, address, port);
long nanoTime = System.nanoTime();
socket.send(d);
long diff = System.nanoTime() - nanoTime;
System.out.println( out.length + " in " + diff + "ms." );
Does any one have tips or tricks to speed this process?
有没有人有提示或技巧来加速这个过程?
9 个解决方案
#1
You can use the Timer class to schedule an event.
您可以使用Timer类来安排事件。
Timer timer = new Timer();
TimerTask task = new TimerTask() {
public void run() {
//send packet here
}};
timer.scheduleAtFixedRate(task, 0, 60);
This will create a recurring event every 60ms to execute the "run" command. All things remaining equal, the packet should hit the wire every 60ms (although, the first packet will be delayed by some amount, and garbage collection/other tasks/etc may slightly delay this number).
这将每60ms创建一个重复发生的事件来执行“run”命令。在所有事情保持相同的情况下,数据包应该每60分钟接通一次(虽然,第一个数据包将被延迟一些数量,垃圾收集/其他任务/等可能会稍微延迟这个数字)。
#2
You're seeing the time taken to copy the data from user-space into kernel space. It takes even longer to send through the UDP, IP and Ethernet layers and it can take a variable amount of time for a datagram to cross the physical network to its destination.
您将看到将数据从用户空间复制到内核空间所花费的时间。通过UDP,IP和以太网层发送需要更长的时间,数据报跨越物理网络到达目的地可能需要不同的时间。
Assuming you have a network that exhibits no jitter (variance in per-packet transmission time) and your process is running at real-time priority, and nothing else is competing with it for the CPU...
假设您的网络没有抖动(每个数据包传输时间的差异)并且您的进程以实时优先级运行,并且没有其他任何东西与CPU竞争...
You need to call send every 60ms, no matter how long it takes for the send() method to execute. You cannot wait 60ms between calls. You need to measure how long it takes to perform the body of your loop (send() and whatever else) and subtract that from 60ms to get the wait time.
无论send()方法执行多长时间,您都需要每60ms调用一次send。你不能在两次通话之间等待60ms。您需要测量执行循环体(send()和其他任何东西)所需的时间,并从60ms中减去它以获得等待时间。
#3
Use a Timer, as mentioned by James Van Huis. That way, you will at least get the average frequency correct.
使用James Van Huis提到的计时器。这样,您至少可以获得正确的平均频率。
Quote from the javadoc :
引用来自javadoc:
If an execution is delayed for any reason (such as garbage collection or other background activity), two or more executions will occur in rapid succession to "catch up." In the long run, the frequency of execution will be exactly the reciprocal of the specified period (assuming the system clock underlying Object.wait(long) is accurate).
如果由于任何原因(例如垃圾收集或其他后台活动)延迟执行,则会快速连续执行两次或更多次执行以“赶上”。从长远来看,执行的频率将恰好是指定周期的倒数(假设Object.wait(long)下的系统时钟是准确的)。
Also, to answer your actual, but perhaps slightly misguided question: reusing an instance DatagramPacket and just setting a new output buffer shaves of a "massive" microsecond in average, on my machine...
另外,要回答你的实际问题,但也许是一个有点误导的问题:在我的机器上重用一个实例DatagramPacket并且只设置一个平均“大”微秒的新输出缓冲区...
datagram.setData(out);
socket.send(datagram);
It reduces the load on the gc slightly so it might be a good idea if you are sending at a high rate.
它会略微降低gc的负载,因此如果您以高速率发送它可能是一个好主意。
#4
Besides for the obvious and smart-allecky response of "wait only 59 ms," there isn't a whole lot you can actually do. Any operation you take is going to take some amount of time which is not likely to be consistent. As such, there is no way to guarantee that your packets will be delivered at precisely 60 ms intervals.
除了为明显的和智能响应allecky“只等待59毫秒,”没有一大堆,你实际上可以做。您采取的任何操作都将花费一些时间,这可能不一致。因此,无法保证您的数据包将以精确的60 ms间隔传送。
Remember that it takes time to wrap your tiny little 56 byte message in the headers needed for the UDP and IP layers and still more time to shunt it out to your network card and send it on its way. This adds another 8 bytes for the UDP layer, 20 for the IP layer, and still more for whatever the link layer needs. There is nothing you can do to avoid this.
请记住,在UDP和IP层所需的标头中包含微小的56字节消息需要花费时间,并且还有更多时间将其分流到网卡并在途中发送。这为UDP层增加了8个字节,为IP层增加了20个字节,而对于链路层需要的更多内容则更多。你无能为力避免这种情况。
Also, since you are using UDP, there is no way that you can guarantee that your packets actually arrive, or if they do that they arrive in order. TCP can make these guarantees, but neither can guarantee that they will actually arrive on time. In particular, network congestion may slow down your data en route to the destination, causing it to be late, even compared to the rest of your data. Thus, it is unreasonable to try to use a remote application to control another at precise intervals. You should consider yourself lucky if your signals actually arrive within 2 ms of when you want it to.
此外,由于您使用的是UDP,因此您无法保证数据包实际到达,或者如果他们这样做,则无法按顺序到达。 TCP可以做出这些保证,但两者都不能保证它们能够按时到达。特别是,网络拥塞可能会降低到达目的地的数据速度,导致数据延迟,甚至与其他数据相比也是如此。因此,尝试使用远程应用程序以精确的间隔控制另一个应用程序是不合理的。如果您的信号实际上在您想要的2毫秒内到达,您应该认为自己很幸运。
#5
I had the same problem as you. I found the solution. To make a long story short, here it is:
我遇到了和你一样的问题。我找到了解决方案。长话短说,这里是:
Look for the Java class ScheduledThreadPoolExecutor
, it is in the Java 5 JDK/JRE. (i can post only one link as i just found out otherwise i would have pointed to the Oracle JavaDoc)
查找Java类ScheduledThreadPoolExecutor,它位于Java 5 JDK / JRE中。 (我只能发布一个链接,因为我刚刚发现,否则我会指向Oracle JavaDoc)
ScheduledThreadPoolExecutor schedThPoolExec = new ScheduledThreadPoolExecutor(1);
/*
*
* cue a byte buffer for sending in equal segments on the udp port with a inter-pkt-delay
*
*/
public void send(byte[] data, String destinationHost, int destinationPort, double interPacketDelayMs) {
long interDelayNanos = (long) ( interPacketDelayMs * 1000000.0 );
schedThPoolExec.scheduleAtFixedRate( new SendPacketsTimerTask(data, destinationHost, destinationPort), 0, interDelayNanos , TimeUnit.NANOSECONDS);
}
/*
*
*
*
*/
class SendPacketsTimerTask implements Runnable {
int offset = 0;
byte[] buffer;
String host;
int port;
public SendPacketsTimerTask(byte[] buffer, String destinationHost, int destinationPort) {
this.buffer = buffer;
host = destinationHost;
port = destinationPort;
}
@Override
public void run() {
if(offset + PKT_SIZE < buffer.length) {
//copy from cue to packet
byte[] tmp_pkt_buffer = new byte[PKT_SIZE];
System.arraycopy(buffer, offset, tmp_pkt_buffer, 0, PKT_SIZE);
try {
//send packet
socket.send( new DatagramPacket(tmp_pkt_buffer, tmp_pkt_buffer.length, InetAddress.getByName(host), port) );
//increment offset
offset += tmp_pkt_buffer.length;
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
Along with the TimerTask
class (as already mentioned above) you can schedule an event periodicaly. Now you just need to write the TimerTask that will send your messages, or as in my case a buffer of data.
与TimerTask类(如上所述)一起,您可以定期安排事件。现在您只需编写将发送消息的TimerTask,或者在我的情况下编写数据缓冲区。
My problem was actualy that i am handling real time media streams and that i need a throughputs of 15 Mbits+ (video data). So that brings you to inter-packet-delays of 0.5 ms. So the granularity of the Thread.sleep
method (which takes nano-seconds arguments true, but has miliseconds granularity nevertheless - true also ). So I was stuck with 6 mbit sending rate. When i checked out the Timer
class i thought i found my solution. Finaly finding out this class was not handling my low execution periods either. Searching for people having similar problems i found this article which was very helpful. Instead of the Timer
class you can use the above mentioned thread scheduler class which is accordingly binded to native code using your full system performance to run the send method periodicaly with the highest resolution possible.
我的问题是我正在处理实时媒体流,我需要15 Mbits +(视频数据)的吞吐量。这样就可以实现0.5 ms的数据包间延迟。所以Thread.sleep方法的粒度(纳米秒参数为真,但仍具有毫秒粒度 - 也是如此)。所以我坚持使用6 mbit的发送速率。当我查看Timer类时,我以为我找到了我的解决方案。最终发现这个课程并没有处理我的低执行期。搜索有类似问题的人我发现这篇文章非常有帮助。您可以使用上面提到的线程调度程序类代替Timer类,该类相应地使用您的完整系统性能绑定到本机代码,以尽可能高的分辨率定期运行send方法。
Note: The general meaning (also at my employer) Java would be "too slow" , "have imprecise timings") to do timing critical applications and high network data throughput is finaly averred as WRONG. It WAS TRUE. Finaly with Java 5 we can achieve full possible timing capabilities and thus application performance :)
注意:一般意义(也在我的雇主)Java将“太慢”,“有不精确的时间”)来做关键时序应用程序和高网络数据吞吐量最终被认为是错误的。这是正确的。最后使用Java 5,我们可以实现完全可能的计时功能,从而实现应用程序性能:)
#6
If you send the packets out in 60ms intervals then theoretically the packets would arrive in 60ms intervals at the destination, however this is not guaranteed. Once the packets hit the link they become the mercy of the network link which could include network traffic and even dropping your packets along the routed path.
如果以60ms的间隔发送数据包,理论上数据包将在目的地以60ms的间隔到达,但这不能保证。一旦数据包到达链路,它们就会成为网络链路的怜悯,这可能包括网络流量,甚至会丢弃沿着路由路径的数据包。
Is there a reason the packets must be received exactly 60ms apart? If so, there are other protocols that could help you achieve this.
是否有必要在相隔60ms的时间内接收数据包?如果是这样,还有其他协议可以帮助您实现这一目标。
#7
How about sending your packets at 58 millisecond intervals?
如何以58毫秒的间隔发送数据包?
No matter how you optimize (and there really aren't any opportunities to do so; using the channel-orient NIO will do the same work), some time will be required to send data, and there is likely to be some variability there. If precise timing is required, some strategy that acknowledges the transmission time is required.
无论你如何优化(并且确实没有任何机会这样做;使用面向渠道的NIO将做同样的工作),需要一些时间来发送数据,并且可能存在一些可变性。如果需要精确定时,则需要一些确认传输时间的策略。
Also, a note about the measurement: be sure not to measure the delay until several thousand iterations have been performed. This gives a the optimizer a chance to do its work and give a more representative timing.
另外,关于测量的注意事项:确保在几千次迭代完成之前不测量延迟。这使优化器有机会完成其工作并提供更具代表性的时序。
At one time, the time resolution on Windows was poor. However, 1 millisecond resolution is now common. Try the following test to see what how precise your machine is.
有一次,Windows上的时间分辨率很差。但是,1毫秒的分辨率现在很常见。尝试以下测试,了解您的机器有多精确。
public static void main(String... argv)
throws InterruptedException
{
final int COUNT = 1000;
long time = System.nanoTime();
for (int i = 0; i < COUNT; ++i) {
Thread.sleep(57);
}
time = System.nanoTime() - time;
System.out.println("Average wait: " + (time / (COUNT * 1000000F)) + " ms");
}
On my Windows XP machine, the average wait time is 57.7 ms.
在我的Windows XP计算机上,平均等待时间为57.7毫秒。
#8
Since you are not using a Real Time Java there is no way make sure you will always send a packet every 60ms. I would set up a timer thread that will do a 'notify' on two other waiting threads that actually send the packet. You could get by with only one thread to send but I am sort of anal about having a backup in case there is a problem.
由于您没有使用实时Java,因此无法确保每隔60ms始终发送一个数据包。我会设置一个计时器线程,它将对另外两个实际发送数据包的等待线程进行“通知”。你可以只用一个线程发送,但我有点肛门有备份,以防出现问题。
#9
You are measuring nanoTime, so it will give you nano seconds instead of milli seconds.
你正在测量nanoTime,所以它会给你纳秒秒而不是毫秒。
long diff = System.nanoTime() - nanoTime; System.out.println( out.length + " in " + diff + "ms." );
long diff = System.nanoTime() - nanoTime; System.out.println(out.length +“in”+ diff +“ms。”);
#1
You can use the Timer class to schedule an event.
您可以使用Timer类来安排事件。
Timer timer = new Timer();
TimerTask task = new TimerTask() {
public void run() {
//send packet here
}};
timer.scheduleAtFixedRate(task, 0, 60);
This will create a recurring event every 60ms to execute the "run" command. All things remaining equal, the packet should hit the wire every 60ms (although, the first packet will be delayed by some amount, and garbage collection/other tasks/etc may slightly delay this number).
这将每60ms创建一个重复发生的事件来执行“run”命令。在所有事情保持相同的情况下,数据包应该每60分钟接通一次(虽然,第一个数据包将被延迟一些数量,垃圾收集/其他任务/等可能会稍微延迟这个数字)。
#2
You're seeing the time taken to copy the data from user-space into kernel space. It takes even longer to send through the UDP, IP and Ethernet layers and it can take a variable amount of time for a datagram to cross the physical network to its destination.
您将看到将数据从用户空间复制到内核空间所花费的时间。通过UDP,IP和以太网层发送需要更长的时间,数据报跨越物理网络到达目的地可能需要不同的时间。
Assuming you have a network that exhibits no jitter (variance in per-packet transmission time) and your process is running at real-time priority, and nothing else is competing with it for the CPU...
假设您的网络没有抖动(每个数据包传输时间的差异)并且您的进程以实时优先级运行,并且没有其他任何东西与CPU竞争...
You need to call send every 60ms, no matter how long it takes for the send() method to execute. You cannot wait 60ms between calls. You need to measure how long it takes to perform the body of your loop (send() and whatever else) and subtract that from 60ms to get the wait time.
无论send()方法执行多长时间,您都需要每60ms调用一次send。你不能在两次通话之间等待60ms。您需要测量执行循环体(send()和其他任何东西)所需的时间,并从60ms中减去它以获得等待时间。
#3
Use a Timer, as mentioned by James Van Huis. That way, you will at least get the average frequency correct.
使用James Van Huis提到的计时器。这样,您至少可以获得正确的平均频率。
Quote from the javadoc :
引用来自javadoc:
If an execution is delayed for any reason (such as garbage collection or other background activity), two or more executions will occur in rapid succession to "catch up." In the long run, the frequency of execution will be exactly the reciprocal of the specified period (assuming the system clock underlying Object.wait(long) is accurate).
如果由于任何原因(例如垃圾收集或其他后台活动)延迟执行,则会快速连续执行两次或更多次执行以“赶上”。从长远来看,执行的频率将恰好是指定周期的倒数(假设Object.wait(long)下的系统时钟是准确的)。
Also, to answer your actual, but perhaps slightly misguided question: reusing an instance DatagramPacket and just setting a new output buffer shaves of a "massive" microsecond in average, on my machine...
另外,要回答你的实际问题,但也许是一个有点误导的问题:在我的机器上重用一个实例DatagramPacket并且只设置一个平均“大”微秒的新输出缓冲区...
datagram.setData(out);
socket.send(datagram);
It reduces the load on the gc slightly so it might be a good idea if you are sending at a high rate.
它会略微降低gc的负载,因此如果您以高速率发送它可能是一个好主意。
#4
Besides for the obvious and smart-allecky response of "wait only 59 ms," there isn't a whole lot you can actually do. Any operation you take is going to take some amount of time which is not likely to be consistent. As such, there is no way to guarantee that your packets will be delivered at precisely 60 ms intervals.
除了为明显的和智能响应allecky“只等待59毫秒,”没有一大堆,你实际上可以做。您采取的任何操作都将花费一些时间,这可能不一致。因此,无法保证您的数据包将以精确的60 ms间隔传送。
Remember that it takes time to wrap your tiny little 56 byte message in the headers needed for the UDP and IP layers and still more time to shunt it out to your network card and send it on its way. This adds another 8 bytes for the UDP layer, 20 for the IP layer, and still more for whatever the link layer needs. There is nothing you can do to avoid this.
请记住,在UDP和IP层所需的标头中包含微小的56字节消息需要花费时间,并且还有更多时间将其分流到网卡并在途中发送。这为UDP层增加了8个字节,为IP层增加了20个字节,而对于链路层需要的更多内容则更多。你无能为力避免这种情况。
Also, since you are using UDP, there is no way that you can guarantee that your packets actually arrive, or if they do that they arrive in order. TCP can make these guarantees, but neither can guarantee that they will actually arrive on time. In particular, network congestion may slow down your data en route to the destination, causing it to be late, even compared to the rest of your data. Thus, it is unreasonable to try to use a remote application to control another at precise intervals. You should consider yourself lucky if your signals actually arrive within 2 ms of when you want it to.
此外,由于您使用的是UDP,因此您无法保证数据包实际到达,或者如果他们这样做,则无法按顺序到达。 TCP可以做出这些保证,但两者都不能保证它们能够按时到达。特别是,网络拥塞可能会降低到达目的地的数据速度,导致数据延迟,甚至与其他数据相比也是如此。因此,尝试使用远程应用程序以精确的间隔控制另一个应用程序是不合理的。如果您的信号实际上在您想要的2毫秒内到达,您应该认为自己很幸运。
#5
I had the same problem as you. I found the solution. To make a long story short, here it is:
我遇到了和你一样的问题。我找到了解决方案。长话短说,这里是:
Look for the Java class ScheduledThreadPoolExecutor
, it is in the Java 5 JDK/JRE. (i can post only one link as i just found out otherwise i would have pointed to the Oracle JavaDoc)
查找Java类ScheduledThreadPoolExecutor,它位于Java 5 JDK / JRE中。 (我只能发布一个链接,因为我刚刚发现,否则我会指向Oracle JavaDoc)
ScheduledThreadPoolExecutor schedThPoolExec = new ScheduledThreadPoolExecutor(1);
/*
*
* cue a byte buffer for sending in equal segments on the udp port with a inter-pkt-delay
*
*/
public void send(byte[] data, String destinationHost, int destinationPort, double interPacketDelayMs) {
long interDelayNanos = (long) ( interPacketDelayMs * 1000000.0 );
schedThPoolExec.scheduleAtFixedRate( new SendPacketsTimerTask(data, destinationHost, destinationPort), 0, interDelayNanos , TimeUnit.NANOSECONDS);
}
/*
*
*
*
*/
class SendPacketsTimerTask implements Runnable {
int offset = 0;
byte[] buffer;
String host;
int port;
public SendPacketsTimerTask(byte[] buffer, String destinationHost, int destinationPort) {
this.buffer = buffer;
host = destinationHost;
port = destinationPort;
}
@Override
public void run() {
if(offset + PKT_SIZE < buffer.length) {
//copy from cue to packet
byte[] tmp_pkt_buffer = new byte[PKT_SIZE];
System.arraycopy(buffer, offset, tmp_pkt_buffer, 0, PKT_SIZE);
try {
//send packet
socket.send( new DatagramPacket(tmp_pkt_buffer, tmp_pkt_buffer.length, InetAddress.getByName(host), port) );
//increment offset
offset += tmp_pkt_buffer.length;
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
Along with the TimerTask
class (as already mentioned above) you can schedule an event periodicaly. Now you just need to write the TimerTask that will send your messages, or as in my case a buffer of data.
与TimerTask类(如上所述)一起,您可以定期安排事件。现在您只需编写将发送消息的TimerTask,或者在我的情况下编写数据缓冲区。
My problem was actualy that i am handling real time media streams and that i need a throughputs of 15 Mbits+ (video data). So that brings you to inter-packet-delays of 0.5 ms. So the granularity of the Thread.sleep
method (which takes nano-seconds arguments true, but has miliseconds granularity nevertheless - true also ). So I was stuck with 6 mbit sending rate. When i checked out the Timer
class i thought i found my solution. Finaly finding out this class was not handling my low execution periods either. Searching for people having similar problems i found this article which was very helpful. Instead of the Timer
class you can use the above mentioned thread scheduler class which is accordingly binded to native code using your full system performance to run the send method periodicaly with the highest resolution possible.
我的问题是我正在处理实时媒体流,我需要15 Mbits +(视频数据)的吞吐量。这样就可以实现0.5 ms的数据包间延迟。所以Thread.sleep方法的粒度(纳米秒参数为真,但仍具有毫秒粒度 - 也是如此)。所以我坚持使用6 mbit的发送速率。当我查看Timer类时,我以为我找到了我的解决方案。最终发现这个课程并没有处理我的低执行期。搜索有类似问题的人我发现这篇文章非常有帮助。您可以使用上面提到的线程调度程序类代替Timer类,该类相应地使用您的完整系统性能绑定到本机代码,以尽可能高的分辨率定期运行send方法。
Note: The general meaning (also at my employer) Java would be "too slow" , "have imprecise timings") to do timing critical applications and high network data throughput is finaly averred as WRONG. It WAS TRUE. Finaly with Java 5 we can achieve full possible timing capabilities and thus application performance :)
注意:一般意义(也在我的雇主)Java将“太慢”,“有不精确的时间”)来做关键时序应用程序和高网络数据吞吐量最终被认为是错误的。这是正确的。最后使用Java 5,我们可以实现完全可能的计时功能,从而实现应用程序性能:)
#6
If you send the packets out in 60ms intervals then theoretically the packets would arrive in 60ms intervals at the destination, however this is not guaranteed. Once the packets hit the link they become the mercy of the network link which could include network traffic and even dropping your packets along the routed path.
如果以60ms的间隔发送数据包,理论上数据包将在目的地以60ms的间隔到达,但这不能保证。一旦数据包到达链路,它们就会成为网络链路的怜悯,这可能包括网络流量,甚至会丢弃沿着路由路径的数据包。
Is there a reason the packets must be received exactly 60ms apart? If so, there are other protocols that could help you achieve this.
是否有必要在相隔60ms的时间内接收数据包?如果是这样,还有其他协议可以帮助您实现这一目标。
#7
How about sending your packets at 58 millisecond intervals?
如何以58毫秒的间隔发送数据包?
No matter how you optimize (and there really aren't any opportunities to do so; using the channel-orient NIO will do the same work), some time will be required to send data, and there is likely to be some variability there. If precise timing is required, some strategy that acknowledges the transmission time is required.
无论你如何优化(并且确实没有任何机会这样做;使用面向渠道的NIO将做同样的工作),需要一些时间来发送数据,并且可能存在一些可变性。如果需要精确定时,则需要一些确认传输时间的策略。
Also, a note about the measurement: be sure not to measure the delay until several thousand iterations have been performed. This gives a the optimizer a chance to do its work and give a more representative timing.
另外,关于测量的注意事项:确保在几千次迭代完成之前不测量延迟。这使优化器有机会完成其工作并提供更具代表性的时序。
At one time, the time resolution on Windows was poor. However, 1 millisecond resolution is now common. Try the following test to see what how precise your machine is.
有一次,Windows上的时间分辨率很差。但是,1毫秒的分辨率现在很常见。尝试以下测试,了解您的机器有多精确。
public static void main(String... argv)
throws InterruptedException
{
final int COUNT = 1000;
long time = System.nanoTime();
for (int i = 0; i < COUNT; ++i) {
Thread.sleep(57);
}
time = System.nanoTime() - time;
System.out.println("Average wait: " + (time / (COUNT * 1000000F)) + " ms");
}
On my Windows XP machine, the average wait time is 57.7 ms.
在我的Windows XP计算机上,平均等待时间为57.7毫秒。
#8
Since you are not using a Real Time Java there is no way make sure you will always send a packet every 60ms. I would set up a timer thread that will do a 'notify' on two other waiting threads that actually send the packet. You could get by with only one thread to send but I am sort of anal about having a backup in case there is a problem.
由于您没有使用实时Java,因此无法确保每隔60ms始终发送一个数据包。我会设置一个计时器线程,它将对另外两个实际发送数据包的等待线程进行“通知”。你可以只用一个线程发送,但我有点肛门有备份,以防出现问题。
#9
You are measuring nanoTime, so it will give you nano seconds instead of milli seconds.
你正在测量nanoTime,所以它会给你纳秒秒而不是毫秒。
long diff = System.nanoTime() - nanoTime; System.out.println( out.length + " in " + diff + "ms." );
long diff = System.nanoTime() - nanoTime; System.out.println(out.length +“in”+ diff +“ms。”);