前言


本文旨在介绍传统Socket服务端与NIO服务端的差异.

以餐厅服务员简单举例,每个客人对应一个请求.

传统Socket / OIO


 public class OioServer {

     @SuppressWarnings("resource")
public static void main(String[] args) throws Exception { ExecutorService newCachedThreadPool = Executors.newCachedThreadPool();
//创建socket服务,监听10101端口
ServerSocket server=new ServerSocket(10101);
System.out.println("服务器启动!");
while(true){
//获取一个套接字(阻塞)
final Socket socket = server.accept();
System.out.println("来个一个新客户端!");
newCachedThreadPool.execute(new Runnable() { @Override
public void run() {
//业务处理
handler(socket);
}
}); }
} /**
* 读取数据
* @param socket
* @throws Exception
*/
public static void handler(Socket socket){
try {
byte[] bytes = new byte[1024];
InputStream inputStream = socket.getInputStream(); while(true){
//读取数据(阻塞)
int read = inputStream.read(bytes);
if(read != -1){
System.out.println(new String(bytes, 0, read));
}else{
break;
}
}
} catch (Exception e) {
e.printStackTrace();
}finally{
try {
System.out.println("socket关闭");
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

缺点

单线程情况下只能有一个客户端

用线程池可以有多个客户端连接,但是非常消耗性能

类比图

NIOServer


 public class NIOServer {
// 通道管理器
private Selector selector; /**
* 获得一个ServerSocket通道,并对该通道做一些初始化的工作
*
* @param port
* 绑定的端口号
* @throws IOException
*/
public void initServer(int port) throws IOException {
// 获得一个ServerSocket通道
ServerSocketChannel serverChannel = ServerSocketChannel.open();
// 设置通道为非阻塞
serverChannel.configureBlocking(false);
// 将该通道对应的ServerSocket绑定到port端口
serverChannel.socket().bind(new InetSocketAddress(port));
// 获得一个通道管理器
this.selector = Selector.open();
// 将通道管理器和该通道绑定,并为该通道注册SelectionKey.OP_ACCEPT事件,注册该事件后,
// 当该事件到达时,selector.select()会返回,如果该事件没到达selector.select()会一直阻塞。
serverChannel.register(selector, SelectionKey.OP_ACCEPT);
} /**
* 采用轮询的方式监听selector上是否有需要处理的事件,如果有,则进行处理
*
* @throws IOException
*/
public void listen() throws IOException {
System.out.println("服务端启动成功!");
// 轮询访问selector
while (true) {
// 当注册的事件到达时,方法返回;否则,该方法会一直阻塞
selector.select();
// 获得selector中选中的项的迭代器,选中的项为注册的事件
Iterator<?> ite = this.selector.selectedKeys().iterator();
while (ite.hasNext()) {
SelectionKey key = (SelectionKey) ite.next();
// 删除已选的key,以防重复处理
ite.remove(); handler(key);
}
}
} /**
* 处理请求
*
* @param key
* @throws IOException
*/
public void handler(SelectionKey key) throws IOException { // 客户端请求连接事件
if (key.isAcceptable()) {
handlerAccept(key);
// 获得了可读的事件
} else if (key.isReadable()) {
handelerRead(key);
}
} /**
* 处理连接请求
*
* @param key
* @throws IOException
*/
public void handlerAccept(SelectionKey key) throws IOException {
ServerSocketChannel server = (ServerSocketChannel) key.channel();
// 获得和客户端连接的通道
SocketChannel channel = server.accept();
// 设置成非阻塞
channel.configureBlocking(false); // 在这里可以给客户端发送信息哦
System.out.println("新的客户端连接");
// 在和客户端连接成功之后,为了可以接收到客户端的信息,需要给通道设置读的权限。
channel.register(this.selector, SelectionKey.OP_READ);
} /**
* 处理读的事件
*
* @param key
* @throws IOException
*/
public void handelerRead(SelectionKey key) throws IOException {
// 服务器可读取消息:得到事件发生的Socket通道
SocketChannel channel = (SocketChannel) key.channel();
// 创建读取的缓冲区
ByteBuffer buffer = ByteBuffer.allocate(1024);
int read = channel.read(buffer);
if(read > 0){
byte[] data = buffer.array();
String msg = new String(data).trim();
System.out.println("服务端收到信息:" + msg); //回写数据
ByteBuffer outBuffer = ByteBuffer.wrap("好的".getBytes());
channel.write(outBuffer);// 将消息回送给客户端
}else{
System.out.println("客户端关闭");
key.cancel();
}
} /**
* 启动服务端测试
*
* @throws IOException
*/
public static void main(String[] args) throws IOException {
NIOServer server = new NIOServer();
server.initServer(8000);
server.listen();
} }

优点

利用Selector多路复用技术, 一个线程可以处理多个客户端.

类比图

Netty Server


Netty与传统Server对比的更多相关文章

  1. JDBC连接SQL server与ADO.NET连接Sql Server对比

    JDBC连接SQL server与ADO.NET连接Sql Server对比 1.JDBC连接SQL server 1)java方面目前有很多驱动能够驱动连接SQL servernet.   主流的有 ...

  2. 虚拟桌面基础架构(VDI)与终端服务和传统PC对比

    VDI(Virtual Desktop Infrastructure),即虚拟桌面基础架构,正迅速成为一个热门词汇,它将颠覆企业向终端用户交付应用的游戏规则.这篇专题就是想通过VDI与两种传统技术的对 ...

  3. Docker优势以及与传统虚拟机对比(1)

    docker优势 1.更快速地交付和部署: 2.更高的虚拟化(不需要额外的hypervisor支持,是内核级的虚拟化,实现更高的性能呢和效率): 3.更轻松的迁移和扩展: 4.更简单的管理  与传统的 ...

  4. (转)netty、mina性能对比分析

    转自: http://blog.csdn.net/mindfloating/article/details/8622930 流行 NIO Framework netty 和 mina 性能测评与分析 ...

  5. SQL Server 对比数据库差异

    一.视图和存储过程比较 [原理]利用系统表“sysobjects"和系统表“syscomments”,将数据库中的视图和存储过程进行对比.系统表"sysobjects"之 ...

  6. TCP粘包/拆包 ByteBuf和channel 如果没有Netty? 传统的多线程服务器,这个也是Apache处理请求的模式

    通俗地讲,Netty 能做什么? - 知乎 https://www.zhihu.com/question/24322387 谢邀.netty是一套在java NIO的基础上封装的便于用户开发网络应用程 ...

  7. Netty Client和Server端实现

    本文基于Nett4.0.26.Final版本浅析Client与Server端通讯,先看服务器端: public class Server { public static void run(int po ...

  8. Netty(一):server启动流程解析

    netty作为一个被广泛应用的通信框架,有必要我们多了解一点. 实际上netty的几个重要的技术亮点: 1. reactor的线程模型; 2. 安全有效的nio非阻塞io模型应用; 3. pipeli ...

  9. netty写Echo Server & Client完整步骤教程(图文)

    1.创建Maven工程 1.1 父节点的pom.xml代码(root pom文件) 1 <?xml version="1.0" encoding="UTF-8&qu ...

随机推荐

  1. 修改Jupyter notebook的启动目录

    修改Jupyter notebook的启动目录 1. 在控制台输入以下命令,检查Jupyter notebook的安装目录 jupyter notebook --generate-config ​ 如 ...

  2. 如何用java创建一个jdbc程序

    第一个jdbc程序 JDBC简介 Java数据库连接(Java Database Connectivity,JDBC),是一种用于执行SQL语句的Java API,它由一组用Java编程语言编写的类和 ...

  3. Lua 和 C 交互中虚拟栈的操作

    Lua 和 C 交互中虚拟栈的操作 /* int lua_pcall(lua_State *L, int nargs, int nresults, int msgh) * 以保护模式调用具有" ...

  4. win7旗舰版安装IIS

    1.在控制面板中:程序->打开或关闭Windows功能 2.在弹出的对话窗中,在“Internet服务信息”中作如下勾选(打钩的为全选) 点击确定后安装. 3.安装成功后回到控制面板->系 ...

  5. D - MUH and Cube Walls

    D. MUH and Cube Walls   Polar bears Menshykov and Uslada from the zoo of St. Petersburg and elephant ...

  6. Windows Message Queue

    Windows Message Queue Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Other ...

  7. Assigning Workstations

    题目链接:http://vjudge.net/contest/127404#problem/A /* 给你n个数字,让你找出一个最小的数字,这个数字不在这些数字中出现的 ,注意:这个数字如果各个位上的 ...

  8. Grunt打包seajs项目

    在使用seajs时,常常将若干脚本分为多次require进来,这样开发中比较方便,但是,会增加http请求次数,在生产环境中需要进行打包合并.压缩等操作. 以Grunt构建工具为例,对一个seajs项 ...

  9. sublime中配置Java 环境

    1.线安装jdk,并配置好环境变量2.创建批处理或Bash Shell脚本文件打开任意的文本编辑器,输入下面的内容,并保存为runJava.bat文件,然后把runJava.bat批处理文件移动到JD ...

  10. JS是按值传递还是按引用传递?【转载】

    最近遇到个有趣的问题:“JS中的值是按值传递,还是按引用传递呢?” 在分析这个问题之前,我们需了解什么是按值传递(call by value),什么是按引用传递(call by reference). ...