从BIO到Netty的演变

从BIO到Netty的演变 前言

计算机网络可以说是每个学计算机的都绕不过去的一道坎。计算机网络到底有多么重要,你走到大学图书馆的计算机部分,翻开那些什么《从零开始:黑客XXX》,《黑客攻防从入门到放弃》等书籍,基本第一部分都是在谈论网络。你去一些X客论坛,上面的教程帖也基本都是从网络部分开始的。

相信每一位科班出身的,都学习过《计算机网络》这样书籍, 上过这样的课程。当然教师资源如何,我这里就不谈论,那一定又会引出一顿苦水。但是学习完这样的课程,我们还是对计算机网络感到十分迷茫。这时候的我们可以背下网络七层模型,网络五层模型等,了解局域网,IP等基本地概念,但是计算机网络对于我们来说,还是一个十分空荡荡的名词。

为了更好地了解网络(绝对不是因为那时候很迷黑客的缘故),我决定参加高级网络工程师的考试。通过网络工程师的我对计算机网络有了更为深入的理解,开始将自己的计算机网络体系从概念上勾连起来。也许我可以看懂其中的一些路由规则,甚至看懂一些路由分发的论文。但是我依旧只是站在理论的角度,去理解计算机网络。

到了工作的时候,开始了解Socket编程,开始参与各种实际生产环境的编程。这个时候的我开始对网络有了虽然简单,但是十分真实的接触。计算机网络不再只是停留在书本中的概念,而是我用以实现业务目标的切实手段。

随着工作中开始负责物联网项目的建设,我对网络中的各种协议开始有了自己的认识,甚至可以自己实现网络协议规范的代码落地。于此同时,由于对网络交互的性能要求,我不再只是会使用BIO网络编程,我开始使用NIO网络编程。

为了自己的知识储备,也是为了满足自己的好奇心,我查找了许多的资料,也报了许多课程,去学习网络编程。而我正好周六完成了软考的又一次考试,所以接下来有一定空闲时间的我,接下来会继续整理我的知识,并将它写成博客。

这篇博客的主要内容就是按照演变的顺序,写下BIO->NIO->Reactor->Netty这样的四个里程碑。这也是大佬们推荐的计算机网络编程的学习路线。不过这次只是给个整体的认识以及demo,更为深入的原理探究,会放在后面。

BIO 介绍

几乎每个人都是BIO开始的计算机网络编程,而其中大部分也永远地留在了这个计算机网络编程的模型。

优点

理解简单

实现简单

要求较低

缺点

性能低

瓶颈低

扩展难

代码示例(BIO下TCP)

这里给出一些简单的demo,供大家认识。

BIO_Client package tech.jarry.learning.netease; import java.io.IOException; import java.io.OutputStream; import java.net.Inet4Address; import java.net.InetSocketAddress; import java.net.Socket; import java.nio.charset.Charset; import java.util.Scanner; /** * @Description: * @Author: jarry */ public class BIOClient { private static final Charset charset = Charset.forName("utf-8"); public static void main(String[] args) throws IOException { Socket socket = new Socket(); // Socket socket = new Socket("localhost", 8080); // 我还以为可以的。但是貌似上面的8080表示目标端口,而下面的8080表示源端口(发送端口) // socket.bind(new InetSocketAddress("localhost", 8080)); // 后来才去确定,.bind是用于绑定源信息,而.connect是用于绑定目标信息 socket.connect(new InetSocketAddress(Inet4Address.getLocalHost(), 8080)); OutputStream outputStream = socket.getOutputStream(); Scanner scanner = new Scanner(System.in); System.out.println("please input: "); String msg = scanner.nextLine(); outputStream.write(msg.getBytes(charset)); scanner.close(); outputStream.close(); socket.close(); } } BIO_ServerV1 package tech.jarry.learning.netease; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.InetSocketAddress; import java.net.ServerSocket; import java.net.Socket; /** * @Description: BIO模型中Server端的简单实现 * @Author: jarry */ public class BIOServer { public static void main(String[] args) throws IOException { ServerSocket serverSocket = new ServerSocket(); serverSocket.bind(new InetSocketAddress(8080)); System.out.println("server has started"); while (!serverSocket.isClosed()) { Socket requestClient = serverSocket.accept(); System.out.println("server get a connection: " + requestClient.toString()); InputStream requestInputStream = requestClient.getInputStream(); BufferedReader reader = new BufferedReader(new InputStreamReader(requestInputStream)); String msg; while ((msg = reader.readLine()) != null) { if (msg.length() == 0) { break; } System.out.println(msg); } System.out.println("server has receive a message from: " + requestClient.toString()); requestInputStream.close(); requestClient.close(); } serverSocket.close(); } } BIO_ServerV2 package tech.jarry.learning.netease; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.InetSocketAddress; import java.net.ServerSocket; import java.net.Socket; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * @Description: 直接对原有代码BIOServer进行暴力修改,将其阻塞部分,通过多线程实现异步处理 * @Author: jarry */ public class BIOServer1 { private static ExecutorService executorService = Executors.newCachedThreadPool(); public static void main(String[] args) throws IOException { ServerSocket serverSocket = new ServerSocket(); serverSocket.bind(new InetSocketAddress(8080)); System.out.println("server has started"); while (!serverSocket.isClosed()) { Socket requestClient = serverSocket.accept(); System.out.println("server get a connection: " + requestClient.toString()); executorService.submit(new Runnable() { @Override public void run() { InputStream requestInputStream = null; try { requestInputStream = requestClient.getInputStream(); } catch (IOException e) { e.printStackTrace(); } BufferedReader reader = new BufferedReader(new InputStreamReader(requestInputStream)); String msg = null; while (true) { try { if (!((msg = reader.readLine()) != null)) { break; } } catch (IOException e) { e.printStackTrace(); } if (msg.length() == 0) { break; } System.out.println(msg); } System.out.println("server has receive a message from: " + requestClient.toString()); try { requestInputStream.close(); requestClient.close(); } catch (IOException e) { e.printStackTrace(); } } }); } serverSocket.close(); } /** * 运行结果分析: * server has started * server get a connection: Socket[addr=http://www.likecs.com/10.0.75.1,port=64042,localport=8080] * server get a connection: Socket[addr=http://www.likecs.com/10.0.75.1,port=64052,localport=8080] * server get a connection: Socket[addr=http://www.likecs.com/10.0.75.1,port=64061,localport=8080] * 123 * server has receive a message from: Socket[addr=http://www.likecs.com/10.0.75.1,port=64042,localport=8080] * 456 * server has receive a message from: Socket[addr=http://www.likecs.com/10.0.75.1,port=64052,localport=8080] * 789 * server has receive a message from: Socket[addr=http://www.likecs.com/10.0.75.1,port=64061,localport=8080] */ } BIO_ServerV3 package tech.jarry.learning.netease; import java.io.*; import java.net.InetSocketAddress; import java.net.ServerSocket; import java.net.Socket; /** * @Description: 直接对原有代码BIOServer进行暴力修改,增加了其http格式的返回,确保浏览器可以正常访问 * @Author: jarry */ public class BIOServer2 { public static void main(String[] args) throws IOException { ServerSocket serverSocket = new ServerSocket(); serverSocket.bind(new InetSocketAddress(8080)); System.out.println("server has started"); while (!serverSocket.isClosed()) { Socket requestClient = serverSocket.accept(); System.out.println("server get a connection: " + requestClient.toString()); InputStream requestInputStream = requestClient.getInputStream(); BufferedReader reader = new BufferedReader(new InputStreamReader(requestInputStream)); String msg; while ((msg = reader.readLine()) != null) { if (msg.length() == 0) { break; } System.out.println(msg); } System.out.println("server has receive a message from: " + requestClient.toString()); // 返回数据,并确保可以被http协议理解 OutputStream outputStream = requestClient.getOutputStream(); outputStream.write("HTTP/1.1 200 OK\r\r".getBytes("utf-8")); outputStream.write("Content-Length: 11\r\n\r\n".getBytes("utf-8")); outputStream.write("Hello World".getBytes("utf-8")); outputStream.flush(); requestInputStream.close(); outputStream.close(); requestClient.close(); } serverSocket.close(); } /** * 运行结果分析: */ // server has started // server get a connection: Socket[addr=http://www.likecs.com/0:0:0:0:0:0:0:1,port=63008,localport=8080] // GET / HTTP/1.1 // Host: localhost:8080 // Connection: keep-alive // Cache-Control: max-age=0 // Upgrade-Insecure-Requests: 1 // User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36 // Sec-Fetch-Mode: navigate // Sec-Fetch-User: ?1 // Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3 // Sec-Fetch-Site: none // Accept-Encoding: gzip, deflate, br // Accept-Language: en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7 // Cookie: Webstorm-c7a2b5a2=b5e53f87-54cc-41d5-a21f-c7be3056dfe8; centcontrol_login_token=09E8A6B6888CB0B7A9F89AB3DB5FAFE4 // server has receive a message from: Socket[addr=http://www.likecs.com/0:0:0:0:0:0:0:1,port=63008,localport=8080] // server get a connection: Socket[addr=http://www.likecs.com/0:0:0:0:0:0:0:1,port=63009,localport=8080] // GET /favicon.ico HTTP/1.1 // Host: localhost:8080 // Connection: keep-alive // Pragma: no-cache // Cache-Control: no-cache // Sec-Fetch-Mode: no-cors // User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36 // Accept: image/webp,image/apng,image/*,*/*;q=0.8 // Sec-Fetch-Site: same-origin // Referer: :8080/ // Accept-Encoding: gzip, deflate, br // Accept-Language: en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7 // Cookie: Webstorm-c7a2b5a2=b5e53f87-54cc-41d5-a21f-c7be3056dfe8; centcontrol_login_token=09E8A6B6888CB0B7A9F89AB3DB5FAFE4 // server has receive a message from: Socket[addr=http://www.likecs.com/0:0:0:0:0:0:0:1,port=63009,localport=8080] }

上面的代码是一套的,可以进行Server与Client的通信,功能较为简单。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpfgfx.html