Netty与传统Server对比
时间:2022-04-24
本文章向大家介绍Netty与传统Server对比,主要内容包括前言、传统Socket / OIO、NIOServer、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
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- RecyclerView嵌套RecyclerView完美实现京东tab吸顶效果
- Android使用SmsManager实现短信发送功能
- Kotlin结合Rxjava+Retrofit实现极简网络请求的方法
- 用Android Studio3.0新功能加快构建速度
- Android实现图片添加阴影效果的2种方法
- Android Webview与ScrollView的滚动兼容及留白处理的方法
- Android AOP框架AspectJ使用详解
- android仿Adapter实现自定义PagerAdapter方法示例
- android绘制几何图形的实例代码
- Android ListView控件使用方法
- Android开发之Android.mk模板的实例详解
- android实现文件下载功能
- Android实现可以展开的TextView
- 详解android 用webview加载网页(https和http)
- Android自定义网络连接工具类HttpUtil