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. 魔板 Magic Squares(广搜,状态转化)

    题目背景 在成功地发明了魔方之后,鲁比克先生发明了它的二维版本,称作魔板.这是一张有8个大小相同的格子的魔板: 1 2 3 4 8 7 6 5 题目描述 我们知道魔板的每一个方格都有一种颜色.这8种颜 ...

  2. 独木舟(51NOD 1432 )

    n个人,已知每个人体重.独木舟承重固定,每只独木舟最多坐两个人,可以坐一个人或者两个人.显然要求总重量不超过独木舟承重,假设每个人体重也不超过独木舟承重,问最少需要几只独木舟? Input 第一行包含 ...

  3. Linux 下文件压缩与解压命令详解

    tar 命令 -c 建立压缩档案 -x 解压 -t 查看内容 -r 向压缩归档文件末尾追加文件 -u 更新原压缩包中的文件 这五个是独立的命令,压缩解压都要用到其中一个,可以和别的命令连用但只能用其中 ...

  4. Spring Boot2.4双数据源的配置

    相较于单数据源,双数据源配置有时候在数据分库的时候可能更加有利 但是在参考诸多博客以及书籍(汪云飞的实战书)的时候,发现对于spring boot1.X是完全没问题的,一旦切换到spring boot ...

  5. idea中创建web项目搭建Hibernate框架连接oracle数据库

    hibernate框架 hibernate是数据化持久工具,也是一个开源代码的ORM解决方案.hibernate内部封装了通过jdbc访问数据库的操作,向商场应用提供面向对象的数据访问api. hib ...

  6. 【redis常用的键值操作及性能优化】

    服务端 启动redis服务 { // -a:指定密码 -h:指定主机 -p:指定端口 } //让redis 服务中断崩溃 //保存和关闭 //后台备份 //设置登录密码 //redis-benchma ...

  7. isolate-user-vlan隔离用户vlan的配置

    lab1 根据项目需求搭建好拓扑图: 首先,配置sw2,在E0/4/0接口上创建vlan20,并将该vlan接口配置成带有ip地址的类以太接口 其次,在E0/4/1接口上加入vlan2,同理,E0/4 ...

  8. php-5.6.26源代码 - hash存储结构 - 初始化

    初始化 有指定析构函数,在销毁hash的时候会调用,如:“类似extension=test.so扩展”也是存放在HashTable中的,“类似extension=test.so扩展”的module_s ...

  9. 图的遍历(Python实现)

    图的遍历(Python实现) 记录两种图的遍历算法——广度优先(BFS)与深度优先(DFS). 图(graph)在物理存储上采用邻接表,而邻接表是用python中的字典来实现的. 两种遍历方式的代码如 ...

  10. 004---Linux系统设置

    Linux版本相关命令 查看系统版本:cat /etc/redhat-release 查看系统内核版本以及位数:uname -r [root@hostname1 ~]# cat /etc/redhat ...