2016-05-09 25 views
0

我只是想知道是否可以使用SocketChannel类(使用ByteBuffer)来模拟Java中的常规Socket类的阻塞特性。我做了两个试验项目,一个模拟客户端和其他模拟服务器:在Java中使用阻塞NIO

客户端代码:

public static void main(String[] args) throws IOException { 

    SocketChannel socket = SocketChannel.open(new InetSocketAddress("127.0.0.1", 6789)); 

    //Simulate this: 
    //DataOutputStream dos = new DataOutputStream(socket.socket().getOutputStream()); 
    //dos.writeInt(4); 
    //dos.writeInt(6); 

    ByteBuffer buffer = ByteBuffer.allocate(4); 
    buffer.putInt(4); 
    buffer.flip(); 
    socket.write(buffer); 
    buffer.clear(); 
    buffer.putInt(6); 
    buffer.flip(); 
    socket.write(buffer); 
} 

服务器代码:

public static void main(String[] args) throws IOException, InterruptedException { 
    ServerSocketChannel ssc = ServerSocketChannel.open(); 
    ssc.socket().bind(new InetSocketAddress(6789)); 
    SocketChannel socketCh = ssc.accept(); 
    socketCh.configureBlocking(true); 
    // Simulate this 
    // DataInputStream dis = new DataInputStream(socketCh.socket().getInputStream()); 
    // System.out.println(dis.readInt()); 
    // System.out.println(dis.readInt()); 

    // This is something to avoid. This is not the same as what is up above 
    // If the 2nd line prints -1, the 3rd prints 4 
    // If the 2nd line prints 4, the 3rd prints 6 
    ByteBuffer buffer = ByteBuffer.allocate(1024); 
    socketCh.read(buffer); 
    buffer.rewind(); 
    System.out.println("First number: " + buffer.getInt()); 
    buffer.clear(); 
    System.out.println("Change: " + socketCh.read(buffer)); 
    buffer.rewind(); 
    System.out.println("Second Number: " + buffer.getInt()); 
} 

正如我在评论中说,该结果运行服务器时,客户端(按该顺序)是不可预知的,因为有时第二个数字可能会保持为4或变为6,而Change分别为-1或4(整数字节)。

至于服务器端,我知道我可以让它等待,以便第二个socketCh.read(buffer)返回一个非-1的值,这意味着什么都没有被写入(我推测)在SocketChannel中。

但是,在客户端,我没有任何想法。

我知道我可以改为使用DataOutputStream和DataInputStream并以旧式方式进行,但我想知道如何使用SocketChannel来完成此操作,只是为了方便起见。另外你也不会因为另一个诡计而出错。

尽管我手动将服务器配置为阻塞,但我认为这是默认配置,因此可以丢弃它。

预先感谢您! PS:希望我可以避免使用Selector类来完成这样一个简单的任务...

编辑:我知道Selector类只能用于非阻塞模式。

回答

1

您丢掉了可能已被读取的额外数据,并假设每次读取都提供与每次写入相对应的内容(例如,第一次只传递int)。 TCP中没有任何东西可以保证这一点。

rewind()更改为flip();将clear()更改为compact();添加一些read()返回值的检查;它应该按预期工作。

您不能在阻止模式下使用Selector

+0

好的谢谢!是的,我知道你不能在阻塞模式下使用Selector,但是我希望避免必须将SocketChannel配置为非阻塞,并且必须为此简单任务完成所有这些。 –

+0

现在我读了一下compact()的细节,让整个过程更加有意义。这就是我为了掠过一本书而​​得到的结果,我想:\。谢谢你,真的很感激它 –