最后更新时间:2014-06-25

一个Java NIO的SocketChannel是一个连接到TCP网络套接字的通道。它是Java网络的套接字的NIO的等价物。这里有两种方式创建SocketChannel:

  1. 你打开一个SocketChannel,并且连接到网络中某个地方的服务器。
  2. 当一个连接到达一个ServerSocketChannel的时候可以被创建。

打开一个SocketChannel


这里有一个如何打开一个SocketChannel的方式:


SocketChannel socketChannel = SocketChannel.open();
socketChannel.connect(new InetSocketAddress("http://jenkov.com", 80));


关闭一个SocketChannel


使用之后通过调用SocketChannel.close()方法,你可以关闭一个SocketChannel。这里有一个例子:

socketChannel.close();



从一个SocketChannel中读数据


为了从一个SocketChannel中读取数据,你可以调用read方法中的一个。这里有一个例子:


ByteBuffer buf = ByteBuffer.allocate(48);

int bytesRead = socketChannel.read(buf);



首先一个Buffer被分配了。从SocketChannel中读取的数据读到了Buffer中。


第二步SocketChannel.read()方法被调用。这个方法从SocketChannel中读数据到Buffer。通过调用read()方法返回的int值告诉我们有多少个字节写到了Buffer中。如果返回的是-1,就达到了流的结尾(这个连接就被关闭了)。


写数据到SocketChannel中


使用SocketChannel.write()方法可以写数据到SocketChannel,这个方法携带一个Buffer作为参数。这里有一个例子:


String newData = "New String to write to file..." + System.currentTimeMillis();

ByteBuffer buf = ByteBuffer.allocate(48);
buf.clear();
buf.put(newData.getBytes());

buf.flip();

while(buf.hasRemaining()) {
    channel.write(buf);
}



注意SocketChannel.write()方法在while循环内部是怎么样被调用的。这里的write()方法写数据到SocketChannel中没有固定的多少字节。因此我们将重复这个write()方法的调用直到这个Buffer中没有数据要写了。


非阻塞模式


你可以设置SocketChannel进入非阻塞模式。当你这样做的时候,你可以在异步的模式下调用connect(),read()和write()方法。


connect()


如果这个SocketChannel是在非阻塞模式下,并且你调用了connect()方法,这个方法可能在一个连接建立之前返回。为了决定这个连接是否连接上了,你可以调用finishConnect()方法,像下面这样:


socketChannel.configureBlocking(false);
socketChannel.connect(new InetSocketAddress("http://jenkov.com", 80));

while(! socketChannel.finishConnect() ){
    //wait, or do something else...    
}



write()


在非阻塞模式下这个write()方法可能会在没有写任何东西之前返回。因此你需要在一个循环中调用这个write()方法。但是,因为这个已经在前面的写数据的例子中被做了,因此在这里你不需要做任何事情了。


read()


在非阻塞模式下这个read()方法可能还没有读到任何数据就返回了。因此你需要注意返回的这个int值,它会告诉你读取到多少个字节了。


跟Selectors一起使用的非阻塞模式


这个SocketChannel的非阻塞模式跟Selector一起会工作的更好。通过一个Selector注册一个或者更多的SocketChannel,你可以请求通道的Selector是否准备好了读写等等。怎么样在SocketChannel中使用Selector,你这个教程的后面的章节中将会有更详细的解释。