公司的一些项目采用了netty框架,为了加速适应公司开发,本博主认真学习netty框架,前一段时间主要看了看书,发现编程这东西,不上手还是觉得差点什么,于是为了加深理解,深入学习,本博主还是决定多动手,一方面记录一些总结性的思考性东西,另一方面也为日后复习查看留下一些东西。

  那么废话少说,现在开始,首先在进入netty学习之前,我们是要认识一下IO并引出NIO的概念。

  与IO相关的几种编程及特点分为:

编程类别 特点
传统BIO编程

典型的一请求一应答模型,一个请求新建一个线程,应答完成线程销毁,线程个数和客户端并发访问呈现1:1的正比关系,当线程数膨胀之后,虚拟机性能下降明显,随着并发量继续增大,线程耗尽就会出现线程堆栈溢出,创建新线程失败,并最终宕机。该模型无法满足高性能高并发的场景。

伪异步IO编程

伪异步IO是对BIO的优化,引入线程池和消息队列,改善了传统BIO编程,但是其底层仍然是BIO模型,该模型引入线程池后界定了线程的数量,N个线程处理M个客户端请求,M可以远远大于N,线程池灵活调配线程资源,有最大线程数限制,避免了一个客户端请求创建一个线程的弊端,不会发生高并发访问下的线程资源耗尽而造成堆栈溢出或宕机的问题。

其不利因素是当一个客户端请求没有处理完成时,如IO读写或网络慢时,会造成任务队列中的任务一直处于等待状态,被阻塞了。当线程池中所有线程都满程处于阻塞状态时,就无法接收客户端新的请求,请求总是超时,此时可以认为是系统崩溃。

NIO编程

NIO模型引入了缓冲区Buffer,所有数据的读写都是用缓冲区处理的。引入channel通道,和selector多路复用器。

客户端发起的连接操作是异步的,可以通过在多路复用器注册OP_CONNECT等待后续结果,不需要像之前的客户端那样被同步阻塞,

socketchannel的读写都是一步的,如果没有可以读写的数据他不会同步等待,直接返回,这样I/O通信线程就可以处理其他的链路,不需要同步等待这个链路可用;

Selector线程可以同时处理成千上万个客户端连接,而且性能不会随客户端的增加而线性下降,非常适合高性能、高负载的网络服务器。

AIO编程

AIO是NIO2.0,它引入了异步通道概念,提供了异步文件通道和异步套接字通道的实现。异步通道提供了java.util.concurrent.Future类来表示异步操作的结果。

在执行异步操作时候传入一个java.io.channels.

CompletionHandler接口的实现类作为操作完成的回调。

NIO2.0的异步套接字通道是真正的异步非阻塞I/O,它不需要通过多路复用器Selector对注册的通道进行轮询操作即可实现异步读写,从而简化了NIO的编程模型。

现在看看逐个看看相关模型和代码:

BIO模型

传统的BIO代码 时间服务端

package com.example.biodemo;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket; public class TimeServer {
public static void main(String[] args) throws IOException {
int port = 8090;
if (args != null && args.length > 0) {
try {
port = Integer.valueOf(args[0]);
} catch (NumberFormatException e) {
port = 8090;
}
}
ServerSocket server = null;
try {
server = new ServerSocket(port);
System.out.println("the timeServer is start in port :" + port);
Socket socket = null;
while (true) {
socket = server.accept();
new Thread(new TimeServerHandler(socket)).start();
}
} finally {
if (server != null) {
System.out.println("the time server close");
server.close();
server = null;
}
} }
}

传统BIO 时间处理

package com.example.biodemo;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket; public class TimeServerHandler implements Runnable {
private Socket socket; public TimeServerHandler(Socket socket) {
this.socket = socket;
} @Override
public void run() {
BufferedReader in = null;
PrintWriter out = null;
try {
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
out = new PrintWriter(this.socket.getOutputStream(), true);
String currentTime = null;
String body = null;
while (true) {
body = in.readLine();
if (body == null) {
break;
}
System.out.println("the time server receive order:" + body);
currentTime = "QUERY TIME ORDER".equalsIgnoreCase(body) ? new java.util.Date(System.currentTimeMillis()).toString() : "bad order";
out.println(currentTime); }
} catch (Exception e) {
if (in != null) {
try {
in.close();
} catch (IOException el) {
el.printStackTrace();
}
}
if (out != null) {
out.close();
out = null;
}
if (this.socket != null) {
try {
this.socket.close();
} catch (IOException e1) {
e1.printStackTrace();
}
this.socket = null;
}
}
}
}

  客户端代码

 package com.example.biodemo;

 import java.io.*;
import java.net.Socket; public class TimeClient {
public static void main(String[] args) {
int port = 8090;
if (args != null && args.length > 0) {
try {
port = Integer.valueOf(args[0]);
} catch (NumberFormatException ne) {
port = 8090;
}
}
Socket socket = null;
BufferedReader in = null;
PrintWriter out = null;
try {
socket = new Socket("127.0.0.1", port);
System.out.println(socket.getInputStream());
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
out = new PrintWriter(socket.getOutputStream(), true);
out.println("QUERY TIME ORDER");
System.out.println("send order 2 server succeed.");
String resp = in.readLine();
System.out.println("now is :" + resp);
} catch (IOException e1) { } finally {
if (out != null) {
out.close();
out = null;
} if (in != null) {
try {
in.close();
} catch (IOException e2) {
e2.printStackTrace();
}
in = null;
if (socket != null) {
try {
socket.close();
} catch (IOException e3) {
e3.printStackTrace();
} }
socket = null;
} }
}
}

启动服务端

启动客户端

再看看服务端

整个过程是:服务端先在某一端口启动服务,本博主是在8090上启动,启动后,客户端启动,发送请求,请求被服务端接收后,进行逻辑处理,并将逻辑处理结果返回,这里的逻辑处理结果是当前时间,返回的结果客户端接收后显示出来。这就是一个典型的BIO模型。

netty权威指南学习笔记一——NIO入门(1)BIO的更多相关文章

  1. netty权威指南学习笔记一——NIO入门(3)NIO

    经过前面的铺垫,在这一节我们进入NIO编程,NIO弥补了原来同步阻塞IO的不足,他提供了高速的.面向块的I/O,NIO中加入的Buffer缓冲区,体现了与原I/O的一个重要区别.在面向流的I/O中,可 ...

  2. netty权威指南学习笔记一——NIO入门(4)AIO

    NIO2.0引入了新的异步通道的概念,并提供了异步文件通道和异步套接字通道的实现.异步通道提供以下两种方式获取操作结果. 1.通过java.util.concurrent.Future 类来表示异步操 ...

  3. netty权威指南学习笔记一——NIO入门(2)伪异步IO

    在上一节我们介绍了四种IO相关编程的各个特点,并通过代码进行复习了传统的网络编程代码,伪异步主要是引用了线程池,对BIO中服务端进行了相应的改造优化,线程池的引入,使得我们在应对大量客户端请求的时候不 ...

  4. netty权威指南学习笔记二——netty入门应用

    经过了前面的NIO基础知识准备,我们已经对NIO有了较大了解,现在就进入netty的实际应用中来看看吧.重点体会整个过程. 按照权威指南写程序的过程中,发现一些问题:当我们在定义handler继承Ch ...

  5. netty权威指南学习笔记六——编解码技术之MessagePack

    编解码技术主要应用在网络传输中,将对象比如BOJO进行编解码以利于网络中进行传输.平常我们也会将编解码说成是序列化/反序列化 定义:当进行远程跨进程服务调用时,需要把被传输的java对象编码为字节数组 ...

  6. netty权威指南学习笔记八——编解码技术之JBoss Marshalling

    JBoss Marshalling 是一个java序列化包,对JDK默认的序列化框架进行了优化,但又保持跟java.io.Serializable接口的兼容,同时增加了一些可调参数和附加特性,这些参数 ...

  7. netty权威指南学习笔记五——分隔符和定长解码器的应用

    TCP以流的方式进行数据传输,上层应用协议为了对消息进行区分,通常采用以下4中方式: 消息长度固定,累计读取到长度综合为定长LEN的报文后,就认为读取到了一个完整的消息,将计数器置位,重新开始读取下一 ...

  8. netty权威指南学习笔记三——TCP粘包/拆包之粘包现象

    TCP是个流协议,流没有一定界限.TCP底层不了解业务,他会根据TCP缓冲区的实际情况进行包划分,在业务上,一个业务完整的包,可能会被TCP底层拆分为多个包进行发送,也可能多个小包组合成一个大的数据包 ...

  9. netty权威指南学习笔记七——编解码技术之GoogleProtobuf

    首先我们来看一下protobuf的优点: 谷歌长期使用成熟度高: 跨语言支持多种语言如:C++,java,Python: 编码后消息更小,更利于存储传输: 编解码性能高: 支持不同协议版本的兼容性: ...

随机推荐

  1. linux服务器上安装jdk8的两种方法

    这里介绍两种安装方式: yum安装(力荐) 从官网下载包安装 获得一台linux服务器 要在linux下安装jdk,首先你得先有一台linux服务器,虚拟机或者租一台都可以   yum安装jdk 在l ...

  2. redis服务器性能优化

    1.系统内存OOM优化 vm.overcommit_memory Redis会占用非常大内存,所以通常需要关闭系统的OOM,方法为将“/proc/sys/vm/overcommit_memory”的值 ...

  3. 「JSOI2010」满汉全席

    前言 由于蒟蒻才刚开始学 \(\text{2-SAT}\),所以题解中有的地方可能不够精炼,望多包涵! 题目描述 题目意思很简单,标准的\(\text{2-SAT}\)问题模型.那么我们就先来介绍一下 ...

  4. MySQL 之与Python相关

    一.python 操作mysql import pymysql ''' # 1.基本语法 # (1) 连接数据库 # conn = pymysql.connect(host = "ip地址& ...

  5. C#对象、List<>转DataTable

    public static DataTable ObjectToTable(object obj)         {             try {                 Type t ...

  6. Random Variables

    可测空间(Measurable Space)和测度空间(Measure Space) 集合X,X上的一个σ-algebra A,则(X,A)被称为可测空间(measurable space) 再在A上 ...

  7. JS中的原始类型和判断方法

    ECMAScript 中定义了 7 种原始类型: Boolean String Number Null Undefined Symbol(新定义) BigInt(新定义) 注意: 原始类型不包含 Ob ...

  8. Day2-C-迷宫问题 -POJ3984

    定义一个二维数组: int maze[5][5] = { 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, ...

  9. Day3-N - Monthly Expense POJ3273

    Farmer John is an astounding accounting wizard and has realized he might run out of money to run the ...

  10. mysql产生随机数

     mysql产生随机数小结一下,可以为mysql的表生成大量的随机数: 1) 产生0到10000间的随机数    SELECT RAND() * 10000; 对应产生相应的整数    SELECT ...