NIO-SocketChannel详解

SocketChannel为JAVA-NIO中核心类,它实现了SelectableChannel/ScatteringByteChannel/GatheringByteChannel.不过它仍然为一个抽象类.实现层将会有JVM在运行时选择.(参见下文)

 

SocketChannel只不过是Socket通讯 + Selector机制的抽象层API,底层的通讯仍需要socket支持.

可以通过open()方法创建SocketChannel,底层通过SelectorProvider.provider().openSocketChannel(),采用系统默认的provider创建底层的通道,新创建的socketChannel已经打开,但并未建立TCP连接,此时尝试进行IO操作,将抛出异常(NotYetConnectedException).此后需要connect(remote)方法来建立连接;SocketChannel支持在非阻塞模式下连接:connect方法发起远程TCP连接,但是其立即返回,不过连接的过程仍然在进行,之后需要通过finishConnect方法检测并完成链接,可以通过isConnectionPending()检测链接是否正在进行.

 

可单独的关闭套接字通道的input和output,而无需关闭Channel;如果通过Socket关闭了当前channel的input,那么此后在channel上的read操作,将直接返回-1(EOF).如果通过Socket关闭了channel的output,那么此后在次channel上的write操作,将抛出ClosedChannelException.

 

事实上channel即为socket链接的高层封装,每个channel都绑定在一个socket上,它们息息相关.

SocketChannel的关闭支持异步关闭(来自InterruptableChannel特性),这与Channel类中指定的异步close操作有关.如果一个线程关闭了某个Socket input,那么同时另一个线程被阻塞在该SocketChannel的read操作中,那么处于阻塞线程中的读取操作将完成,而不读取任何字节且返回-1.如果一个线程关闭了socket output,而同时另一个线程被阻塞在该socketChannel的write操作中,此时阻塞线程将收到AsynchronousClosedException.

 

SocketChannel是线程安全的,但是任何时刻只能有一个线程处于read或者write操作(read操作同步readLock,write操作同步writeLock,2个线程可以同时进行read和write;),不过DatagramChannel支持并发的读写.

 

connect和finishConnect方法是互相同步的(一个同步锁对象).

  • public static SocketChannel open() throws IOException:开启一个通道,通过调用系统默认的provider.openSockentChannel方法创建通道.
  • public static SocketChannel open(SocketAddress remote) throws IOException:等效于与open(),connect(remote).
  • public final int validOps():返回其支持的操作集.对于SocketChannel除了不支持OP_ACCEPT之外,其他操作均支持.
  • public abstract boolean isConnected():判断此通道关联的socket是否已经建立连接.
  • public abstract boolean isConnectionPending():判断通道是否正在进行操作连接.只有当尚未finishConnection且已经调用connect时,返回true.
  • public abstract boolean connect(SocketAddress remote) throws IOException:底层socket建立连接.如果此通道为非阻塞模式,则调用此方法发起一个非阻塞连接操作.如果连接立即建立成功,则返回true,否则返回false.则此后必须通过调用finishConnect方法来完成链接.如果通道出去阻塞模式,则阻塞直到建立链接成功或者网络异常返回.可以在任意时间调用此方法.如果正在调用此方法时在此通道上调用了read或者write(原则上说几乎不应该如此操作),那么read/write将阻塞.底层实现简析:参见(SocketChannelImpl: http://javasourcecode.org/html/open-source/jdk/jdk-6u23/sun/nio/ch/SocketChannelImpl.java.html);此方法将会对readLock/writeLock对象锁进行同步,由此可见在connect时,将阻塞read/write操作.

 

//建立连接的参考代码
try{
	begin();//中断响应
	connectThread.doConnect();//对于remote为本地连接时,极有可能会立即返回
	if(connectSuccess){
		return true;
	}
	if(isBlocking){
		for(;;){
			if(connectSucees){
				return true;
			}
		}
	}else{
		state = CONNECT_PENDING;
		return false;
	}
}finally{
	end(boolean);//中断响应
}catch(Exception e){
	close();
	throw e;
}
 

 

  • public abstract boolean finishConnect() throws IOException:促成套接字连接完成.此方法支持与channel的非阻塞模式中.如果已经建立连接则返回true.否则返回false.此方法在非阻塞模式下会立即返回.
    boolean isSuccess = channel.connect(remote);
    if(!isSuccess){
    	while(!finishConnect()){
    		Thread.sleep(500);
    	}
    }
     
  • public abstract long read(ByteBuffer) throws IOException:来自readableChannel.对于一定数量的字节,并交付给ByteBuffer.在非阻塞模式下,有可能立即返回.
  • public abstract long read(ByteBuffer[] dst):来自ScatteringByteChannel.对于read操作,其内部将同步readLock(对象锁)和stateLock(和connect()方法同步一个锁);此方法支持中断响应,因此又有了begin()/end()方法的出现.[参考:http://shift-alt-ctrl.iteye.com/blog/1841324]

你可能感兴趣的:(SocketChannel)