package com.study.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.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set; public class NIOServer {
private static int port = 9995; //端口 // 1.第一个是服务
private static ServerSocketChannel server; // 2.第二个是多路复用器
private static Selector selector; // 3.第三个就是缓冲区buffer
// 信息接收
ByteBuffer rcBuffer = ByteBuffer.allocate(1024);
// 信息写出
ByteBuffer sendBuffer = ByteBuffer.allocate(1024); // 4.维护一个事件标签集合,和selector配合使用
Map<SelectionKey,String> sessionMsg = new HashMap<SelectionKey,String>(); // 初始化
public NIOServer() throws IOException{
server = ServerSocketChannel.open(); // 打开服务端,服务端临听端口
server.socket().bind(new InetSocketAddress(port)); //
server.configureBlocking(false); //设置为非阻塞,默认是true
selector = Selector.open(); //实例化多路复用器 //server注册上多路复用器之后,多路复用器才会为server工作,实现一个server为成千上万个client工作
//selector和事件标签Selectionkey是一起应用的,第一次服务器,是接受,Accept
server.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("NIO服务器已启动,且监听的端口是" + port); //this.port范围加大
} // 监听请求方法
public void listen() throws IOException{
while(true){
// 进来就是通过多路复用器selector,来看是否有注册事件
int eventCount = selector.select(); // 已注册事件数量
if(eventCount == 0){
// selector继续轮询,NIO的内部机制就是不断轮询注册到selector上面的多个channel
continue;
} // 拿到事件集合,SelectorKey的作用就是获取这些就绪通道的集合
Set<SelectionKey> keys = selector.selectedKeys(); //迭代
Iterator<SelectionKey> iterator = keys.iterator();
while(iterator.hasNext()){
SelectionKey key = iterator.next(); //这个事件就是客户端的一个读或者写
process(key); //处理事件
//处理完后,事件移出集合
iterator.remove();
}
}
} // 处理客户端事件
private void process(SelectionKey key) {
// 处理客户端请求,定义客户端对象
SocketChannel client = null;
try { // 判断key是否是有效的
if(key.isValid() && key.isAcceptable()){
client = server.accept(); //接收一个客户端
client.configureBlocking(false); //设置为非阻塞
client.register(selector , SelectionKey.OP_READ); //读取客户端请求,事件标签类型改为读取 } else if(key.isValid() && key.isReadable()){ //是否是可读的
// 读到缓冲区
rcBuffer.clear();
client = (SocketChannel)key.channel(); // 拿到客户端通道
int len = client.read(rcBuffer); //读取的长度
if(len > 0){ //读到内容
String msg = new String(rcBuffer.array() , 0 ,len);
System.out.println("服务端收到msg:"+msg);
sessionMsg.put(key, msg);
// 告诉selector,已读完,下次可以写数据
client.register(selector, SelectionKey.OP_WRITE);
}
}else if(key.isValid() && key.isWritable()){
if(!sessionMsg.containsKey(key)){ //是否有消息需要回
return;
} //回复消息
client = (SocketChannel)key.channel(); // 拿到客户端通道
sendBuffer.clear();
sendBuffer.put(new String(sessionMsg.get(key)+ "你好,你的请求已完成").getBytes()); //设置读取位
sendBuffer.flip(); // 缓冲区的内容写出去
client.write(sendBuffer); // 再次注册入selector
client.register(selector, SelectionKey.OP_READ);
}
} catch (IOException e) {
try { //读取key事件时,遇到客户端异常下线,不会引起异常
key.cancel();
client.socket().close();
client.close();
} catch (IOException e1) {
e1.printStackTrace();
}
} } public static void main(String[] args) {
try {
NIOServer server = new NIOServer();
server.listen();
} catch (IOException e) {
e.printStackTrace();
}
}
}

CLIENT

package com.study.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.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set; public class NIOClient {
private static int port = 9995; //端口 // 1.第一个是服务
private static ServerSocketChannel clientC; // 2.第二个是多路复用器
private static Selector selector; // 3.第三个就是缓冲区buffer
// 信息接收
ByteBuffer rcBuffer = ByteBuffer.allocate(1024);
// 信息写出
ByteBuffer sendBuffer = ByteBuffer.allocate(1024); // 4.维护一个事件标签集合,和selector配合使用
Map<SelectionKey,String> sessionMsg = new HashMap<SelectionKey,String>(); // 初始化
public NIOClient() throws IOException{
clientC = ServerSocketChannel.open(); // 打开服务端,服务端临听端口
clientC.socket().bind(new InetSocketAddress(port)); //
clientC.configureBlocking(false); //设置为非阻塞,默认是true
selector = Selector.open(); //实例化多路复用器 //server注册上多路复用器之后,多路复用器才会为server工作,实现一个server为成千上万个client工作
//selector和事件标签Selectionkey是一起应用的,第一次服务器,是接受,Accept
clientC.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("NIO服务器已启动,且监听的端口是" + port); //this.port范围加大
} // 监听请求方法
public void listen() throws IOException{
while(true){
// 进来就是通过多路复用器selector,来看是否有注册事件
int eventCount = selector.select(); // 已注册事件数量
if(eventCount == 0){
// selector继续轮询,NIO的内部机制就是不断轮询注册到selector上面的多个channel
continue;
} // 拿到事件集合,SelectorKey的作用就是获取这些就绪通道的集合
Set<SelectionKey> keys = selector.selectedKeys(); //迭代
Iterator<SelectionKey> iterator = keys.iterator();
while(iterator.hasNext()){
SelectionKey key = iterator.next(); //这个事件就是客户端的一个读或者写
process(key); //处理事件
//处理完后,事件移出集合
iterator.remove();
}
}
} // 处理客户端事件
private void process(SelectionKey key) {
// 处理客户端请求,定义客户端对象
SocketChannel client = null;
try { // 判断key是否是有效的
if(key.isConnectable()){
client = (SocketChannel)key.channel(); // 拿到客户端通道
client.configureBlocking(false); //设置为非阻塞
client.register(selector , SelectionKey.OP_READ); //读取客户端请求,事件标签类型改为读取 } else if(key.isValid() && key.isReadable()){ //是否是可读的
// 读到缓冲区
rcBuffer.clear();
client = (SocketChannel)key.channel(); // 拿到客户端通道
int len = client.read(rcBuffer); //读取的长度
if(len > 0){ //读到内容
String msg = new String(rcBuffer.array() , 0 ,len);
sessionMsg.put(key, msg);
// 告诉selector,已读完,下次可以写数据
client.register(selector, SelectionKey.OP_WRITE);
}
}else if(key.isValid() && key.isWritable()){
if(!sessionMsg.containsKey(key)){ //是否有消息需要回
return;
} //回复消息
client = (SocketChannel)key.channel(); // 拿到客户端通道
sendBuffer.clear();
sendBuffer.put(new String(sessionMsg.get(key)+ "你好,你的请求已完成").getBytes()); //设置读取位
sendBuffer.flip(); // 缓冲区的内容写出去
client.write(sendBuffer); // 再次注册入selector
client.register(selector, SelectionKey.OP_READ);
}
} catch (IOException e) {
try { //读取key事件时,遇到客户端异常下线,不会引起异常
key.cancel();
client.socket().close();
client.close();
} catch (IOException e1) {
e1.printStackTrace();
}
} } public static void main(String[] args) {
try {
NIOServer server = new NIOServer();
server.listen();
} catch (IOException e) {
e.printStackTrace();
}
}
}

NIO--2-代码的更多相关文章

  1. Java基础知识强化之IO流笔记72:NIO之 NIO核心组件(NIO使用代码示例)

    1.Java NIO 由以下几个核心部分组成: Channels(通道) Buffers(缓冲区) Selectors(选择器) 虽然Java NIO 中除此之外还有很多类和组件,Channel,Bu ...

  2. Java NIO 学习笔记

    为了防止无良网站的爬虫抓取文章,特此标识,转载请注明文章出处.LaplaceDemon/SJQ. http://www.cnblogs.com/shijiaqi1066/p/3344148.html ...

  3. nio简介

    上一篇  Java I/O演进与Linux网络I/O模型 一.传统BIO java传统bio编程概念: http://www.cnblogs.com/carl10086/p/6034563.html# ...

  4. 掌握NIO,程序人生

    就像新IO为java带来的革新那样,让我们也开启一段新的程序人生. 关键字:NIO,BIO,伪IO,AIO,多路复用选择器,通道,缓冲区,jdk研究,回调函数,高并发 java.nio 概述 历史背景 ...

  5. Netty5序章之BIO NIO AIO演变

    Netty5序章之BIO NIO AIO演变 Netty是一个提供异步事件驱动的网络应用框架,用以快速开发高性能.高可靠的网络服务器和客户端程序.Netty简化了网络程序的开发,是很多框架和公司都在使 ...

  6. Java NIO之网络编程

    最近在研究Java NIO和netty,曾经一度感觉很吃力,根本原因还是对操作系统.TCP/IP.socket编程的理解不到位. 不禁感叹,还是当初逃的课太多. 假如上天给我一次机会,能够再回到意气风 ...

  7. 操作系统层面聊聊BIO,NIO和AIO (epoll)

    BIO 有了Block的定义,就可以讨论BIO和NIO了.BIO是Blocking IO的意思.在类似于网络中进行read, write, connect一类的系统调用时会被卡住. 举个例子,当用re ...

  8. Netty序章之BIO NIO AIO演变

    Netty序章之BIO NIO AIO演变 Netty是一个提供异步事件驱动的网络应用框架,用以快速开发高性能.高可靠的网络服务器和客户端程序.Netty简化了网络程序的开发,是很多框架和公司都在使用 ...

  9. day 4 Socket 和 NIO Netty

    Scoket通信--------这是一个例子,可以在这个例子的基础上进行相应的拓展,核心也是在多线程任务上进行修改 package cn.itcast.bigdata.socket; import j ...

  10. Java NIO Socket编程实例

    各I/O模型优缺点 BIO通信模型 BIO主要的问题在于每当有一个新的客户端请求接入时,服务端必须创建一个新的线程处理新接入的客户端链路,一个线程只能处理一个客户端连接 线程池I/O编程 假如所有可用 ...

随机推荐

  1. I/O流、文件操作

    1)操作文件 Path和Files是在JavaSE7中新添加进来的类,它们封装了在用户机器上处理文件系统所需的所有功能.Path表示的一个目录名序列,其后还可以跟着一个文件名.路径中的第一个参数可以是 ...

  2. php+sqlserver处理读取decimal 类型数据,不满1的数字会去掉0的问题

    php+sqlserver处理读取decimal 类型数据,如果数据不满1,会去掉0的问题.比如读取的数据是 0.05,会显示 .05 function convert_number($number) ...

  3. [Cracking the Coding Interview] 4.6 Successor 后继节点

    Write an algorithm to find the 'next' node(i.e. in-order successor) of a given node in a binary sear ...

  4. MongoDB入门---简介

    最近呢,刚好有一些时间,所以就学习了一下新的数据库类型MongoDB.要想了解这个MongoDB,我们首先需要了解一个概念,那就是nosql(not only sql).一下就是官方的概念: NoSQ ...

  5. 一步一步学Linq to sql(二):DataContext与实体

    DataContext DataContext类型(数据上下文)是System.Data.Linq命名空间下的重要类型,用于把查询句法翻译成SQL语句,以及把数据从数据库返回给调用方和把实体的修改写入 ...

  6. Java常考面试题

    Java常考面试题 1. 什么是Java虚拟机?为什么Java被称作是“平台无关的编程语言”? 答:Java虚拟机是一个可以执行Java字节码的虚拟机进程.Java源文件被编译成能被Java虚拟机执行 ...

  7. VHDL入门学习-程序组成

    1. VHDL程序的组成 一个完整的VHDL程序是以下五部分组成的: 2. 库(LIBRARY):比较好理解,调用系统已有的库,WORK库就是用户当前编辑文件所在的文件夹, IEEE库:由IEEE(美 ...

  8. onenet基础通信套件返回+CIS ERROR: 50的问题解决

    1. 场景分析,主要问题就是有些操作返回+CIS ERROR: 50 2. 看了一下在AT+MIPLOBSERVERSP这个指令里面是没有返回+CIS ERROR: 50的错误类型的,所以应该是在解析 ...

  9. 虚拟现实-VR-UE4-创建C++版工程

    首先,创建C++版本的UE4 项目工程,我使用的是4.12.3版本,据了解,新版本后面的编译都是vs2015 所以,想要创建C++版本的工程,就需要安装vs2015 至于vs2015的安装,自己百度吧 ...

  10. Python简要标准库(3)

    shelve 若只需要一个简单的存储方案,那么shelve模块可以满足你大部分的需要,你所需要的只是为它提供文件名.shelve中唯一有趣的函数是open,在调用的时候他会返回一个Shelf对象 注意 ...