文档章节

基于java底层api实现的nio

一不留神
 一不留神
发布于 2017/04/07 16:25
字数 1161
阅读 8
收藏 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,可以写了
			}
		}		
	}
}

 

© 著作权归作者所有

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

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

Java小铺
08/15
0
0
Apache Mina 网络通信

Apache Mina Server 是一个网络通信应用框架,也就是说,它主要是对基于TCP/IP、UDP/IP协议栈的通信框架(当然,也可以提供JAVA 对象的序列化服务、虚拟机管道通信服务等),Mina 可以帮助我...

Mr&Cheng
2013/01/20
0
0
Java NIO原理 图文分析及代码实现

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

囚兔
2015/04/29
0
0
Linux IO模型与Java NIO

概述 看Java NIO一篇文章的时候又看到了“异步非阻塞”这个概念,一直处于似懂非懂的状态,想解释下到底什么是异步 什么是非阻塞,感觉抓不住重点。决定仔细研究一下。 本文试图研究以下问题...

yingtju
06/29
0
0
Java NIO原理图文分析及代码实现

前言: 最近在分析hadoop的RPC(Remote Procedure Call Protocol ,远程过程调用协议,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。可以参考:http://baik...

SunnyWu
2014/11/05
0
1

没有更多内容

加载失败,请刷新页面

加载更多

下一页

八大包装类型的equals方法

先看其中一个源码 结论:八大包装类型的equals方法都是先判断类型是否相同,不相同则是false,相同则判断值是否相等 注意:包装类型不能直接用==来等值比较,否则编译报错,但是数值的基本类型...

xuklc
39分钟前
1
0
NoSQL , Memcached介绍

什么是NoSQL 非关系型数据库就是NoSQL,关系型数据库代表MySQL 对于关系型数据库来说,是需要把数据存储到库、表、行、字段里,查询的时候根据条件一行一行地去匹配,当量非常大的时候就很耗...

TaoXu
昨天
0
0
890. Find and Replace Pattern - LeetCode

Question 890. Find and Replace Pattern Solution 题目大意:从字符串数组中找到类型匹配的如xyy,xxx 思路: 举例:words = ["abc","deq","mee","aqq","dkd","ccc"], pattern = "abb"abc ......

yysue
昨天
0
0
Linux | Redis

写在前面的话 常言道,不作笔记不读书。在下是深有体会啊,所以,跟我一起做下本节的笔记吧,或许多年以后,你一定会感谢今天的你。 安装 在官网的下载页 Redis Download 直接写了在Linux的安...

冯文议
昨天
1
0
NoSQL-memcached

NoSQL介绍 NoSQL叫非关系型数据库。而关系型数据库代表有MySQL。对于关系型数据库来说,是需要把数据存储到库、表、行、字段里,查询的时候根据条件一行一行地去匹配,当量非常大的时候就很...

ln97
昨天
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部