Java 当消息大小较大时,socketchannel.write()会变得非常慢
在我使用java nio的程序中,socketchannel.write()在尝试连续写入10 KB消息时变得非常慢。测得的写入完整10 KB消息的时间介于160 ms和200 ms之间。但写入完整5 KB消息的时间仅为0.8 ms 在选择器中,我只读取Selection.OP_,不处理Selection.OP_写入。当收到一条完整的大消息时,它会被写入另一个接收器4次 有人也有同样的问题吗?有一篇关于socketchannel.write()慢的帖子。我的问题是如何在读操作和写操作之间交替切换 如果我添加一个惯性值,例如150毫秒,响应时间就会缩短。有没有办法找到缓冲区已满的时间,以便让程序等待。我的操作系统是windows xp 谢谢 我遵循EPJ的建议,检查写入的字节数。但响应时间仍然很长。我在这里发布了我的部分代码,并想检查我的代码是否有错误 //这是使用nio的writeData()部分:Java 当消息大小较大时,socketchannel.write()会变得非常慢,java,nio,socketchannel,Java,Nio,Socketchannel,在我使用java nio的程序中,socketchannel.write()在尝试连续写入10 KB消息时变得非常慢。测得的写入完整10 KB消息的时间介于160 ms和200 ms之间。但写入完整5 KB消息的时间仅为0.8 ms 在选择器中,我只读取Selection.OP_,不处理Selection.OP_写入。当收到一条完整的大消息时,它会被写入另一个接收器4次 有人也有同样的问题吗?有一篇关于socketchannel.write()慢的帖子。我的问题是如何在读操作和写操作之间交替切换
while (buffer.hasRemaining()) {
try {
buffer.flip();
n = socket.write(buffer);
if(n == 0) {
key.interestOps(SelectionKey.OP_WRITE);
key.attach(buffer);
break;
}
} catch (IOException e) {
e.printStackTrace();
} finally {
buffer.compact();
}
}
if(buffer.position()==0) {
key.interestOps(SelectionKey.OP_READ);
}
如果写入时间超过20微秒,我建议您存在缓冲区已满问题。我假设您正在使用阻塞NIO。当发送缓冲区未满时,通常需要5-20微秒。在过去,我已经将我的服务器配置为杀死任何需要2ms写入的慢速消费者。(可能有点咄咄逼人。) 您可以尝试增加发送缓冲区的大小(Socket.setSendBufferSize(int),它也可用于SocketChannels),但似乎您正在尝试发送超出带宽允许的数据
10 KB不是一个大消息,典型的发送缓冲区大小是64 KB,因此要使其满,您需要有6-7条消息未发送。这可能解释了5KB的方式相对较快。我建议您的读取过程较慢,这会导致其接收缓冲区备份,这会导致发送缓冲区备份,从而导致发送暂停 或者您没有为非阻塞模式正确编写代码。如果write()方法的结果为零,则必须(a)将interesttops更改为OP_write,并(b)返回select循环。当你得到OP_WRITE时,你必须重复写入;如果您写入了所有数据,请将数据更改回OP_READ,否则一切保持原样,等待下一次OP_写入。如果在非阻塞模式下写入时尝试循环,即使在存在零长度写入的情况下,也只会旋转,浪费CPU周期和时间 模错误:
while (buffer.position() > 0)
{
try
{
buffer.flip();
int count = ch.write(buffer);
if (count == 0)
{
key.interestOps(SelectionKey.OP_WRITE);
break;
}
}
finally
{
buffer.compact();
}
}
if (buffer.position() == 0)
{
key.interestOps(SelectionKey.OP_READ);
}
我猜它一直试图发送一个10KB的TCP数据包,但失败了很多。消息是连续发布的。拓扑是一个节点链。消息间隔为100ms@MartijnCourteaux不是。TCP打包发生在较低级别。它不会尝试发送IP数据包>路径MTU。谢谢。但我使用的是Java非阻塞套接字。当服务器收到消息时,它会将消息转发到下一个跃点4次。我不会将选择键更改为OP_WRITE。当我写入时,选择键为OP_READ。我想我的问题是tcp缓冲区已满。如果我的猜测是正确的,如何解决这个问题?关闭socketchannel会有帮助吗?确定为什么没有足够的带宽或使用速度慢,并修复它会有帮助。如果您无法控制其中任何一个,那么关闭插座是最后的手段。顺便说一句:如果您使用的是非阻塞,它不应该在写入时阻塞,它应该只是无法写入任何数据@苏珊,你正在做一个全新的注册。我说要把兴趣点改成OP_WRITE,我还说当你写成功的时候要把它们改回OP_READ。你没有那样做。另一个问题是,无论写入状态如何,都应该在flip()和write()之后压缩(),否则缓冲区将处于无效状态。另一个是write()永远不会返回<0:请参阅Javadoc。如果有一些示例代码,它将非常有用。更改windows系统tcp缓冲区是否有帮助?@susan请参见上文。众所周知,Windows socket发送和接收缓冲区在8k时太小,将它们增加到32k或48k总是有帮助的。不过,我相信您有一个编码问题,它无法解决。谢谢。我感谢你的帮助。我被困在这里有一段时间了,所以我很担心。你知道如何增加windows套接字缓冲区大小吗?我将继续修复我的编码问题。在消息之间添加间隔是一种解决方案,但是,它可能不是一个好的解决方案。@susan将键更改为OP_WRITE会影响select()的功能,但与实际写入无关。同上OP_READ和reading。如果您没有写出消息,那是因为您没有正确地围绕写操作循环,或者您没有正确地处理零长度写操作。我发布的代码应该能正确完成这两件事。您的Buffer.haslaining()测试不正确。这仅在读取时有效,或在缓冲区处于翻转状态时写入时有效。