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. HDFS的存储策略

    本文介绍hdfs的存储策略 内容译自:http://hadoop.apache.org/docs/r2.8.0/hadoop-project-dist/hadoop-hdfs/ArchivalStor ...

  2. oracle 11g grid软件安装[20180121]

      实验环境:     系统->Redhat 6.5     Oracle软件版本->oracle 11.2.0.4.0        系统初始化     设定hosts主机名和对应IP地 ...

  3. Java实现文件的上传下载

    文件上传,下载的方法: 上传代码 /** * 文件上传.保存 * * @param mapping * @param form * @param request * @param response * ...

  4. MongoDB学习(1)--安装,基本curd操作

    知识点: 1-MongoDB 安装,启动和卸载 2-基本概念 3-基本的增删改查操作(CURD) 来回顾总结一把学习的mongodb,如果有javascript基础,学习"芒果DB" ...

  5. Python入门学习笔记4:他人的博客及他人的学习思路

    看其他人的学习笔记,可以保证自己不走弯路.并且一举两得,即学知识又学方法! 廖雪峰:https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958 ...

  6. (转)Updates were rejected because the tip of your current branch is behind

    刚创建的github版本库,在push代码时出错: $ git push -u origin masterTo git@github.com:******/Demo.git ! [rejected] ...

  7. STM32进阶之串口环形缓冲区实现(转载)

    转载自微信公众号“玩转单片机”,感谢原作者“杰杰”. 队列的概念 在此之前,我们来回顾一下队列的基本概念:队列 (Queue):是一种先进先出(First In First Out ,简称 FIFO) ...

  8. Eclipse报错:An internal error occurred during: "Building workspace". Java heap space),卡死解决办法

    在项目工程的根目录下,找到.project,用记事本打开,把两处删除掉: 第一处: <buildCommand> <name>org.eclipse.wst.jsdt.core ...

  9. 开源版本 hadoop-2.7.5 + apache-hive-2.1.1 + spark-2.3.0-bin-hadoop2.7整合使用

    一,开源软件版本: hadoop版本 : hadoop-2.7.5 hive版本 :apache-hive-2.1.1 spark版本: spark-2.3.0-bin-hadoop2.7 各个版本到 ...

  10. Service ANR问题

    错误堆栈: ActivityManager: ANR in com.oppo.reader PID: 8071 Reason: executing service com.oppo.reade//co ...