NIO之SocketChannel简单使用


客户端:

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;

public class SocketChannelTest
{
	public static void main(String[] args) throws IOException{
		SocketChannel socket = SocketChannel.open();
		socket.configureBlocking(false);
		//设置非阻塞状态 则在connect返回之前可以执行下一步	while(!socket.finishConnect())判断
		socket.connect(new InetSocketAddress("localhost",50000));//如果不设置为非阻塞模式 则connect是阻塞方法 
		
		while(!socket.finishConnect()){
			System.out.println("waiting");
		}
		
		ByteBuffer buffer = ByteBuffer.allocate(1024);
		int i = -100;
		while((i = socket.read(buffer))!=-1){//读取信息 默认为阻塞的 可通过	socket.configureBlocking(false)设置为非阻塞 非阻塞模式下 返回读取的文件字节数 如果没有 则返回0 如果该通道已到达流的末尾,则返回 -1 
			if( i != 0){
				buffer.flip();//一定要flip,read会改变position的值
				System.out.println(buffer.position()+"  "+buffer.limit());
				String info = getString(buffer);
			
				System.out.println(info);
				buffer.clear();
			}
			
			
		}
		System.out.println("done");
		socket.close();
	}
	
	/**
	 * 将ByteBuffer转成字符串
	 * @param buffer
	 * @return
	 */
	public static String getString(ByteBuffer buffer)  
	{  
		Charset charset = null;  
		CharsetDecoder decoder = null;  
		CharBuffer charBuffer = null;  
		try  
		{  
			charset = Charset.forName("UTF-8");  
			decoder = charset.newDecoder();  
			// charBuffer = decoder.decode(buffer);//用这个的话,只能输出来一次结果,第二次显示为空  
			charBuffer = decoder.decode(buffer.asReadOnlyBuffer());  
			return charBuffer.toString();  
		}  
		catch (Exception ex)  
		{  
			ex.printStackTrace();  
			return "";  
		}  
	}  
}


这里需要注意的是:


在非阻塞模式下调用connect( )方法之后,SocketChannel又被切换回了阻塞模式。那么如果有必要的话,调用线程会阻塞直到连接建立完成,finishConnect( )方法接着就会返回true值。

设置非阻塞模式时一定要调用finishConnect()来完成连接  否则读写操作将会报错NotYetConnectedException

下面是finishConnect的API解释:

finishConnect

public abstract boolean finishConnect()
                               throws IOException
完成套接字通道的连接过程。

通过将套接字通道置于非阻塞模式,然后调用其 connect 方法来发起非阻塞连接操作。一旦建立了连接,或者尝试已失败,该套接字通道就变为可连接的,并且可调用此方法完成连接序列。如果连接操作失败,则调用此方法将导致抛出合适的 IOException

如果已连接了此通道,则不阻塞此方法并且立即返回 true。如果此通道处于非阻塞模式,那么当连接过程尚未完成时,此方法将返回 false。如果此通道处于阻塞模式,则在连接完成或失败之前将阻塞此方法,并且总是返回 true 或抛出描述该失败的、经过检查的异常。

可在任意时间调用此方法。如果正在调用此方法时在此通道上调用读取或写入操作,则在此调用完成前将首先阻塞该操作。如果试图发起连接但失败了,也就是说如果调用此方法导致抛出经过检查的异常,则关闭此通道。

返回:
当且仅当已连接此通道的套接字时才返回 true
抛出:
NoConnectionPendingException - 如果未连接此通道并且尚未发起连接操作
ClosedChannelException - 如果此通道已关闭
AsynchronousCloseException - 如果正在进行连接操作时另一个线程关闭了此通道
ClosedByInterruptException - 如果正在进行连接操作时另一个线程中断了当前线程,因此关闭了该通道并将当前线程设置为中断状态
IOException - 如果发生其他 I/O 错误




关于SocketChannel的read方法返回值:

(read后position的值会变化)

转自http://blog.csdn.net/pingnanlee/article/details/9712439

1、read什么时候返回-1

read返回-1说明客户端的数据发送完毕,并且主动的close socket。所以在这种场景下,你需要关闭socketChannel并且取消key,最好是退出当前函数。注意,这个时候服务端要是继续使用该socketChannel进行读操作的话,就会抛出“远程主机强迫关闭一个现有的连接”的IO异常。

2、read什么时候返回0

其实read返回0有3种情况,一是某一时刻socketChannel中当前(注意是当前)没有数据可以读,这时会返回0,其次是bytebuffer的position等于limit了,即bytebuffer的remaining等于0,这个时候也会返回0,最后一种情况就是客户端的数据发送完毕了,这个时候客户端想获取服务端的反馈调用了recv函数,若服务端继续read,这个时候就会返回0。





服务端:

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;

public class ServerSocketChannelTest
{
	public static void main(String[] args) throws IOException{
		int port = 50000;
		ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();  
	//	serverSocketChannel.configureBlocking(false);  
		ServerSocket serverSocket = serverSocketChannel.socket();  
		serverSocket.bind(new InetSocketAddress(port));  //绑定端口
		serverSocketChannel.configureBlocking(false);  //设置成非阻塞模式 即不会再accept因为等待连接而阻塞  如果没有连接则立即返回null 
	//	System.out.println(serverSocketChannel.isBlocking());
		while(true){
			SocketChannel socket = serverSocketChannel.accept();
			if(socket!=null){
				System.out.println("accept connect from "+socket.getLocalAddress());
				ByteBuffer buffer = ByteBuffer.allocate(1024);
				buffer.put("hello".getBytes());//法送hello信息
				buffer.flip();//position回置
				socket.write(buffer);
			}
		}
	}
}


 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值