SocketChannel.write(缓冲区)阻塞,它写入零字节

时间:2016-02-18 06:18:10

标签: java linux nio socketchannel

当我们使用套接字通道写入方法写入数据时。这需要花费太多时间来处理小字节数据。例如,如果许多客户端连接到我的应用程序,则需要43950 ms来写入16249字节数据。它尝试442次来写上面的数据。

public static void writeBytesFixedLength(SocketChannel sChannel, String msg){       
    ByteBuffer writeBuffer = ByteBuffer.allocate(msg.length()*2);
    writeBuffer.put(msg.getBytes());
    writeBuffer.flip();         
    long nbytes = 0;
    long toWrite = writeBuffer.remaining();
    int sleepCount = 0;
    int loopCount = 0;
    int sleepTime = 50;
    int sumSleepCount = 0;
    int sumSleepTime = 0;
    try 
    {
        int count = 0;
        while (nbytes != toWrite) {
            count= sChannel.write(writeBuffer);
            nbytes +=count;
            loopCount += 1;
            try {

                if(count == 0){            
                    OSUsage();
                    MainImapServer.printThreadStatus();
                    sleepCount += 1;
                    sumSleepCount += 1;
                    if(sleepCount == 4){
                        sleepTime = 50;
                        sleepCount =1;
                    }
                    sumSleepTime += sleepTime*sleepCount;
                    Thread.sleep(sleepTime*sleepCount);                      

                }
            }
            catch (InterruptedException e) {}
        }            
    }
    catch (ClosedChannelException cce) {}
    catch (Exception e) {}

    if(sumSleepCount >3)
    logger.info("Send buffer is full: Total Byte: "+ toWrite+ " sleepCount: "+sumSleepCount +" sleepTime: "+sumSleepTime+ " loopCount: "+ loopCount);
}

请提出一些建议来解决这个问题

提前致谢

1 个答案:

答案 0 :(得分:0)

你在这里断言你的套接字通道write()调用是阻塞的,并且它返回零。这些断言是相互矛盾的。你误会了。 API规范和底层机制都使这成为不可能。 阻止它返回零。

编辑从您的代码中可以看出它返回零。这意味着几件事:

  1. 阻止。
  2. 您的频道处于非阻止模式。
  3. 你的写作速度快于接收者的阅读速度。
  4. 当你得到零时,你应该为OP_WRITE注册一个Selector的频道,调用select(),并在频道变为可写时重试写入;如果写入成功,请取消注册OP_WRITE。这sleep()没有废话。

    显然你需要阅读Oracle NIO教程。或者扔掉它并使用阻止模式。 java.net甚至。它简单得多。