Socket Channel

新的 Socket Channel 可以运行非阻塞模式,并且是可选择的。再也不用为每个 socket 创建一个线程了。

全部 socket 通道类(DatagramChannel、SocketChannel 和 ServerSocketChannel)都是由位于 java.nio.channels.spi 包中的 AbstractSelectableChannel 引申而来。

DatagramChannel 和 SocketChannel 实现定义读和写功能的接口而 ServerSocketChannel 不实现。ServerSocketChannel 负责监听传入的连接和创建新的 SocketChannel 对象,它本身从不传输数据。

要把 Socket Channel 设置成非阻塞的,需要使用到父类 SelectableChannel 的方法:

1
2
3
4
5
6
7
8

public abstract class SelectableChannel extends AbstractChannel implements Channel
{
// This is a partial API listing
public abstract void configureBlocking (boolean block) throws IOException;
public abstract boolean isBlocking( );
public abstract Object blockingLock( );
}

有条件的选择是一种可以用来查询通道的机制,该查询可以判断通道是否准备好执行一个目标操作,如读或写。

configureBlocking( ),传入 true 是阻塞模式,false 是非阻塞模式。

ServerSocketChannel

1
2
3
4
5
6
7
8
public abstract class ServerSocketChannel
extends AbstractSelectableChannel
{
public static ServerSocketChannel open( ) throws IOException
public abstract ServerSocket socket( );
public abstract ServerSocket accept( ) throws IOException;
public final int validOps( )
}

实例代码:

1
2
3
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.socket().bind(new InetSocketAddress("localhost", 8888));
serverSocketChannel.configureBlocking(false);

ServerSocketChannel 也有 accept() 方法。会返回 SocketChannel 对象,返回的对象可以在非阻塞模式下运行。

SocketChannel

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public abstract class SocketChannel
extends AbstractSelectableChannel
implements ByteChannel, ScatteringByteChannel, GatheringByteChannel
{
// This is a partial API listing
public static SocketChannel open( ) throws IOException
public static SocketChannel open (InetSocketAddress remote) throws IOException
public abstract Socket socket( );
public abstract boolean connect (SocketAddress remote) throws IOException;
public abstract boolean isConnectionPending( );
public abstract boolean finishConnect( ) throws IOException;
public abstract boolean isConnected( );
public final int validOps( )
}

每个 SocketChannel 对象创建时都是同一个对等的 java.net.Socket 对象串联的。 静态的 open( )方法可以创建一个新的 SocketChannel 对象,而在新创建的 SocketChannel 上调用 socket( )方法能返回它对等的 Socket 对象;在该 Socket 上调用 getChannel( )方法则能返回最初的那个 SocketChannel。

1
2
3
4
5
SocketChannel socketChannel = SocketChannel.open( );
SocketChannel.open (new InetSocketAddress ("somehost", somePort));

SocketChannel socketChannel = SocketChannel.open( );
socketChannel.connect (new InetSocketAddress ("somehost", somePort));

DatagramChannel

每一个 DatagramChannel 对象也有一个关联的 DatagramSocket 对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public abstract class DatagramChannel
extends AbstractSelectableChannel
implements ByteChannel, ScatteringByteChannel, GatheringByteChannel
{
// This is a partial API listing
public static DatagramChannel open( ) throws IOException
public abstract DatagramSocket socket( );
public abstract DatagramChannel connect (SocketAddress remote)
throws IOException;
public abstract boolean isConnected( );
public abstract DatagramChannel disconnect( ) throws IOException;
public abstract SocketAddress receive (ByteBuffer dst)
throws IOException;
public abstract int send (ByteBuffer src, SocketAddress target)
public abstract int read (ByteBuffer dst) throws IOException;
public abstract long read (ByteBuffer [] dsts) throws IOException;
public abstract long read (ByteBuffer [] dsts, int offset,int length)
throws IOException;
public abstract int write (ByteBuffer src) throws IOException;
public abstract long write(ByteBuffer[] srcs) throws IOException;
public abstract long write(ByteBuffer[] srcs, int offset,
int length)
throws IOException;
}

实例代码:

1
2
3
DatagramChannel channel = DatagramChannel.open( );
DatagramSocket socket = channel.socket( );
socket.bind (new InetSocketAddress (portNumber));

管道

java.nio.channels 包中含有一个名为 Pipe(管道)的类。

Pipe 类实现一个管道范例,不过它所创建的管道是进程内(在 Java 虚拟机进程内部)而非进程间使用的。

1
2
3
4
5
6
7
8
public abstract class Pipe {
public static Pipe open( ) throws IOException;
public abstract SourceChannel source( );
public abstract SinkChannel sink( );
public static abstract class SourceChannel extends AbstractSelectableChannel implements ReadableByteChannel, ScatteringByteChannel

public static abstract class SinkChannel extends AbstractSelectableChannel implements WritableByteChannel, GatheringByteChannel
}

Pipe.open( )工厂方法来创建 Pipe。Pipe 类定义了两个嵌套的通道类来实现管路。

Pipe.SourceChannel 负责读,Pipe.SinkChannel 负责写。

这两个通道实例是在 Pipe 对象创建的同时被创建的,可以通过在 Pipe 对象上分别调用 source( )和 sink( )方法来取回。

【参考资料】

  1. Java Nio

—EOF—