NIO:流(TCP)信道详解

流信道有两个变体:SocketChannelServerSocketChannel。像其对应的Socket一样,SocketChannel是相互连接的终端进行通信的信道。

SocketChannel:创建,连接和关闭

static SocketChannel open(SocketAddress remote)

static SocketChannel open()

boolean connect(SocketAddress remote)

boolean isConnected()

void close()

boolean isOpen()

Socket socket()

调用SocketChannel的静态工厂方法open()可以创建一个实例。open()方法的第一种形式SocketAddress(见第2章)为参数,返回一个连接到指定服务器的SocketChannel实例。注意,该方法可能会无限期地阻塞下去。open()的无参数形式用于创建一个没有连接的SocketChannel实例,该实例可以通过调用connect()方法连接到指定终端。当使用完SocketChannel后,需要调用close()方法将其关闭。有一点很重要,即每个SocketChannel实例都"包裹"了一个基本Java Socket,并可以通过socket()方法对该Socket进行访问。这就可以通过基本的Socket方法进行绑定、设置套接字选项等操作。一个SocketChannel的创建、连接和关闭的例子,见TCPEchoClientNonblocking.java(第113-114页)。

在创建并连接SocketChannel后,就可以调用该信道的读写方法进行I/O操作。

SocketChannel:读和写

int read(ByteBuffer dst)

long read(ByteBuffer[] dsts)

long read(ByteBuffer[] dsts, int offset, int length)

int write(ByteBuffer src)

long write(ByteBuffer[] srcs)

long write(ByteBuffer[] srcs, int offset, int length)

读操作的最基本形式以一个ByteBuffer为参数,并将读取的数据填入该缓冲区所有的剩余字节空间中。另一种形式以多个ByteBuffer为参数(ByteBuffer数组),并根据其在数组中的顺序,将读取的数据依次填入每个缓冲区的剩余字节空间中。这种方法称为散射式读,因为它将读入的字节分散到了多个缓冲区中。需要注意重要的一点,散射式读不一定会将所有缓冲区填满,这些缓冲区的总空间大小只是一个上限。

写操作的最基本形式以一个ByteBuffer为参数,并试图将该缓冲区中剩余的字节写入信道。另一种形式以一个ByteBuffer数组作为参数,并试图将所有缓冲区中的剩余字节都写入信道。这种方法称为聚集式写,因为它把多个缓冲区中的字节聚集起来,一起发送出去。读

写操作的例子见TCPEchoClientNonblocking.javaTCPServerSelector.java

与其对应的ServerSocket一样,ServerSocketChannel是用来侦听客户端连接的信道。

ServerSocketChannel:创建,接受和关闭

static ServerSocketChannel open()

ServerSocket socket()

SocketChannel accept()

void close()

boolean isOpen()

调用静态工厂方法open()可以创建一个ServerSocketChannel实例。每个实例都包裹了一ServerSocket实例,并可以通过socket()方法对其访问。正如前面的例子所表明的,必须通过访问底层的ServerSocket实例来实现绑定指定端口,设置套接字选项等操作。在创建了信道实例并绑定端口后,就可以调用accept()方法来准备接收客户端的连接请求。连接成功则返回一个新的已连接的SocketChannel。在用完ServerSocketChannel后,需要调用close()方法将其关闭。使用ServerSocket的例子见TCPServerSelector.java(第116-117页)。

如前文提到的那样,阻塞式信道除了能够(必须)与Buffer一起使用外,对于普通套接字来说几乎没有优点。因此,可能总是需要将信道设置成非阻塞式的。

SocketChannel, Server SocketChannel:设置阻塞行为

SelectableChannel configureBlocking(boolean block)

boolean isBlocking()

通过调用configureBlocking(false)可以将SocketChannelServerSocketChannel设置为非阻塞模式。configureBlocking()方法将返回一个SelectableChannel,它是SocketChannelServerSocketChannel父类。

考虑为SocketChannel设置连接的情况。如果传给SocketChannel的工厂方法open()一个远程地址,对该方法的调用则将阻塞等待,直到成功建立了连接。要避免这种情况,可以使open()方法的无参数形式,配置信道为非阻塞模式,再调用connect()方法,指定远程终端地址。如果在没有阻塞的情况下连接已经建立,connect()方法返回true;否则需要有检查套接字是否连接成功的方法。

SocketChannel:测试连接性

boolean finishConnect()

boolean isConnected()

boolean isConnectionPending()

对于非阻塞SocketChannel来说,一旦已经发起连接,底层套接字可能即不是已经连接,又不是没有连接,而是连接"正在进行"。由于底层协议的工作机制(见第6章),套接字可能会在这个状态一直保持下去。finishConnect()方法可以用来检查在非阻塞套接字上试图进行的连接的状态,还可以在阻塞套接字建立连接的过程中阻塞等待,直到连接成功建立。例如,你可能需要将信道配置成非阻塞模式,通过connect()方法发起连接,做完一些其他工作后,又将信道配置成阻塞模式,然后调用finishConnect()方法等待连接建立完成。或者可以让信道保持在非阻塞模式,并反复调用finishConnect()方法,如TCPEchoClientNonblocking.java中所示。

isConnected()用于检查套接字是否已经建立了连接,从而避免在进行其他操作时抛出NotYetConnectedException异常(如调在用read()write()时)。还可以使用isConnectionPending()方法来检查是否有连接在该信道上发起。知道是否有连接发起是必要的,因为如果没有的话,finishConnect()方法将抛出NoConnectionPendingException异常。

相关下载:

Java_TCPIP_Socket编程(doc)

http://download.csdn.net/detail/undoner/4940239

文献来源:

LSOFT.CN(琅软中国)

你可能感兴趣的:(NIO:流(TCP)信道详解)