文档章节

基于java底层api实现的nio

一不留神
 一不留神
发布于 2017/04/07 16:25
字数 1161
阅读 11
收藏 2

服务器端

package nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

public class Server {
	
	private static ByteBuffer recvBuf = ByteBuffer.allocate(1024);
	
	private static ByteBuffer respBuf = ByteBuffer.allocate(1024);

	private static Map<SelectionKey,Object> sessionMessage = new ConcurrentHashMap<SelectionKey,Object>();
	public static void main(String[] args) throws IOException {
		//多路复用器
		Selector selector = Selector.open();
		
		//创建server
		ServerSocketChannel server = ServerSocketChannel.open();
		server.socket().bind(new InetSocketAddress(9999));//绑定端口
		server.configureBlocking(false);//设置非阻塞
		
		//server上注册一个多路复用器  事件标签OP_ACCEPT接收客户端连接 这样多路复用器将不断轮询server,当有客户端连接过来,就会被轮询出来  
		server.register(selector, SelectionKey.OP_ACCEPT);
		System.out.println("服务器已经启动");
		//启动监听
		listener(server, selector);
		
	}
	
	
	public static void listener(ServerSocketChannel server, Selector selector ) throws IOException{
		while (true) {
			int eventCount = selector.select();//如果有客户端连接过来,就会被轮询出来
			if (eventCount <= 0) {//小于等于0,说明没有客户端接入
				continue;
			}
			Set<SelectionKey> keys = selector.selectedKeys();//获取有事件触发的selectkey
			Iterator<SelectionKey> iter = keys.iterator();
			while (iter.hasNext()) {
				SelectionKey key = iter.next();
				//处理事件
				try {
					process(server,selector,key);
				} catch (IOException e) {//客户端异常关闭
					close(key);
				}
				iter.remove();//处理完移除这个事件
			}
		}
	}
	
	public static void process(ServerSocketChannel server,  Selector selector ,SelectionKey key) throws IOException{
		SocketChannel client = null;
		if (key.isValid() && key.isAcceptable() ) {//事件是否是有效的
			client = server.accept();//有客户端接入,把客户端连接通道也注册到多路复用器上
			
			client.configureBlocking(false);//非阻塞的
			client.register(selector, SelectionKey.OP_READ);//客户端连接过来,注册读事件
		}else if(key.isValid() && key.isReadable()){//可读的,说明注册在多路复用上的客户端有数据发过来了
			recvBuf.clear();//清空缓冲区
			client = (SocketChannel) key.channel();//通过key获取到客户端,这个客户端是在Acceptable时连接过来的客户端
			int length = client.read(recvBuf);//将数据读到缓冲区
			if (length > 0) {//读取到内容的时候
				String message = new String(recvBuf.array(),0,length);
				sessionMessage.put(key, message);//将数据放到sessionmessage中
				key.interestOps(SelectionKey.OP_WRITE);//读完数据后,这个客户端在多路复用器上的事件由read变为write,可以写了
			}else{
				if (client.isConnected()) {
					System.out.println("客户端关闭");
					close(key);
				}
			}
		}else if(key.isValid() && key.isWritable()){//可写的,说明注册在多路复用上的客户端数据已经接收完了,可以往客户端写数据了
			if (!sessionMessage.containsKey(key)) {
				return;
			}
			//获取到客户端发送过来的数据
			client = (SocketChannel) key.channel();
			Object resp = handler(sessionMessage.get(key));//将读取到的数据暴露给用户处理,得到响应数据
			respBuf.clear();
			respBuf.put((ByteBuffer)resp);
			respBuf.flip();
			client.write(respBuf);//响应客户端
			key.interestOps(SelectionKey.OP_READ);//写完数据后,这个客户端在多路复用器上的事件又由write变为read,可以读了
		}else{
			client = server.accept();//有客户端接入,把客户端连接通道也注册到多路复用器上
			System.out.println("连接状态::"+client.isConnected());
		}
	}
	
	public static ByteBuffer handler(Object message){
		System.out.println("来自客户端的消息:"+message);
		return ByteBuffer.wrap((message+"这是响应").getBytes());
		
	}
	
	public static void close(SelectionKey key){
		key.cancel();//取消注册
		SocketChannel client = (SocketChannel) key.channel();
		try {
			if (client != null) {
				client.socket().close();
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

客户端

package nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Map;
import java.util.Scanner;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

public class Client {
	private static ByteBuffer sendBuf = ByteBuffer.allocate(1024);
	
	private static ByteBuffer respBuf = ByteBuffer.allocate(1024);
	
	private static Map<SelectionKey,Object> sessionMessage = new ConcurrentHashMap<SelectionKey,Object>();
	public static void main(String[] args) throws IOException {
		//多路复用器
	    Selector selector = Selector.open();
		
		//客户端
		SocketChannel client = SocketChannel.open();
		client.configureBlocking(false);
		client.register(selector, SelectionKey.OP_CONNECT);//注册连接事件
		client.connect(new InetSocketAddress("localhost", 9999));//连接服务器,触发connect事件
		//监听客户端事件
		listener(client,selector);
	}

	private static void listener(SocketChannel client, Selector selector) throws IOException {
		while (true) {
				int eventCount = selector.select();//如果有客户端连接过来,就会被轮询出来
				if (eventCount <= 0) {//小于等于0,说明没有事件触发
					continue;
				}
				Set<SelectionKey> keys = selector.selectedKeys();//获取有事件触发的selectkey
				Iterator<SelectionKey> iter = keys.iterator();
				while (iter.hasNext()) {
					SelectionKey key = iter.next();
					//处理事件
					try {
						process(client,selector,key);
					} catch (IOException e) {//客户端异常关闭
						//close(key);
					}
					iter.remove();//处理完移除这个事件
				}
			
		}
	}

	private static void process(SocketChannel client, Selector selector,
			SelectionKey key) throws IOException{
		Scanner scan = new Scanner(System.in);
		SocketChannel channel = null;
		if (key.isValid() && key.isConnectable() ) {//事件是否是有效的
			channel = (SocketChannel) key.channel();
			if (channel.isConnectionPending()) {//如果正在连接,完成连接
				channel.configureBlocking(false);
				channel.finishConnect();
				System.out.println("客户端连接成功");
			}
			client.register(selector, SelectionKey.OP_WRITE);//客户端连接上了,可以写了
		}else if(key.isValid() && key.isWritable()){//可写了,向服务器端发送消息
			System.out.println("可以写了-----");
			String line = scan.next();
			if (line.equals("finsh")) {
				System.out.println("关闭了...");
				key.cancel();
				client.close();
				System.exit(1);
			}else{
				sendBuf.clear();
				sendBuf.put(line.getBytes());
				sendBuf.flip();
				client.write(sendBuf);//响应客户端
				key.interestOps(SelectionKey.OP_READ);//写完数据后,这个客户端在多路复用器上的事件又由write变为read,可以读了
			}
		}else if(key.isValid() && key.isReadable()){//可读,获取服务器端响应
			System.out.println("可以读了-----");
			respBuf.clear();//清空缓冲区
			int length = client.read(respBuf);//将数据读到缓冲区
			if (length > 0) {//读取到内容的时候
				String message = new String(respBuf.array(),0,length);
				System.out.println("client-响应信息::::"+message);
				key.interestOps(SelectionKey.OP_WRITE);//读完数据后,这个客户端在多路复用器上的事件由read变为write,可以写了
			}
		}		
	}
}

 

© 著作权归作者所有

共有 人打赏支持
一不留神
粉丝 7
博文 31
码字总数 23780
作品 0
郑州
后端工程师
私信 提问
跳槽时,这些Java面试题99%会被问到

我在 Oracle 已经工作了近 7 年,面试过从初级到非常资深的Java工程师,且由于 Java 组工作任务的特点,我非常注重面试者的计算机科学基础和编程语言的理解深度,可以不要求面试者非要精通 ...

Java小铺
08/15
0
0
晒晒你看过的哪些Java相关的书。

@红薯 要我们晒Jar包 , 我倒想看看大家都看过什么Java编程相关的书籍,我先来:如下 1、iText in Action 主要内容: a、自动化静态和动态XFA表单 b、如何从XML生成动态PDF或数据库 c、如何添...

刘学炜
2012/09/27
317
4
Java网络编程框架

自从JDK1.4中有了NIO以后,这个方面越来越活跃,也为java赢得更多开发者的支持。做java网络编程需要掌握一些基本的知识和技能: 套接字编程、阻塞/非阻塞通信、创建HTTP服务器与客户程序、数...

长平狐
2012/08/29
2.3K
0
12《Java核心技术》之Java有几种文件拷贝方式?哪一种最高效?

一、提出问题 上一讲我们学习到,NIO 不止是多路复用,NIO 2 也不只是异步 IO,今天我们一起学习 Java IO 体系中,其他不可忽略的部分。 今天我们要讨论的的问题是,Java 有几种文件拷贝方式...

飞鱼说编程
10/25
0
1
Java NIO原理 图文分析及代码实现

Java NIO原理图文分析及代码实现 前言: 最近在分析hadoop的RPC(Remote Procedure Call Protocol ,远程过程调用协议,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术...

囚兔
2015/04/29
0
0

没有更多内容

加载失败,请刷新页面

加载更多

fabric增删改查Mac

备份1.3版本,重新下载1.1版本到fabric文件夹 /opt/gopath/src/github.com/hyperledger/fabric -> /opt/gopath/src/github.com/hyperledger/fabric1.3 新建/opt/gopath/src/github.com/hype......

八戒八戒八戒
8分钟前
1
0
盘点愚人节各大网站彩蛋,谁最爱恶搞?

如今的愚人节俨然已是各品牌宣传了一个重要节日,同时,也成为了各大互联网科技企业凑热闹,比拼创意和策划的节日。跟小编一起看看有哪些有趣的策划吧! Google地图变成吃豆人游戏 每年愚人节...

临江仙卜算子
32分钟前
2
0
Java7/8 中的 HashMap 和 ConcurrentHashMap 全解析

本文分析的是源码,所以至少读者要熟悉它们的接口使用,同时,对于并发,读者至少要知道 CAS、ReentrantLock、UNSAFE 操作这几个基本的知识,文中不会对这些知识进行介绍。Java8 用到了红黑树...

java菜分享
33分钟前
1
0
玩手机与做实验

看过这样一个故事:说的是在二十世纪二十年代初的一个深夜,担任英国剑桥大学卡文迪许实验室主任的卢瑟福来实验室检查,发现一位学生还在做实验。卢瑟福就问他:“你上午做什么了?”学生回答...

Bob2100
今天
4
0
Kafka流式处理

Kafka Streams 初识流式处理 什么是数据流 数据流(也叫事件流)是无边界数据集的抽象表示。无边界意味着无限和持续增长。无边界数据集之所以是无限的,是因为随着时间的推移,新记录会不断加...

东都大狼狗
今天
9
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部