Java网络并发编程
2023-08-22 17:29:27 0 举报
Java网络并发编程
作者其他创作
大纲/内容
网络
OSI七层网络模型
物理层
主要定义物理设备标准,主要传输比特流
发送端将0,1码转化为电流强弱进行传输
接收端根据电流强弱转化为0,1码
数据链路层
主要用于对数据包中的MAC地址进行封装和解析,也叫数据帧
这一层工作设备主要有路由器,网桥,交换机
网络层
对数据包中的IP地址进行封装和解析也叫数据包
主要设备,路由器,交换机,防火墙等
传输层
定义了传输数据的协议,和端口号,主要用于数据的分段,传输和重组
在这一层的工作协议
TCP
传输控制协议,传输效率低,可靠性强
用于传输可靠性要求高,数据量很小的数据
UDP
用户数据协议,与TCP相反,可靠性要求不高,数据量大
会话层
在传输协议的基础上建立连接并验证访问和会话管理
表示层
对接收的数据进行编码,加解密,解压缩等
应用层
基于网络构建具体应用
如 FTP文件上传,HTTP服务,DNS服务等
TCP/IP四层网络模型
网络接口层
定义了主机之间的通信协议,如ATM,FDDI等通信协议
网络层
主要用于数据的传输,路由及地址的解析
以保障主机把数据发送到任何网络上的目标
传输层
使源端和目的端机器上对等实体可以进行基于会话协议通信
应用层
负责具体应用层协议
FTP,HTTP等
常见网络协议
应用层
HTTP 超文本传输协议
基于 TCP 协议
主要是为 Web 浏览器与 Web 服务器之间的通信而设计的
SMTP 简单邮件发送协议
基于 TCP 协议
是一种用于发送电子邮件的协议。注意
POP3/IMAP 邮件接收协议
基于 TCP 协议
负责邮件接收的协议
FTP 文件传输协议
基于 TCP 协议
用于在计算机之间传输文件的协议
FTP 是一种不安全的协议,因为它在传输过程中不会对数据进行加密
建议在传输敏感数据时使用更安全的协议,如 SFTP
Telent 远程登陆协议
基于 TCP 协议
用于通过一个终端登陆到其他服务器
以明文形式发送,一般使用SSH
SSH 安全网络传输协议
基于 TCP 协议
通过加密和认证机制实现安全的访问和文件传输等业务
RTP 实时传输协议
通常基于 UDP 协议,但也支持 TCP 协议
它提供了端到端的实时传输数据的功能
DNS 域名管理系统
基于 UDP 协议
用于解决域名和 IP 地址的映射问题
传输层
TCP
传输控制协议
提供 面向连接 的,可靠 的数据传输服务
UDP
用户数据协议
提供 无连接的,尽最大努力 的数据传输服务(不保证数据传输的可靠性),简单高效
HTTP
过程
DNS解析
TCP连接
发送HTTP请求
服务器处理请求并返回HTTP报文
浏览器解析渲染页面
连接结束
HTTP和HTTPS区别
端口号:HTTP 默认是 80,HTTPS 默认是 443
URL 前缀:HTTP 的 URL 前缀是 http://,HTTPS 的 URL 前缀是 https://
安全性和资源消耗
HTTP 协议运行在 TCP 之上,所有传输的内容都是明文,客户端和服务器端都无法验证对方的身份
HTTPS
HTTPS 是运行在 SSL/TLS 之上的 HTTP 协议,SSL/TLS 运行在 TCP 之上
所有传输的内容都经过加密,加密采用对称加密
但对称加密的密钥用服务器方的证书进行了非对称加密
HTTP 安全性没有 HTTPS 高
但是 HTTPS 比 HTTP 耗费更多服务器资源
SEO(搜索引擎优化)
搜索引擎通常会更青睐使用 HTTPS 协议的网站,因为 HTTPS 能够提供更高的安全性和用户隐私保护
使用 HTTPS 协议的网站在搜索结果中可能会被优先显示,从而对 SEO 产生影响
HTTPS
HTTP加密流程
发起请求
证书返回
证书验证
秘钥交换
数据传输
TCP
建立通信时三次握手
SYN连接请求
对方回应SYN+ACK
ACK确认
断开连接时通信四次挥手
客户端发送终止标志位FIN
服务端接收并返回ACK
服务端再次发送FIN=1 ACK=1
客户端接收到后最终的FIN断开
负载均衡
Java的网络编程模型
同步阻塞IO模型 Blocking IO
概述
指的是用户空间(或者线程)主动发起,需要等待内核 IO 操作彻底完成后才返回到用户空间的 IO 操作
在 IO 操作过程中,发起 IO 请求的用户进程(或者线程)处于阻塞状态
工作流程
用户线程发起IO的read请求,用户线程就进入阻塞状态
当系统内核收到read请求后开始准备数据,当数据未到达内核缓冲区时,内核等待
完整数据到达后,将内核缓冲区数据复制用户缓冲区,然后内核返回结果
此时用户线程才会接触阻塞状态,重新运行起来
优缺点
优点
应用程序开发非常简单;在阻塞等待数据期间,用户线程挂起,基本不会占用 CPU 资源
缺点
阻塞 IO 模型需要大量的线程来维护大量的网络连接,内存、线程切换开销会非常巨大,性能很低,基本上是不可用的
同步非阻塞IO模型 Non-Blocking IO,NIO
简述
指的是用户空间的程序不需要等待内核IO操作彻底完成
可以立即返回用户空间去执行后续的指令
即发起 IO 请求的用户进程(或者线程)处于非阻塞状态
内核会立即返回给用户一个 IO 状态值
工作流程
用户线程发起read请求,立马能够得到内核返回的结果
如果内核数据未准备好,则返回结果为false
为了读取到数据,用户线程会不断发起read请求
当内核数据到达后,用户线程阻塞,内核开始将数据从内核缓冲区取复制到用户缓冲区,然后内核返回结果
用户进程读取到数据后,才会解除阻塞状态,重新运行起来
同步IO和NIO区别
IO 发起请求后,用户线程阻塞,直到IO数据从内核缓冲区复制到用户缓冲区,解除阻塞状态,消耗大量线程开销
NIO 发起请求后,轮询数据是否已经准备好,直到完成 IO 系统调用为止,消耗大量CPU时间
多路复用IO模型
概述
通过一种机制,可以监视多个描述符,一旦某个描述符就绪(一般是读写就绪时)
内核就能够将文件描述符的就绪状态返回给用户线程,
用户空间可以根据文件描述符的就绪状态进行相应的 IO 系统调用
属于一种经典的 Reactor 模式实现
工作流程
选择器注册 Java是Selector
将需要 read 操作的目标文件描述符(socket连接)注册到Selector,开启整个 IO 多路复用模型的轮询流程
就绪状态的轮询
查询所有提前注册过的目标文件描述符(socket连接)的 IO 就绪状态
当任何一个注册过的 socket 中的数据准备好或者就绪了就说明内核缓冲区有数据了
内核将该 socket 加入就绪的列表中,并且返回就绪事件
用户线程获得了就绪状态的列表后
根据其中的 socket 连接发起 read 系统调用,用户线程阻塞
内核开始复制数据,将数据从内核缓冲区复制到用户缓冲区
数据复制完成后
内核返回结果,用户线程才会解除阻塞的状态,用户线程读取到了数据,继续执行
特点
一个选择器查询线程可以同时处理成千上万的网络连接,所以用户程序不必创建和维护大量的线程,从而大大减少了系统的开销
异步IO模型/信号驱动IO模型
概述
指的是用户空间的线程变成被动接收者,而内核空间成为主动调用者
当用户线程收到通知时,数据已经被内核读取完毕并放在了用户缓冲区内
内核在 IO 完成后通知用户线程直接使用即可
典型的回调模式,用户进程(或者线程)向内核空间注册了各种 IO 事件的回调函数,由内核去主动调用。
工作流程
用户线程发起了 read 系统调用后,立刻就可以去做其他的事,用户线程不阻塞
内核开始 IO 的第一个阶段:准备数据。准备好数据,内核就会将数据从内核缓冲区复制到用户缓冲区
内核会给用户线程发送一个信号(Signal),或者回调用户线程注册的回调方法,告诉用户线程 read 系统调用已经完成,数据已经读入用户缓冲区。
用户线程读取用户缓冲区的数据,完成后续的业务操作
特点
在内核等待数据和复制数据的两个阶段,用户线程都不是阻塞的
用户线程需要接收内核的 IO 操作完成的事件
或者用户线程需要注册一个 IO 操作完成的回调函数
正因为如此,异步 IO 有的时候也被称为信号驱动IO
JavaNIO模型的实现
Channel(通道)
与传统的IO模型中的Stream流类似
只不过Stream是单向的,InputStream和OutStream
而channel是双向的,可读可写的操作
主要实现
FileChannel,SocketChannel,ServerChannel
Buffer(缓冲区)
实际上就是一个容器,其内部通过一个连续的字节数组存储IO上的数据
在NIO中,Channel在文件或者网络上数据的读写,其结果必须是通过Buffer
Buffer是一个抽象类,对不同数据类型 有不同的实现
ByteBuffer,IntBuffer,CharBuffer,LongBuffer,DoubleBuffer
Selectorl(选择器)
用于检测在多个注册的Channel上是否有IO事件发生,并对检测到的IO事件进行相应的响应和处理
因此通过一个Selector就可以实现多个Channel的管理
不必为每个连接都创建一个线程,避免线程资源的浪费和多线程之间的上下文切换导致的开销
同时只有Selector只有在Channel上有读写事件发生时,才会调用IO函数进行读写,可极大减少系统开销,提高系统并发量
传统IO与NIO的对比
传统IO模型是面向流的
JavaNIO是面向缓冲区的
传统IO的流操作是阻塞模式的
JavaNIO的流操作是非阻塞
Reactor线程模型
概述
Reactor是一种并发处理客户端请求与响应的事件驱动模型
服务端在接收客户端请求后采用多路复用策略
通过一个非阻塞线程来异步接收所有客户端请求
并将这些请求转发到相关的工作线程组进行处理
其核心是事件驱动
角色
Reactor线程
负责监听和分配事件, 将IO事件分派给对应的Handler, 新的事件包括连接建立就绪、读就绪、写就绪等
Handler处理器
将自身与事件绑定, 执行非阻塞IO任务, 完成channel读写, 一级业务逻辑
Acceptor
处理客户端新连接,并派发请求到处理器
单线程模型
指所有客户端IO请求都在同一个线程(Thread)上完成
Client
NIO客户端,向服务端发起TCP连接,并发送数据
Acceptor
NIO服务端,通过Acceptor接受客户端的TCP连接
Dispather
接收客户端的数据并将数据以ByteBuffer的形式发送到对应的解码器
DecoderHandler
解码器,读取客户端的数据并将数据进行解码和消息应答
EncoderHandler
编码器,将客户端发送的数据(消息的请求和应答)进行统一的编码处理,并写入通道
异步非阻塞IO,将所有IO操作都集中在一个线程中处理,处理流程如下
Acceptor接受客户端TCP连接请求消息
在链路建立成功通过Dispatcher将接收到的消息写入ByteBuffer,并派发对应的DecoderHandler进行消息解码和处理
在消息处理完成后调用对应的EncoderHandler将该请求对应的响应消息进行编码和下发
多线程模型
将Acceptor的操作封装在一组线程池中,通过线程池进行监听服务端端口,接收客户端TCP连接请求,处理网络IO读写等操作操作
线程池一般使用标准的JDK线程池,该线程池中包含一个任务队列和一系列NIO线程
这些NIO线程负责具体的消息读取,编码,解码和发送
主从多线程(MainReactor主,SubReactor从)
Reactor主线程MainReactor通过select监听客户端连接时间, 接收到事件后, 通过Acceptor处理客户端链接事件
当Acceptor处理完成链接事件后, MainReactor将连接分配到SubReactor
SubReactor将连接加入到自己的连接队列进行监听, 并创建Handler各种事件进行处理
当连接上有新事件发生, Subreactor就会调用对应的Handler处理
Handler通过read从通道上获取数据, 将请求分发到Worker线程池处理业务
Worker线程池会分配独立线程完成业务处理, 并将处理请求返回给Handler, Handler通过send向客户端响应数据
一个MainReactor可以对应多个SubReactor, 即一个MainReactor线程对应多个SubReactor线程
Netty框架
RPC
0 条评论
下一页