基本本地错误发送
我有一个是在发送多个线程使用DatagramChannel.send包的应用程序的每个到它自己的IP地址/端口和每个人的保持恒定比特率/带宽。时不时地,我得到这个错误:
java.net.SocketException: Invalid argument: no further information
at sun.nio.ch.DatagramChannelImpl.send0(Native Method)
at sun.nio.ch.DatagramChannelImpl.sendFromNativeBuffer(Unknown Source)
at sun.nio.ch.DatagramChannelImpl.send(Unknown Source)
at sun.nio.ch.DatagramChannelImpl.send(Unknown Source)
...
它发生在随机的 - 有时5分钟,一天后,有时启动之后 - 所以我真的有问题重现它进行测试。而在我的家用机器上,我根本无法复制它。
环境
- 的Windows 7,第8和Server 2012中(全部64位)
- 64位的Java 7更新45
更多信息
的应用正在发送SI/EIT数据到DVB-C网络。我为每个80-120个线程创建一个188字节的数组列表并给它使用。线程获取列表并循环遍历列表,直到提供新列表。
- 该错误通常发生在多个通道上。但它也可能发生在一个人身上。
- 直到我们有40多个线程时,才会发生错误。
- 循环遍历列表时发生错误,而不是当我将新列表绑定到线程时。
- 该应用程序没有用完内存。它通常运行高达JVM内存的70%。
- 奇怪的部分:如果我运行多个应用程序的每个实例〜10个线程的问题是相同的。
简化代码示例
for(int i = 0; i < 100; ++i) {
final int id = i;
new Thread(new Runnable() {
@Override
public void run() {
final Random r = new Random();
final List<byte[]> buffer = Lists.newArrayList();
for(int i = 0; i < 200; ++i) {
final byte[] temp = new byte[188];
r.nextBytes(temp);
buffer.add(temp);
}
final SocketAddress target = new InetSocketAddress("230.0.0.18", 1000 + id);
try (final DatagramChannel channel = DatagramChannel.open(StandardProtocolFamily.INET)) {
channel.configureBlocking(false);
channel.setOption(StandardSocketOptions.IP_MULTICAST_IF, NetworkInterface.getByName("eth0"));
channel.setOption(StandardSocketOptions.IP_MULTICAST_TTL, 8);
channel.setOption(StandardSocketOptions.SO_REUSEADDR, true);
channel.setOption(StandardSocketOptions.SO_SNDBUF, 1024 * 64);
int counter = 0;
int index = 0;
while(true) {
final byte[] item = buffer.get(index);
channel.send(ByteBuffer.wrap(item), target);
index = (index + 1) % buffer.size();
counter++;
Thread.sleep(1);
}
}
catch(Exception e) {
LOG.error("Fail at " + id, e);
}
}
}).start();
}
编辑:
1)@EJP:我设置设置多播特性,我使用的实际应用正在做联接(并阅读一些数据)。但即使我将它们删除后问题仍然存在。
2)如果我只需要发送UDP数据包,我应该使用其他的API吗?我可以找到的所有示例都使用DatagramChannel(或更早的替代方法)。
3)我仍然坚持这一点。如果任何人有一个想法,我甚至可以尝试,请让我知道。
为什么你在没有进行任何连接时设置多播属性? – EJP
你可以试试MulticastSocket。你不应该像这样使用非阻塞模式。在OP_WRITE上选择,而不是睡觉。 – EJP