随笔--------java非阻塞io(nio)

前言

在java网络编程中,相比于一客户一线程阻塞io的模式,非阻塞io在资源的利用上显然要更合理。

客户端(与服务器连接)

//构建套接字格式地址
SocketAddress remoteAddr=new InetSocketAddress("localhost",8060);
SocketChannel clientChannel = SocketChannel.open();
clientChannel.connect(remoteAddr);//会向服务端发送连接事件
recvBuff=ByteBuffer.allocate(1024);//接收缓冲区
sendBuff=ByteBuffer.allocate(1024);//发送缓冲区 

服务端(将通道绑定监听事件并注册到selector)

SocketAddress serverAddr=new InetSocketAddress("localhost",8060);
selector=Selector.open();
ServerSocketChannel serverChannel = ServerSocketChannel.open();
serverChannel.configureBlocking(false);
serverChannel.socket().bind(serverAddr);
serverChannel.register(selector, SelectionKey.OP_ACCEPT);//开始监听ACCEPT事件

服务器处理客户端发来的各种事件

int nKeys = selector.select(); //查询令牌集合
if (nKeys == 0) {
	continue; //没有就绪令牌,越过下面步骤,开始新一轮查询
}
Set<SelectionKey> readyKeys = selector.selectedKeys(); //返回就绪令牌集合
Iterator<SelectionKey> it = readyKeys.iterator(); //就绪令牌集合迭代器
while (it.hasNext()) { //遍历就绪令牌集合
	SelectionKey key = it.next(); //取出下一个令牌
	if (key.isAcceptable()) { //如果是连接事件
		doAccept(key);
	} else if (key.isReadable()) { //如果是读数据事件
 		doRead(key);
	} else if (key.isWritable()) {
 		System.out.println(66666);
	}
	it.remove(); //从就绪集合中删除处理过的令牌
}//end while
private void doAccept(SelectionKey key) throws IOException { 
	try {
		ByteBuffer recvBuff=ByteBuffer.allocate(1024);//接收缓冲区
		ByteBuffer sendBuff=ByteBuffer.allocate(1024);//发送缓冲区
		ServerSocketChannel serverChannel=(ServerSocketChannel)key.channel();//侦听通道 类似ServerSocket
		SocketChannel clientChannel=serverChannel.accept(); //接受连接 类似Socket
		ServerUI.txtArea.append("服务器建立了与客户机的会话通道:"+clientChannel+"\n");
		clientChannel.configureBlocking(false); //非阻塞
		clientChannel.register(selector, SelectionKey.OP_READ);//此通道不可能只是连接,肯定会有读写操作,所以让此通道监听read并注册到selector
	} //end run
	catch (IOException ex) {
         
	}
}
 private void doRead(SelectionKey key) throws IOException {
	try {
		ServerUI.txtArea.append("outdoor"+":"+"Knock! Knock!"+"\n");
		ByteBuffer recvBuff=ByteBuffer.allocate(1024);//接收缓冲区
		ByteBuffer sendBuff=ByteBuffer.allocate(1024);//发送缓冲区
		int state;
		String question;
		Charset charset=Charset.forName("UTF-8");  //字符集
		
		SocketChannel channel = (SocketChannel)key.channel();//得到通道 
		
		recvBuff.clear();//清空接收缓存区
		channel.read(recvBuff);//将读取的数据传输给接收缓存区
		recvBuff.flip(); //缓存区指针回到数据起点 一定要有
		String recvStr=charset.decode(recvBuff).toString(); //解码成字符串

//		String[] split = recvStr.split("/");
//		question=split[0];
//		state=Integer.parseInt(split[1]);
//		System.out.println(question+" "+state);   
//      long currentId = Thread.currentThread().getId();
//      ServerUI.txtArea.append("当前会话线程ID:"+currentId+"\n"); //发布到process
            //根据服务器协议,在网络流上进行读写操作
//		Protocol protocol=new Protocol(); //生成协议对象
//		String outdoorStr; //门外人的回答
//		String indoorStr; //门内人的问话
//		outdoorStr=protocol.protocolWorking(question,state);//根据协议生成门外人的问话
//            
		sendBuff.clear();//清空发送缓存区
		sendBuff=ByteBuffer.wrap(outdoorStr.getBytes(charset));//将要发送的字符串编码并传输到发送缓存区
		channel.write(sendBuff);//开始发送缓存区里的数据
		sendBuff.flip();//缓存区指针回到数据起点 一定要有

//		String[] split1 = outdoorStr.split("/");
//		ServerUI.txtArea.append("outdoor"+":Knock! Knock"+"\n"); //发布门外人的话到process处理   
//		ServerUI.txtArea.append("outdoor"+split1[0]+"\n");

		} catch (IOException ex) {
        
        }
        //
   }//end doRead

注:

要进行数据的读写得是SocketChannel,不可以是ServerSocketChannel(这个是用来建立连接的)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值