TCP/IP+NIO用到的类学习

ServerSocketChannel

public abstract class ServerSocketChannel 
extends AbstractSelectableChannel
implements NetworkChannel

Java NIO中的ServerSocketChannel是一个可以监听新进来的TCP连接的通道,就像标准IO中的ServerSocket一样。ServerSocketChannel类在java.nio.channels包中。

打开ServerSocketChannel

通过调用ServerSocketChannel.open()方法来打开ServerSocketChannel。如:

ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
关闭ServerSocketChannel
serverSocketChannel.close();
监听新进来的连接

通过ServerSocketChannel.accept()方法监听新进来的连接。当accept()方法返回的时候,它返回一个包含新进来的连接的SocketChannel。因此,accept()方法会一直阻塞到有新连接到达。

通常不会仅仅只监听一个连接,在while循环中调用accept()方法,如下面的例子

while(true){
SocketChannel socketChannel = serverSocketChannel.accept();
//do something with socketChannel...
}


public abstract SocketChannel accept() throws IOException

ServerSocketChannel可以设置成非阻塞模式。在非阻塞模式下,accept()方法会立刻返回,如果还没有新进来的连接,返回的将是null。因此,需要检查返回的SocketChannel是否是null.如:

ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();

serverSocketChannel.socket().bind(new InetSocketAddress(9999));
serverSocketChannel.configureBlocking(false);

while(true){
SocketChannel socketChannel = serverSocketChannel.accept();

if(socketChannel != null){
// do something with socketChannel...
}
}

public abstract ServerSocket socket()

Returns A server socket associated with this channel.

public final ServerSocketChannel bind(SocketAddress local)     throws IOException

相当于bind(local,0)

public abstract class AbstractSelectableChannel
extends SelectableChannel

public final SelectionKey register(Selector sel, int ops, Object att)throws ClosedChannelException

Register this channel withe the given selector, returning a selection key.


public abstract class SelectionKey extends Object

public static final int OP_ACCEPT
public static final int OP_CONNECT
public static final int OP_READ
public static final int OP_WRITE

public final boolean isReadable()

相当于k.readyOps() & OP_READ !=0

public final boolean isWritable()

public final boolean isAcceptable()

Selector的创建

Selector selector = Selector.open();

注册Channel到Selector
为了将Channel和Selector配合使用,必须将Channel注册到Selector上。通过SelectableChannel.register()方法实现

channel.configureBlocking(false);
SelectionKey key = channel.register(selector,SelectionKey.OP_READ);

与Selector一起使用时,Channel必须处于非阻塞模式下。这意味着不能将FileChannel与Selector一起使用,因为FileChannel不能切换到非阻塞模式。而套接字可以。
注意register()方法的第二个参数。这是一个“interest集合”,意思是在通过Selector监听Channel时对什么事件感兴趣。可以监听四种不同类型的事件:
Connect,Accept,Read,Write
如果对不止一种事件感兴趣,那么可以用“位或”操作符将常量连接起来。

SelectionKey

代表了Selector和SelectableChannel的注册关系

key.attachment();//返回SelectionKey的attachment,attachent可以在注册channel的时候指定。
key.channel();//返回该SelectionKey对应的Channel。
key.selector();//返回该SelectionKey对应的Selector
key.interestOps();//返回代表需要Selector监控的IO操作的bit mask
key.readyOps();//返回一个bit mask,代表在相应Channel上可以进行IO操作

key.interestOps()
就像向Selector注册通道一节中所描述的,interest集合是你所选择的感兴趣的事件集合。可以通过SelectionKey读写interest集合,像这样:

int interestSet = selectionKey.interestOps();
boolean isInterestedInAccept  = (interestSet & SelectionKey.OP_ACCEPT) == SelectionKey.OP_ACCEPT;
boolean isInterestedInConnect = interestSet & SelectionKey.OP_CONNECT;
boolean isInterestedInRead    = interestSet & SelectionKey.OP_READ;
boolean isInterestedInWrite   = interestSet & SelectionKey.OP_WRITE;

可以看到,用“位或”操作interest集合和给定的SelectionKey常量,可以确定某个确定的事件是否在interest集合中。

key.readyOps()

ready集合是通道已经准备就绪的操作的集合。在一次选择(Selection)之后,你会首先访问这个ready set.

int readySet = selectionKey.readyOps();

可以用像检测interest集合那样的方法,来检测channel中什么事件或操作已经就绪。但是,也可以使用以下四个方法,它们都会返回一个布尔类型:

selectionKey.isAcceptable();
selectionKey.isConnectable();
selectionKey.isReadable();
selectionKey.isWritable();
key.channel() && key.selector()

从SelectionKey访问Channel和Selector很简单,如下:

Channel channel = selectionKey.channel();
Selector selector = selectionKey.selector();

#######key.attachment();
可以将一个对象或者更多信息附着到SelectionKey上,这样就能方便的识别某个给定的通道。例如,可以附加与通道一起使用的Buffer,或是包含聚集数据的某个对象

通过Selector选择通道

一旦调用了select()方法,并且返回值表明有一个或更多个通道就绪了,然后可以通过调用selector的selectedKeys()方法,访问“已选择键集(selected key set)”中的就绪通道。如下所示:

Set selectedKeys = selector.selectedKeys();
当像Selector注册Channel时,Channel.register()方法会返回一个SelectionKey对象。这个对象代表了注册到该selector的通道。可以通过SelectionKey的selectedKeySet()方法访问这些对象。

Set selectedKeys = selector.selectedKeys();
Iterator keyIterator = selectedKeys.iterator();
while(keyIterator.hasNext()) {
    SelectionKey key = keyIterator.next();
    if(key.isAcceptable()) {
    // a connection was accepted by a ServerSocketChannel.
} else if (key.isConnectable()) {
    // a connection was established with a remote server.
} else if (key.isReadable()) {
    // a channel is ready for reading
} else if (key.isWritable()) {
    // a channel is ready for writing
}
keyIterator.remove();
}

这个循环遍历已选择键集中的每个键,并检测各个键所对应的通道的就绪事件。

注意每次迭代末尾的keyIterator.remove()调用。Selector不会自己从已选择键集中移除SelectionKey实例。必须在处理完通道时自己移除。下次该通道变成就绪时,Selector会再次将其放入已选择的键集。

SelectionKey.channel()方法返回的通道需要转型成你要处理的类型,如ServerSocketChannel或SocketChannel等

public abstract class Selector extends Object implements Closeable

protected Selector()
abstract void close()
abstract boolean isOpen()
abstract Setkeys() 
//returns this selector's key set.
static Selector open()
abstract SelectorProvider provider()
//returns the provider that create this channel.
abstract int select()
abstract Set selectedKeys()
//returns this selector''s selected-key set.
abstract Selector wakeup()

Java NIO 系列教程(九)ServerSocketChannel

你可能感兴趣的:(TCP/IP+NIO用到的类学习)