文档章节

基于java底层api实现的nio

一不留神
 一不留神
发布于 2017/04/07 16:25
字数 1161
阅读 8
收藏 2
点赞 0
评论 0

服务器端

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
博文 30
码字总数 23780
作品 0
郑州
后端工程师
Java 5 、6、 7中新特性

JDK5新特性(与1.4相比)【转】 1 循环 for (type variable : array){ body} for (type variable : arrayList){body} 而1.4必须是: for (int i = 0; i < array.length; i++){ type variabl......

thinkyoung ⋅ 2014/10/14 ⋅ 0

面试必看!2018年4月份阿里最新的java程序员面试题目

目录 技术一面(23问) 技术二面(3大块) 性能优化(21点) 项目实战(34块) JAVA方向技术考察点(15点) JAVA开发技术面试中可能问到的问题(17问) 阿里技术面试1 1.Java IO流的层次结构...

美的让人心动 ⋅ 04/16 ⋅ 0

Java NIO 机制分析(一) Java IO的演进

一、引言 Java1.4之前的早期版本,Java对I/O的支持并不完善,开发人员再开发高性能I/O程序的时候,会面临一些巨大的挑战和困难,主要有以下一些问题: (1)没有数据缓冲区,I/O性能存在问题...

宸明 ⋅ 04/20 ⋅ 0

Java 使用 happen-before 规则实现共享变量的同步操作

前言 熟悉 Java 并发编程的都知道,JMM(Java 内存模型) 中的 happen-before(简称 hb)规则,该规则定义了 Java 多线程操作的有序性和可见性,防止了编译器重排序对程序结果的影响。按照官方的...

stateIs0 ⋅ 01/20 ⋅ 0

Jenkins 教程(一)实现自动化打包及邮件通知

个人不喜欢装腔作势一堆专业术语放上去,让大多数人看不懂来提升逼格(所谓的专家),所以我简单的介绍jenkins是干啥的。本文使用jenkins,就是让它把git仓库里的东西取出来,然后在jenkins容器...

FantJ ⋅ 05/26 ⋅ 0

Java NIO 系列教程 -- delete

(一) Java NIO 概述 Java NIO 由以下几个核心部分组成: Channels Buffers Selectors 虽然Java NIO 中除此之外还有很多类和组件,但在我看来,Channel,Buffer 和 Selector 构成了核心的A...

数据之美 ⋅ 2013/06/09 ⋅ 4

Java NIO AsynchronousFileChannel

原文链接 , 原文作者:Jakob Jenkov, 翻译:Neil Hao 在Java 7,AsynchronousFileChannel 被添加到了Java NIO中。使用AsynchronousFileChannel可以实现异步地读取和写入文件数据。 创建一个A...

Neil_Hao ⋅ 01/20 ⋅ 0

smart-ioc 首版发布:为 Android 打造的国产 NIO 通信框架

项目背景 在几年前作者便开始NIO的学习与研究,并在码云上提交了第一个作品smart-socket(NIO版)。本来期望将其打造成异步非阻塞的通信框架,如同netty一样,却最终效果并不理想。恰逢Java ...

三刀蜀黍 ⋅ 05/28 ⋅ 13

gradle/Groovy语法

Groovy官网的介绍(http://www.groovy-lang.org/download.html#gvm) Gradle API 文档: https://docs.gradle.org/current/dsl/org.gradle.api.invocation.Gradle.html 深入理解Android(一)......

shareus ⋅ 04/27 ⋅ 0

Java NIO之Selector(选择器)

历史回顾: Java NIO 概览 Java NIO 之 Buffer(缓冲区) Java NIO 之 Channel(通道) 其他高赞文章: 面试中关于Redis的问题看这篇就够了 一文轻松搞懂redis集群原理及搭建与使用 超详细的Jav...

山川_84b6 ⋅ 05/16 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

知乎Java数据结构

作者:匿名用户 链接:https://www.zhihu.com/question/35947829/answer/66113038 来源:知乎 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 感觉知乎上嘲讽题主简...

颖伙虫 ⋅ 今天 ⋅ 0

Confluence 6 恢复一个站点有关使用站点导出为备份的说明

推荐使用生产备份策略。我们推荐你针对你的生产环境中使用的 Confluence 参考 Production Backup Strategy 页面中的内容进行备份和恢复(这个需要你备份你的数据库和 home 目录)。XML 导出备...

honeymose ⋅ 今天 ⋅ 0

JavaScript零基础入门——(九)JavaScript的函数

JavaScript零基础入门——(九)JavaScript的函数 欢迎回到我们的JavaScript零基础入门,上一节课我们了解了有关JS中数组的相关知识点,不知道大家有没有自己去敲一敲,消化一下?这一节课,...

JandenMa ⋅ 今天 ⋅ 0

火狐浏览器各版本下载及插件httprequest

各版本下载地址:http://ftp.mozilla.org/pub/mozilla.org//firefox/releases/ httprequest插件截至57版本可用

xiaoge2016 ⋅ 今天 ⋅ 0

Docker系列教程28-实战:使用Docker Compose运行ELK

原文:http://www.itmuch.com/docker/28-docker-compose-in-action-elk/,转载请说明出处。 ElasticSearch【存储】 Logtash【日志聚合器】 Kibana【界面】 答案: version: '2'services: ...

周立_ITMuch ⋅ 今天 ⋅ 0

使用快嘉sdkg极速搭建接口模拟系统

在具体项目研发过程中,一旦前后端双方约定好接口,前端和app同事就会希望后台同事可以尽快提供可供对接的接口方便调试,而对后台同事来说定好接口还仅是个开始、设计流程,实现业务逻辑,编...

fastjrun ⋅ 今天 ⋅ 0

PXE/KickStart 无人值守安装

导言 作为中小公司的运维,经常会遇到一些机械式的重复工作,例如:有时公司同时上线几十甚至上百台服务器,而且需要我们在短时间内完成系统安装。 常规的办法有什么? 光盘安装系统 ===> 一...

kangvcar ⋅ 昨天 ⋅ 0

使用Puppeteer撸一个爬虫

Puppeteer是什么 puppeteer是谷歌chrome团队官方开发的一个无界面(Headless)chrome工具。Chrome Headless将成为web应用自动化测试的行业标杆。所以我们很有必要来了解一下它。所谓的无头浏...

小草先森 ⋅ 昨天 ⋅ 0

Java Done Right

* 表示难度较大或理论性较强。 ** 表示难度更大或理论性更强。 【Java语言本身】 基础语法,面向对象,顺序编程,并发编程,网络编程,泛型,注解,lambda(Java8),module(Java9),var(...

风华神使 ⋅ 昨天 ⋅ 0

Linux系统日志

linux 系统日志 /var/log/messages /etc/logrotate.conf 日志切割配置文件 https://my.oschina.net/u/2000675/blog/908189 logrotate 使用详解 dmesg 命令 /var/log/dmesg 日志 last命令,调......

Linux学习笔记 ⋅ 昨天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部