专栏首页xdecodeNetty与传统Server对比

Netty与传统Server对比

前言

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

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

传统Socket / OIO

 1 public class OioServer {
 2 
 3     @SuppressWarnings("resource")
 4     public static void main(String[] args) throws Exception {
 5 
 6         ExecutorService newCachedThreadPool = Executors.newCachedThreadPool();
 7         //创建socket服务,监听10101端口
 8         ServerSocket server=new ServerSocket(10101);
 9         System.out.println("服务器启动!");
10         while(true){
11             //获取一个套接字(阻塞)
12             final Socket socket = server.accept();
13             System.out.println("来个一个新客户端!");
14             newCachedThreadPool.execute(new Runnable() {
15                 
16                 @Override
17                 public void run() {
18                     //业务处理
19                     handler(socket);
20                 }
21             });
22             
23         }
24     }
25     
26     /**
27      * 读取数据
28      * @param socket
29      * @throws Exception
30      */
31     public static void handler(Socket socket){
32             try {
33                 byte[] bytes = new byte[1024];
34                 InputStream inputStream = socket.getInputStream();
35                 
36                 while(true){
37                     //读取数据(阻塞)
38                     int read = inputStream.read(bytes);
39                     if(read != -1){
40                         System.out.println(new String(bytes, 0, read));
41                     }else{
42                         break;
43                     }
44                 }
45             } catch (Exception e) {
46                 e.printStackTrace();
47             }finally{
48                 try {
49                     System.out.println("socket关闭");
50                     socket.close();
51                 } catch (IOException e) {
52                     e.printStackTrace();
53                 }
54             }
55     }
56 }

缺点

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

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

类比图

NIOServer

  1 public class NIOServer {
  2     // 通道管理器
  3     private Selector selector;
  4 
  5     /**
  6      * 获得一个ServerSocket通道,并对该通道做一些初始化的工作
  7      * 
  8      * @param port
  9      *            绑定的端口号
 10      * @throws IOException
 11      */
 12     public void initServer(int port) throws IOException {
 13         // 获得一个ServerSocket通道
 14         ServerSocketChannel serverChannel = ServerSocketChannel.open();
 15         // 设置通道为非阻塞
 16         serverChannel.configureBlocking(false);
 17         // 将该通道对应的ServerSocket绑定到port端口
 18         serverChannel.socket().bind(new InetSocketAddress(port));
 19         // 获得一个通道管理器
 20         this.selector = Selector.open();
 21         // 将通道管理器和该通道绑定,并为该通道注册SelectionKey.OP_ACCEPT事件,注册该事件后,
 22         // 当该事件到达时,selector.select()会返回,如果该事件没到达selector.select()会一直阻塞。
 23         serverChannel.register(selector, SelectionKey.OP_ACCEPT);
 24     }
 25 
 26     /**
 27      * 采用轮询的方式监听selector上是否有需要处理的事件,如果有,则进行处理
 28      * 
 29      * @throws IOException
 30      */
 31     public void listen() throws IOException {
 32         System.out.println("服务端启动成功!");
 33         // 轮询访问selector
 34         while (true) {
 35             // 当注册的事件到达时,方法返回;否则,该方法会一直阻塞
 36             selector.select();
 37             // 获得selector中选中的项的迭代器,选中的项为注册的事件
 38             Iterator<?> ite = this.selector.selectedKeys().iterator();
 39             while (ite.hasNext()) {
 40                 SelectionKey key = (SelectionKey) ite.next();
 41                 // 删除已选的key,以防重复处理
 42                 ite.remove();
 43 
 44                 handler(key);
 45             }
 46         }
 47     }
 48 
 49     /**
 50      * 处理请求
 51      * 
 52      * @param key
 53      * @throws IOException
 54      */
 55     public void handler(SelectionKey key) throws IOException {
 56         
 57         // 客户端请求连接事件
 58         if (key.isAcceptable()) {
 59             handlerAccept(key);
 60             // 获得了可读的事件
 61         } else if (key.isReadable()) {
 62             handelerRead(key);
 63         }
 64     }
 65 
 66     /**
 67      * 处理连接请求
 68      * 
 69      * @param key
 70      * @throws IOException
 71      */
 72     public void handlerAccept(SelectionKey key) throws IOException {
 73         ServerSocketChannel server = (ServerSocketChannel) key.channel();
 74         // 获得和客户端连接的通道
 75         SocketChannel channel = server.accept();
 76         // 设置成非阻塞
 77         channel.configureBlocking(false);
 78 
 79         // 在这里可以给客户端发送信息哦
 80         System.out.println("新的客户端连接");
 81         // 在和客户端连接成功之后,为了可以接收到客户端的信息,需要给通道设置读的权限。
 82         channel.register(this.selector, SelectionKey.OP_READ);
 83     }
 84 
 85     /**
 86      * 处理读的事件
 87      * 
 88      * @param key
 89      * @throws IOException
 90      */
 91     public void handelerRead(SelectionKey key) throws IOException {
 92         // 服务器可读取消息:得到事件发生的Socket通道
 93         SocketChannel channel = (SocketChannel) key.channel();
 94         // 创建读取的缓冲区
 95         ByteBuffer buffer = ByteBuffer.allocate(1024);
 96         int read = channel.read(buffer);
 97         if(read > 0){
 98             byte[] data = buffer.array();
 99             String msg = new String(data).trim();
100             System.out.println("服务端收到信息:" + msg);
101             
102             //回写数据
103             ByteBuffer outBuffer = ByteBuffer.wrap("好的".getBytes());
104             channel.write(outBuffer);// 将消息回送给客户端
105         }else{
106             System.out.println("客户端关闭");
107             key.cancel();
108         }
109     }
110 
111     /**
112      * 启动服务端测试
113      * 
114      * @throws IOException
115      */
116     public static void main(String[] args) throws IOException {
117         NIOServer server = new NIOServer();
118         server.initServer(8000);
119         server.listen();
120     }
121 
122 }

优点

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

类比图

Netty Server

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Java过滤XSS脚本, 可通过Appscan扫描

    项目中有时会需要把一些报错或者解决方案直接返回给前端, 如果直接返回原字符串, 可能会被恶意传参来实现xss注入. 例如常规业务访问一个页面读取文件&file=...

    用户1216491
  • 初识AOP与动态代理

    AOP AOP是指在jvm运行时, 动态将代码切入到指定位置. OOP是一个维度上写代码, AOP是把他切开来, 变成立体的. 这样的好处是: 业务逻辑跟辅助逻...

    用户1216491
  • Java高并发之锁优化

    用户1216491
  • S3C6410启动过程分析

    存储子系统结构如下图所示。6410的存储系统包括两个内部存储器和两个外部存储器端口(参用户手册1.1节、2.1节、4.3节):

    用户4940323
  • [-算法篇-] 最大子序列和

    张风捷特烈
  • 40岁后学习编程:永远不会为时已晚

    万万没想到,正是水族饲养诱惑了43岁的Ken Hart进入网页设计世界。在有了多年在自己家中照顾水生生物的经验之后,Hart开始使用诸如Wix这样的免费网站建设...

    哲洛不闹
  • 40岁后学习编程:永远不会为时已晚

    万万没想到,正是水族饲养诱惑了43岁的Ken Hart进入网页设计世界。在有了多年在自己家中照顾水生生物的经验之后,Hart开始使用诸如Wix这样的免费网站建设...

    用户1667431
  • Webpack06-html打包插件html-webpack-plugin的使用

    在webpack4之前,默认集成该插件,无需安装 在webpack4之后,需要独立安装

    专注APP开发
  • 一个简单易用的图标字体库和CSS框架fontawesome

    font-awesome.css里对.fa-camera-retro:before的定义:\f083

    Jerry Wang
  • centos下安装python mysq

    yum -y install mysql-devel python-devel -y

    py3study

扫码关注云+社区

领取腾讯云代金券