Netty基础—1.网络编程基础二

大纲

1.什么是OSI开放系统互连

2.OSI七层模型各层的作用

3.TCP/IP协议的简介

4.TCP和UDP的简介

5.TCP连接的三次握手

6.TCP连接的四次挥手

7.TCP/IP中的数据包

8.TCP通过确认应答与序列号提高可靠性

9.HTTP请求的传输过程

10.HTTP协议报文结构

11.Socket、短连接、长连接、网络IO流程

12.Linux的IO模型详情

13.Linux的IO模型核心

14.select、poll、epoll的区别

15.水平触发和边缘触发

12.Linux的IO模型详情

(1)同步和异步、阻塞和非阻塞

(2)Linux的IO模型之阻塞IO模型(同步)

(3)Linux的IO模型之非阻塞IO模型(同步)

(4)Linux的IO模型之IO复用模型(同步)

(5)Linux的IO模型之信号驱动IO(同步)

(6)Linux的IO模型之异步IO模型(异步)

(7)Linux的5个IO模型对比

(1)同步和异步、阻塞和非阻塞

同步和异步关注的是:结果的通知方式。同步是指:调用方需要主动等待结果的返回。异步是指:调用方不需要主动等待结果的返回,调用方会通过其他方式(如状态通知、回调函数等)来等待结果的返回。

阻塞和非阻塞关注的是:等待结果返回的调用方的状态。阻塞是指:结果返回之前,当前线程被挂起,不做任何事情。非阻塞是指:结果在返回之前,当前线程可以做其他事情,不会被挂起。

同步和异步关注的是:是否亲自主动获取消息,是否由其他人通知自己。

阻塞和非阻塞关注的是:当前事情还没好时是否还能做其他事情。

一.同步阻塞

同步阻塞基本也是编程中最常见的模型。比如客户去商店买衣服,去了之后发现衣服卖完了,就在店里面一直等,期间不做任何事(包括看手机),等着商家进货,直到有货为止,效率很低。

二.同步非阻塞

同步非阻塞在编程中可以抽象为一个轮询模式。客户去了商店之后,发现衣服卖完了,这个时候不需要傻傻的等着,客户可以去其他地方比如奶茶店买杯水,但是还是需要客户时不时的主动去商店问老板新衣服到了没有。

三.异步阻塞

异步阻塞这个编程里面用的较少。这类似于写了个线程池,submit()后马上future.get(),此时线程还是挂起的。客户去商店买衣服,发现衣服没有了,于是就给老板留给电话,告诉老板说衣服到了就打电话进行通知,然后就一直守着电话不做其他事情。

四.异步非阻塞

客户去商店买衣服,衣服没了,然后给老板留下电话,衣服到了就打电话通知。然后客户就可以随心所欲地去做其他事情,也不用操心衣服什么时候到。只要衣服一到,老板就会打电话进行通知,收到通知后再去买衣服即可。

(2)Linux的IO模型之阻塞IO模型(同步)

一.解析一

应用程序调用一个IO方法,导致应用程序阻塞,等待数据准备好。如果数据没有准备好,则一直等待。如果数据准备好,则将数据从内核空间拷贝到用户空间,然后返回是否成功。

二.解析二

当调用recv()方法时,系统首先查是否有准备好的数据。如果数据没有准备好,那么系统就处于等待状态。如果数据已经准备好,则将数据从内核空间复制到用户空间,然后返回。在套接应用程序中,当调用recv()方法时,未必用户空间就已经存在数据,那么此时recv()方法就会处于等待状态。

图片

三.阻塞IO(BIO)的优点

程序简单,在阻塞等待数据期间,用户线程挂起,用户线程基本不会占用CPU资源。

四.阻塞IO(BIO)的缺点

一般情况下,需要为每个连接配套一条独立的线程,或者说一条线程维护一个连接成功的IO流的读写。在并发量小的情况下,这没什么问题,内存和线程切换开销比较小。但是当在高并发的场景下,需要大量的线程来维护大量的网络连接。因此,基本上BIO模型在高并发场景下是不可用的。

(3)Linux的IO模型之非阻塞IO模型(同步)

一.解析一

把一个Socket设置为非阻塞就是告诉系统内核:当所请求的IO操作无法完成时,不要将进程睡眠,而是返回一个错误。这样IO操作函数将不断测试数据是否已经准备好。如果没有准备好,则继续测试,直到数据准备好为止。在这个不断测试的过程中,会大量的占用CPU的时间,所以该模型不应该被推荐。

二.解析二

把一个Socket设置为非阻塞就是告诉系统内核:在调用Sockets API时,不要让线程睡眠,而应该让函数立即返回。在返回时,该函数返回一个错误代码。

下图展示了一个非阻塞模式的套接字多次调用recv()函数的过程。前三次调用recv()函数时,内核数据还没有准备好。因此recv()函数会立即返回EWOULDBLOCK错误代码。第四次调用recv()函数时,数据已经准备好,被复制到应用程序的缓冲区中。因此recv()函数会返回成功,之后应用程序便开始处理数据。

图片

三.非阻塞IO(NIO)的特点

应用程序线程需不断进行IO系统调用,轮询数据是否已准备好。如果还没准备好,则继续轮询,直到完成系统调用为止。

四.非阻塞IO(NIO)的优点

每次发起IO系统调用,在内核等待数据过程中可以立即返回。用户线程不会阻塞,实时性较好。

五.非阻塞IO(NIO)的缺点

需要不断重复发起IO系统调用,不断询问内核。这种不断的轮询将会占用大量的CPU时间,系统资源利用率比较低。

(4)Linux的IO模型之IO复用模型(同步)

一.解析一(两次调用,两次返回)

IO多路复用模型,是通过一种新的系统调用来实现的。一个进程可以监视多个文件描述符,一旦某个描述符就绪(可读/可写),那么内核就会通知程序进行相应的IO系统调用。非阻塞的BIO就是一个线程只能轮询自己的一个文件描述符。

IO多路复用模型的基本原理就是select/epoll系统调用。单个线程不断的轮询select/epoll系统调用所负责的成百上千的Socket连接,当某个或某些Socket网络连接有数据到达了,就返回这些可以读写的连接。好处是通过一次select/epoll调用,就能查询可读写的成百上千个网络连接。

在这种模式中首先不是进行read系统调动,而是进行select/epoll系统调用。当然前提是要将目标网络连接提前注册到select/epoll可查询的Socket列表,然后才可以开启整个IO多路复用模型的读流程。

步骤一:

首先进行select/epoll系统调用,查询可以读的连接。内核会通过select系统调用查询所有可查询的Socket列表。当任何一个Socket中的数据准备好了,select系统调用就会返回。注意:当用户线程调用了select系统调用时,整个线程是会被阻塞的。

步骤二:

用户线程获得了目标连接后,会发起read系统调用,此时用户线程被阻塞。然后内核开始将数据从内核缓冲区复制到用户缓冲区,接着内核返回结果。

步骤三:

用户线程才解除阻塞的状态,此时用户线程终于读取到数据,继续执行。

二.解析二(两次调用,两次返回)

对一个IO端口,两次调用两次返回,比阻塞IO并没有什么优越性,关键是能实现同时对多个IO端口进行监听。IO复用模型会用到select、poll、epoll函数,这几个函数也会阻塞进程。但是和阻塞IO不同的是,这几个函数可以同时阻塞多个IO操作,而且可以同时对多个读操作和写操作的IO函数进行检测。直到有数据可读或可写时,才真正调用IO操作函数。

当用户进程调用了select,那么整个进程会被阻塞。而同时,内核会监视所有select负责的Socket。当任何一个Socket中的数据准备好了,select系统调用就会返回。这时用户进程再调用read系统调用,将数据从内核拷贝到用户进程。

这个图和阻塞IO的图其实并没有太大的不同,事实上还更差一些。因为这里需要使用两个系统调用(select和recvfrom),而阻塞IO只调用了一个系统调用(recvfrom)。但是select的优势在于它可以同时处理多个连接,select的优势并不是能更快处理单个连接,而是能处理更多的连接。

图片

三.多路复用IO(NIO)的特点

多路复用IO需要用到两个系统调用:一个是select/epoll查询调用,一个是IO的读取调用。负责select/epoll查询调用的线程需要不断进行select/epoll轮询,查找出可以进行IO操作的连接。

四.多路复用IO(NIO)的优点

使用select/epoll的优势是:可以同时处理成千上万个连接。与一条线程维护一个连接相比,IO多路复用技术的最大优势是:系统不必创建线程,也不必维护这些线程,从而大大减小了系统的开销。Java的NIO技术,使用的就是IO多路复用模型。

五.多路复用IO(NIO)的缺点

select/epoll系统调用,本质上也是属于同步IO + 阻塞IO。都需要在读写事件就绪后,自己负责进行读写,这个读写过程是阻塞的。

(5)Linux的IO模型之信号驱动IO(同步)

首先允许套接口进行信号驱动IO。然后安装一个信号处理函数,进程继续运行并不阻塞。当数据准备好时,进程会收到一个SIGIO信号,此时可以在信号处理函数中调用IO操作函数处理数据。

图片

(6)Linux的IO模型之异步IO模型(异步)

AIO的基本流程是:

一.用户线程通过系统调用,告知内核启动某个IO操作,用户线程返回

二.内核在整个IO操作(包括数据准备、数据复制)完成后,通知用户程序

三.用户程序收到通知后便可执行后续的业务操作

内核的数据准备是将数据从网卡读取到内核缓冲区,内核的数据复制是将数据从内核缓冲区拷贝到用户空间的缓冲区。

AIO的详细流程是:

一.当用户线程调用read系统调用后就可以去做其它事了,用户线程不阻塞

二.内核开始IO处理的第一个阶段——准备数据,当内核一直等到数据准备好了,就会将数据从内核缓冲区拷贝到用户缓冲区

三.内核会给用户线程发送一个信号,或者回调用户线程注册的回调接口,告诉用户线程read操作已经完成了

四.用户线程接着就可以读取用户缓冲区的数据,完成后续的业务操作

异步IO模型的特点:在内核的等待数据和复制数据两个阶段,用户线程都不会阻塞。用户线程需要接收内核IO操作完成的事件,或者注册IO操作完成的回调函数到操作系统的内核中。

图片

(7)Linux的5个IO模型对比

其实常用的模型是阻塞IO模型和IO复用模型。

图片

13.Linux的IO模型核心

(1)阻塞IO模型(BIO)

(2)非阻塞IO模型(NIO)

(3)IO复用模型(NIO)

(1)阻塞IO模型(BIO)

应用程序调用一个IO方法,导致应用程序阻塞,等待数据准备好。如果数据没有准备好,则一直等待。如果数据准备好,则将数据从内核空间拷贝到用户空间,然后返回是否成功。

阻塞IO(BIO)的优点:

程序简单,在阻塞等待数据期间,用户线程挂起,用户线程基本不会占用CPU资源。

阻塞IO(BIO)的缺点:

一般情况下,需要为每个连接配套一条独立的线程,或者说一条线程维护一个连接成功的IO流的读写。在并发量小的情况下,这没什么问题,内存和线程切换开销比较小。但是当在高并发的场景下,需要大量的线程来维护大量的网络连接。因此,基本上BIO模型在高并发场景下是不可用的。

图片

(2)非阻塞IO模型(NIO)

把一个Socket设置为非阻塞就是告诉系统内核:当所请求的IO操作无法完成时,不要将进程睡眠,而是返回一个错误。这样IO操作函数将不断测试数据是否已经准备好。如果没有准备好,继续测试,直到数据准备好为止。在这个不断测试的过程中,会大量的占用CPU的时间,所以该模型不应该被推荐。

非阻塞IO(NIO)的特点:

应用程序线程需要不断进行IO系统调用,轮询数据是否已经准备好。如果还没准备好,则继续轮询,直到完成系统调用为止。

非阻塞IO(NIO)的优点:

每次发起IO系统调用,在内核等待数据过程中可以立即返回。用户线程不会阻塞,实时性较好。

非阻塞IO(NIO)的缺点:

需要不断重复发起IO系统调用,不断询问内核。这种不断轮询将占用大量CPU时间,系统资源利用率低。

图片

(3)IO复用模型(NIO)

IO多路复用模型,是通过一种新的系统调用来实现的。一个进程可以监视多个文件描述符,一旦某个描述符就绪(可读/可写),那么内核就会通知程序进行相应的IO系统调用。非阻塞的BIO就是一个线程只能轮询自己的一个文件描述符。

IO多路复用模型的基本原理就是select/epoll系统调用。单个线程不断的轮询select/epoll系统调用所负责的成百上千的Socket连接,当某个或某些Socket网络连接有数据到达了,就返回这些可以读写的连接。好处是通过一次select/epoll调用,就能查询可读写的成百上千个网络连接。

一.select版的多路复用

图片

二.epoll版的多路复用

图片

在这种模式中首先不是进行read系统调动,而是进行select/epoll系统调用。当然前提是要将目标网络连接提前注册到select/epoll可查询的Socket列表,然后才可以开启整个IO多路复用模型的读流程。

步骤一:

首先进行select/epoll系统调用,查询可以读的连接,内核会通过select系统调用查询所有可查询的Socket列表。当任何一个Socket中的数据准备好了,select系统调用就会返回。注意:当用户线程调用了select系统调用时,整个线程是会被阻塞的。

步骤二:

用户线程获得了目标连接后,会发起read系统调用,此时用户线程被阻塞。然后内核开始将数据从内核缓冲区复制到用户缓冲区,接着内核返回结果。

步骤三:

用户线程才解除阻塞的状态,此时用户线程终于读取到数据,继续执行。

三.多路复用IO(NIO)的特点

多路复用IO需要用到两个系统调用:一个是select/epoll查询调用,一个是IO的读取调用。负责select/epoll查询调用的线程:需要不断进行select/epoll轮询,查找出可以进行IO操作的连接。

四.多路复用IO(NIO)的优点

使用select/epoll的优势是:可以同时处理成千上万个连接。与一条线程维护一个连接相比,IO多路复用技术的最大优势是:系统不必创建线程,也不必维护这些线程,从而大大减小了系统的开销。Java的NIO技术,使用的就是IO多路复用模型。

五.多路复用IO(NIO)的缺点

select/epoll系统调用,本质上也是属于同步IO + 阻塞IO。都需要在读写事件就绪后,自己负责进行读写,这个读写过程是阻塞的。

14.select、poll、epoll的区别

(1)支持一个进程所能打开的最大连接数

图片

(2)FD剧增后带来的IO效率问题

图片

(3)消息传递方式

图片

15.水平触发和边缘触发

(1)Level_triggered(水平触发)

当被监控的文件描述符上有可读写事件发生时,epoll_wait()会通知处理程序去读写。如果这次没有把数据一次性全部读写完(如读写缓冲区太小),那么下次调用 epoll_wait()时,它还会通知你在上没读写完的文件描述符上继续读写。当然如果处理程序一直不去读写,它会一直通知处理程序。

如果系统中有大量不需要读写的就绪文件描述符,而它们每次都会返回,这样会大大降低处理程序检索处理程序关心的就绪文件描述符的效率。

(2)Edge_triggered(边缘触发)

当被监控的文件描述符上有可读写事件发生时,epoll_wait()会通知处理程序去读写。如果这次没有把数据全部读写完(如读写缓冲区太小),那么下次调用epoll_wait()时,它不会通知处理程序,也就是它只会通知处理程序一次,直到该文件描述符上出现第二次可读写事件才会通知处理程序。

这种模式比水平触发效率高,系统不会充斥大量处理程序不关心的就绪文件描述符。select()、poll()模型都是水平触发模式,信号驱动IO是边缘触发模式。epoll()模型即支持水平触发,也支持边缘触发,默认是水平触发。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值