当消息大小很大时,socketchannel.write()变得非常慢

在我使用java nio的程序中,socketchannel.write()在尝试连续写入10 KB消息时变得非常慢。 写入完整10 KB消息的测量时间介于160 ms和200 ms之间。 但是编写完整的5 KB消息的时间仅需0.8 ms。

在选择器中,我只有Selection.OP_READ并且不处理Selection.OP_WRITE。 当收到大的完整消息时,它会被写入另一个接收器4次。

有人遇到同样的问题吗? 有关于socketchannel.write()的post很慢。 我的问题是如何在OP_READ和OP_WRITE之间进行替换?

如果我添加一个例如150毫秒的inerval,则响应时间会减少。 有什么办法可以找到缓冲区已满的时候,我可以让程序等待。 我的操作系统是windows xp。

谢谢。

我通过检查写入的字节数来遵循EPJ的建议。 但响应时间仍然很长。 我在这里发布了部分代码,并想检查我的代码是否有问题。

//这是使用nio的writeData()部分:

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微秒。 在过去,我已经配置我的服务器来杀死任何需要2毫秒写入的慢速消费者。 (可能有点咄咄逼人。;)

您可以尝试增加发送缓冲区的大小(Socket.setSendBufferSize(int),也可用于SocketChannels),但看起来您尝试发送的数据超出了带宽允许的数量。

10 KB不是一个大消息,典型的发送缓冲区大小是64 KB,因此要使其满,您需要有6-7条消息未发送。 这可能解释了5KB相对较快的方式。

我建议你的读取过程很慢,这会导致它的接收缓冲区备份,这会导致你的发送缓冲区备份,这会使你的发送停顿。

否则你没有为非阻塞模式正确编写代码。 如果从write()方法得到零结果,则必须(a)将interestOps更改为OP_WRITE并(b)返回到select循环。 当你得到OP_WRITE时,你必须重复写; 如果您编写了所有数据,请将interestOps更改回OP_READ,否则保持原样并等待下一个OP_WRITE。 如果在非阻塞模式下写入时尝试循环,即使存在零长度写入,您也只会旋转,浪费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); }