auto commit

This commit is contained in:
CyC2018
2020-11-17 00:32:18 +08:00
parent f5ad47b470
commit 7e61fc1360
380 changed files with 2371 additions and 46715 deletions

View File

@ -1,23 +1,13 @@
# Socket
<!-- GFM-TOC -->
* [I/O 模型](#一io-模型)
* [阻塞式 I/O](#阻塞式-io)
* [非阻塞式 I/O](#非阻塞式-io)
* [I/O 复用](#io-复用)
* [信号驱动 I/O](#信号驱动-io)
* [异步 I/O](#异步-io)
* [五大 I/O 模型比较](#五大-io-模型比较)
* [I/O 复用](#二io-复用)
* [select](#select)
* [poll](#poll)
* [比较](#比较)
* [epoll](#epoll)
* [工作模式](#工作模式)
* [应用场景](#应用场景)
* [参考资料](#参考资料)
* [Socket](#socket)
* [I/O 模型](#一io-模型)
* [I/O 复用](#二io-复用)
* [参考资料](#参考资料)
<!-- GFM-TOC -->
# I/O 模型
## I/O 模型
一个输入操作通常包括两个阶段
@ -34,7 +24,7 @@ Unix 有五种 I/O 模型:
- 信号驱动式 I/OSIGIO
- 异步 I/OAIO
## 阻塞式 I/O
### 阻塞式 I/O
应用进程被阻塞直到数据从内核缓冲区复制到应用进程缓冲区中才返回
@ -48,7 +38,7 @@ ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/1492928416812_4.png"/> </div><br>
## 非阻塞式 I/O
### 非阻塞式 I/O
应用进程执行系统调用之后内核返回一个错误码应用进程可以继续执行但是需要不断的执行系统调用来获知 I/O 是否完成这种方式称为轮询polling
@ -56,7 +46,7 @@ ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/1492929000361_5.png"/> </div><br>
## I/O 复用
### I/O 复用
使用 select 或者 poll 等待数据并且可以等待多个套接字中的任何一个变为可读这一过程会被阻塞当某一个套接字可读时返回之后再使用 recvfrom 把数据从内核复制到进程中
@ -66,7 +56,7 @@ ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/1492929444818_6.png"/> </div><br>
## 信号驱动 I/O
### 信号驱动 I/O
应用进程使用 sigaction 系统调用内核立即返回应用进程可以继续执行也就是说等待数据阶段应用进程是非阻塞的内核在数据到达时向应用进程发送 SIGIO 信号应用进程收到之后在信号处理程序中调用 recvfrom 将数据从内核复制到应用进程中
@ -74,7 +64,7 @@ ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/1492929553651_7.png"/> </div><br>
## 异步 I/O
### 异步 I/O
应用进程执行 aio_read 系统调用会立即返回应用进程可以继续执行不会被阻塞内核会在所有操作完成之后向应用进程发送信号
@ -82,7 +72,7 @@ ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/1492930243286_8.png"/> </div><br>
## 五大 I/O 模型比较
### 五大 I/O 模型比较
- 同步 I/O将数据从内核缓冲区复制到应用进程缓冲区的阶段第二阶段应用进程会阻塞
- 异步 I/O第二阶段应用进程不会阻塞
@ -93,11 +83,11 @@ ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/1492928105791_3.png"/> </div><br>
# I/O 复用
## I/O 复用
select/poll/epoll 都是 I/O 多路复用的具体实现select 出现的最早之后是 poll再是 epoll
## select
### select
```c
int select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
@ -150,7 +140,7 @@ else
}
```
## poll
### poll
```c
int poll(struct pollfd *fds, unsigned int nfds, int timeout);
@ -201,9 +191,9 @@ else
}
```
## 比较
### 比较
### 1. 功能
#### 1. 功能
select poll 的功能基本相同不过在一些实现细节上有所不同
@ -212,15 +202,15 @@ select 和 poll 的功能基本相同,不过在一些实现细节上有所不
- poll 提供了更多的事件类型并且对描述符的重复利用上比 select
- 如果一个线程对某个描述符调用了 select 或者 poll另一个线程关闭了该描述符会导致调用结果不确定
### 2. 速度
#### 2. 速度
select poll 速度都比较慢每次调用都需要将全部描述符从应用进程缓冲区复制到内核缓冲区
### 3. 可移植性
#### 3. 可移植性
几乎所有的系统都支持 select但是只有比较新的系统支持 poll
## epoll
### epoll
```c
int epoll_create(int size);
@ -286,35 +276,35 @@ else
```
## 工作模式
### 工作模式
epoll 的描述符事件有两种触发模式LTlevel trigger ETedge trigger
### 1. LT 模式
#### 1. LT 模式
epoll_wait() 检测到描述符事件到达时将此事件通知进程进程可以不立即处理该事件下次调用 epoll_wait() 会再次通知进程是默认的一种模式并且同时支持 Blocking No-Blocking
### 2. ET 模式
#### 2. ET 模式
LT 模式不同的是通知之后进程必须立即处理事件下次再调用 epoll_wait() 时不会再得到事件到达的通知
很大程度上减少了 epoll 事件被重复触发的次数因此效率要比 LT 模式高只支持 No-Blocking以避免由于一个文件句柄的阻塞读/阻塞写操作把处理多个文件描述符的任务饿死
## 应用场景
### 应用场景
很容易产生一种错觉认为只要用 epoll 就可以了select poll 都已经过时了其实它们都有各自的使用场景
### 1. select 应用场景
#### 1. select 应用场景
select timeout 参数精度为微秒 poll epoll 为毫秒因此 select 更加适用于实时性要求比较高的场景比如核反应堆的控制
select 可移植性更好几乎被所有主流平台所支持
### 2. poll 应用场景
#### 2. poll 应用场景
poll 没有最大描述符数量的限制如果平台支持并且对实时性要求不高应该使用 poll 而不是 select
### 3. epoll 应用场景
#### 3. epoll 应用场景
只需要运行在 Linux 平台上有大量的描述符需要同时轮询并且这些连接最好是长连接
@ -322,7 +312,7 @@ poll 没有最大描述符数量的限制,如果平台支持并且对实时性
需要监控的描述符状态变化多而且都是非常短暂的也没有必要使用 epoll因为 epoll 中的所有描述符都存储在内核中造成每次需要对描述符的状态改变都需要通过 epoll_ctl() 进行系统调用频繁系统调用降低效率并且 epoll 的描述符存储在内核不容易调试
# 参考资料
## 参考资料
- Stevens W R, Fenner B, Rudoff A M. UNIX network programming[M]. Addison-Wesley Professional, 2004.
- http://man7.org/linux/man-pages/man2/select.2.html
@ -333,10 +323,3 @@ poll 没有最大描述符数量的限制,如果平台支持并且对实时性
- [poll vs select vs event-based](https://daniel.haxx.se/docs/poll-vs-select.html)
- [select / poll / epoll: practical difference for system architects](http://www.ulduzsoft.com/2014/01/select-poll-epoll-practical-difference-for-system-architects/)
- [Browse the source code of userspace/glibc/sysdeps/unix/sysv/linux/ online](https://code.woboq.org/userspace/glibc/sysdeps/unix/sysv/linux/)
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-2.png"></img></div>