Update Socket.md
重新绘制 I/O 模型的配图,更新非阻塞 I/O 和 select 示例的描述。
@@ -48,15 +48,15 @@ Unix 有五种 I/O 模型:
|
||||
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
|
||||
```
|
||||
|
||||
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/1492928416812_4.png"/> </div><br>
|
||||
<div align="center"> <img src="pics/io-blocking.png" width="760px"/> </div><br>
|
||||
|
||||
### 非阻塞式 I/O
|
||||
|
||||
应用进程执行系统调用之后,内核返回一个错误码。应用进程可以继续执行,但是需要不断的执行系统调用来获知 I/O 是否完成,这种方式称为轮询(polling)。
|
||||
应用进程执行系统调用之后,如果数据还没有准备好,内核立即返回错误码 EAGAIN(也写作 EWOULDBLOCK)。应用进程可以继续执行,但是需要不断的执行系统调用来获知 I/O 是否完成,这种方式称为轮询(polling)。
|
||||
|
||||
由于 CPU 要处理更多的系统调用,因此这种模型的 CPU 利用率比较低。
|
||||
|
||||
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/1492929000361_5.png"/> </div><br>
|
||||
<div align="center"> <img src="pics/io-nonblocking.png" width="760px"/> </div><br>
|
||||
|
||||
### I/O 复用
|
||||
|
||||
@@ -66,7 +66,7 @@ ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *
|
||||
|
||||
如果一个 Web 服务器没有 I/O 复用,那么每一个 Socket 连接都需要创建一个线程去处理。如果同时有几万个连接,那么就需要创建相同数量的线程。相比于多进程和多线程技术,I/O 复用不需要进程线程创建和切换的开销,系统开销更小。
|
||||
|
||||
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/1492929444818_6.png"/> </div><br>
|
||||
<div align="center"> <img src="pics/io-multiplex.png" width="760px"/> </div><br>
|
||||
|
||||
### 信号驱动 I/O
|
||||
|
||||
@@ -74,7 +74,7 @@ ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *
|
||||
|
||||
相比于非阻塞式 I/O 的轮询方式,信号驱动 I/O 的 CPU 利用率更高。
|
||||
|
||||
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/1492929553651_7.png"/> </div><br>
|
||||
<div align="center"> <img src="pics/io-signal.png" width="760px"/> </div><br>
|
||||
|
||||
### 异步 I/O
|
||||
|
||||
@@ -82,7 +82,7 @@ ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *
|
||||
|
||||
异步 I/O 与信号驱动 I/O 的区别在于,异步 I/O 的信号是通知应用进程 I/O 完成,而信号驱动 I/O 的信号是通知应用进程可以开始 I/O。
|
||||
|
||||
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/1492930243286_8.png"/> </div><br>
|
||||
<div align="center"> <img src="pics/io-async.png" width="760px"/> </div><br>
|
||||
|
||||
### 五大 I/O 模型比较
|
||||
|
||||
@@ -93,7 +93,7 @@ ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *
|
||||
|
||||
非阻塞式 I/O 、信号驱动 I/O 和异步 I/O 在第一阶段不会阻塞。
|
||||
|
||||
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/1492928105791_3.png"/> </div><br>
|
||||
<div align="center"> <img src="pics/io-compare.png" width="760px"/> </div><br>
|
||||
|
||||
## 二、I/O 复用
|
||||
|
||||
@@ -138,17 +138,21 @@ tv.tv_usec = 0;
|
||||
int ret = select( largest_sock + 1, &fd_in, &fd_out, NULL, &tv );
|
||||
|
||||
// Check if select actually succeed
|
||||
if ( ret == -1 )
|
||||
if ( ret == -1 ) {
|
||||
// report error and abort
|
||||
else if ( ret == 0 )
|
||||
}
|
||||
else if ( ret == 0 ) {
|
||||
// timeout; no event detected
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( FD_ISSET( sock1, &fd_in ) )
|
||||
if ( FD_ISSET( sock1, &fd_in ) ) {
|
||||
// input event on sock1
|
||||
}
|
||||
|
||||
if ( FD_ISSET( sock2, &fd_out ) )
|
||||
if ( FD_ISSET( sock2, &fd_out ) ) {
|
||||
// output event on sock2
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -184,12 +188,14 @@ fds[1].fd = sock2;
|
||||
fds[1].events = POLLOUT;
|
||||
|
||||
// Wait 10 seconds
|
||||
int ret = poll( &fds, 2, 10000 );
|
||||
int ret = poll( fds, 2, 10000 );
|
||||
// Check if poll actually succeed
|
||||
if ( ret == -1 )
|
||||
if ( ret == -1 ) {
|
||||
// report error and abort
|
||||
else if ( ret == 0 )
|
||||
}
|
||||
else if ( ret == 0 ) {
|
||||
// timeout; no event detected
|
||||
}
|
||||
else
|
||||
{
|
||||
// If we detect the event, zero it out so we can reuse the structure
|
||||
@@ -234,7 +240,7 @@ epoll_ctl() 用于向内核注册新的描述符或者是改变某个文件描
|
||||
|
||||
从上面的描述可以看出,epoll 只需要将描述符从进程缓冲区向内核缓冲区拷贝一次,并且进程不需要通过轮询来获得事件完成的描述符。
|
||||
|
||||
<div align="center"> <img src="pics/epoll.png" width="600px"/> </div><br>
|
||||
<div align="center"> <img src="pics/epoll.png" width="640px"/> </div><br>
|
||||
|
||||
epoll 仅适用于 Linux OS。
|
||||
|
||||
@@ -247,8 +253,9 @@ epoll 对多线程编程更加友好,一个线程调用了 epoll_wait() 另一
|
||||
// The function argument is ignored (it was not before, but now it is), so put your favorite number here
|
||||
int pollingfd = epoll_create( 0xCAFE );
|
||||
|
||||
if ( pollingfd < 0 )
|
||||
// report error
|
||||
if ( pollingfd < 0 ) {
|
||||
// report error
|
||||
}
|
||||
|
||||
// Initialize the epoll structure in case more members are added in future
|
||||
struct epoll_event ev = { 0 };
|
||||
@@ -261,8 +268,9 @@ ev.data.ptr = pConnection1;
|
||||
ev.events = EPOLLIN | EPOLLONESHOT;
|
||||
// Add the descriptor into the monitoring list. We can do it even if another thread is
|
||||
// waiting in epoll_wait - the descriptor will be properly added
|
||||
if ( epoll_ctl( epollfd, EPOLL_CTL_ADD, pConnection1->getSocket(), &ev ) != 0 )
|
||||
if ( epoll_ctl( pollingfd, EPOLL_CTL_ADD, pConnection1->getSocket(), &ev ) != 0 ) {
|
||||
// report error
|
||||
}
|
||||
|
||||
// Wait for up to 20 events (assuming we have added maybe 200 sockets before that it may happen)
|
||||
struct epoll_event pevents[ 20 ];
|
||||
@@ -270,10 +278,12 @@ struct epoll_event pevents[ 20 ];
|
||||
// Wait for 10 seconds, and retrieve less than 20 epoll_event and store them into epoll_event array
|
||||
int ready = epoll_wait( pollingfd, pevents, 20, 10000 );
|
||||
// Check if epoll actually succeed
|
||||
if ( ret == -1 )
|
||||
if ( ready == -1 ) {
|
||||
// report error and abort
|
||||
else if ( ret == 0 )
|
||||
}
|
||||
else if ( ready == 0 ) {
|
||||
// timeout; no event detected
|
||||
}
|
||||
else
|
||||
{
|
||||
// Check if any events detected
|
||||
@@ -337,3 +347,4 @@ 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/)
|
||||
- [epoll(7) — Linux manual page](https://man7.org/linux/man-pages/man7/epoll.7.html)
|
||||
|
||||
|
After Width: | Height: | Size: 125 KiB |
|
After Width: | Height: | Size: 121 KiB |
|
After Width: | Height: | Size: 107 KiB |
|
After Width: | Height: | Size: 120 KiB |
|
After Width: | Height: | Size: 130 KiB |
|
After Width: | Height: | Size: 130 KiB |
@@ -0,0 +1,55 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="760" height="380" viewBox="0 0 760 380">
|
||||
<style>
|
||||
text { font-family: "PingFang SC", "Microsoft YaHei", Helvetica, Arial, sans-serif; fill: #3F3F3F; font-size: 12px; }
|
||||
.title { font-weight: bold; font-size: 15px; fill: #333; text-anchor: middle; }
|
||||
.b { font-weight: bold; }
|
||||
.c { text-anchor: middle; }
|
||||
.e { text-anchor: end; }
|
||||
.sub { font-size: 11px; fill: #6E6E6E; }
|
||||
.note { fill: #C0605A; }
|
||||
.ok { fill: #6A9F68; }
|
||||
.mono { font-family: Menlo, Consolas, monospace; }
|
||||
.arrow { stroke: #555; stroke-width: 1.1; fill: none; marker-end: url(#a); }
|
||||
.red { stroke: #C0605A; marker-end: url(#r); }
|
||||
.green { stroke: #6A9F68; marker-end: url(#g); }
|
||||
.dash { stroke-dasharray: 5 4; }
|
||||
.line { stroke: #555; stroke-width: 1.1; fill: none; }
|
||||
.frame { fill: none; stroke: #999; stroke-width: 1; stroke-dasharray: 4 3; }
|
||||
.shadow { fill: #DADADA; }
|
||||
</style>
|
||||
<defs>
|
||||
<marker id="a" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
|
||||
<path d="M1,1.5 L9.5,5 L1,8.5 z" fill="#555"/>
|
||||
</marker>
|
||||
<marker id="r" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
|
||||
<path d="M1,1.5 L9.5,5 L1,8.5 z" fill="#C0605A"/>
|
||||
</marker>
|
||||
<marker id="g" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
|
||||
<path d="M1,1.5 L9.5,5 L1,8.5 z" fill="#6A9F68"/>
|
||||
</marker>
|
||||
</defs>
|
||||
<rect width="100%" height="100%" fill="#FFFFFF"/>
|
||||
|
||||
<text x="380" y="28" class="title">异步 I/O</text>
|
||||
<rect x="120" y="46" width="160" height="30" rx="6" fill="#C6ECE9" stroke="#7DBCB7"/>
|
||||
<text x="200" y="65.5" class="c sub b">应用进程</text>
|
||||
<rect x="460" y="46" width="160" height="30" rx="6" fill="#C6E4FB" stroke="#7FB2D6"/>
|
||||
<text x="540" y="65.5" class="c sub b">内核</text>
|
||||
<line x1="200" y1="78" x2="200" y2="330" stroke="#BBB" stroke-dasharray="4 4"/>
|
||||
<line x1="540" y1="78" x2="540" y2="330" stroke="#BBB" stroke-dasharray="4 4"/>
|
||||
<rect x="554" y="96" width="26" height="94" rx="3" fill="#EAE9E7" stroke="#BFBEBA" stroke-width="1"/>
|
||||
<text x="590" y="139" class="sub b" style="fill:#444">① 等待数据</text>
|
||||
<text x="590" y="155" class="sub">例如等对方发来 hello</text>
|
||||
<rect x="554" y="244" width="26" height="46" rx="3" fill="#E6E3FA" stroke="#B8B0DE" stroke-width="1"/>
|
||||
<text x="590" y="270" class="sub b" style="fill:#444">② 复制到用户缓冲区</text>
|
||||
<text x="554" y="214" class="sub">数据到达</text>
|
||||
<line x1="200" y1="100" x2="540" y2="100" class="arrow "/>
|
||||
<text x="370" y="95" class="c sub mono" style="fill:#444">aio_read(fd, buf, 1024)</text>
|
||||
<line x1="540" y1="114" x2="200" y2="114" class="arrow dash"/>
|
||||
<text x="370" y="109" class="c sub" style="fill:#444">立即返回</text>
|
||||
<rect x="193" y="118" width="14" height="172" rx="3" fill="#C6ECE9" stroke="#7DBCB7"/>
|
||||
<text x="186" y="208" class="sub ok e">继续执行其它代码</text>
|
||||
<line x1="540" y1="290" x2="200" y2="290" class="arrow dash"/>
|
||||
<text x="370" y="285" class="c sub" style="fill:#444">完成通知:buf 中已经是 hello</text>
|
||||
<text x="30" y="356" class="sub">两个阶段都由内核完成,进程收到通知时数据已经在自己的缓冲区中。Linux 上实际的异步 I/O 多用 io_uring。</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.3 KiB |
@@ -0,0 +1,53 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="760" height="380" viewBox="0 0 760 380">
|
||||
<style>
|
||||
text { font-family: "PingFang SC", "Microsoft YaHei", Helvetica, Arial, sans-serif; fill: #3F3F3F; font-size: 12px; }
|
||||
.title { font-weight: bold; font-size: 15px; fill: #333; text-anchor: middle; }
|
||||
.b { font-weight: bold; }
|
||||
.c { text-anchor: middle; }
|
||||
.e { text-anchor: end; }
|
||||
.sub { font-size: 11px; fill: #6E6E6E; }
|
||||
.note { fill: #C0605A; }
|
||||
.ok { fill: #6A9F68; }
|
||||
.mono { font-family: Menlo, Consolas, monospace; }
|
||||
.arrow { stroke: #555; stroke-width: 1.1; fill: none; marker-end: url(#a); }
|
||||
.red { stroke: #C0605A; marker-end: url(#r); }
|
||||
.green { stroke: #6A9F68; marker-end: url(#g); }
|
||||
.dash { stroke-dasharray: 5 4; }
|
||||
.line { stroke: #555; stroke-width: 1.1; fill: none; }
|
||||
.frame { fill: none; stroke: #999; stroke-width: 1; stroke-dasharray: 4 3; }
|
||||
.shadow { fill: #DADADA; }
|
||||
</style>
|
||||
<defs>
|
||||
<marker id="a" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
|
||||
<path d="M1,1.5 L9.5,5 L1,8.5 z" fill="#555"/>
|
||||
</marker>
|
||||
<marker id="r" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
|
||||
<path d="M1,1.5 L9.5,5 L1,8.5 z" fill="#C0605A"/>
|
||||
</marker>
|
||||
<marker id="g" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
|
||||
<path d="M1,1.5 L9.5,5 L1,8.5 z" fill="#6A9F68"/>
|
||||
</marker>
|
||||
</defs>
|
||||
<rect width="100%" height="100%" fill="#FFFFFF"/>
|
||||
|
||||
<text x="380" y="28" class="title">阻塞式 I/O</text>
|
||||
<rect x="120" y="46" width="160" height="30" rx="6" fill="#C6ECE9" stroke="#7DBCB7"/>
|
||||
<text x="200" y="65.5" class="c sub b">应用进程</text>
|
||||
<rect x="460" y="46" width="160" height="30" rx="6" fill="#C6E4FB" stroke="#7FB2D6"/>
|
||||
<text x="540" y="65.5" class="c sub b">内核</text>
|
||||
<line x1="200" y1="78" x2="200" y2="330" stroke="#BBB" stroke-dasharray="4 4"/>
|
||||
<line x1="540" y1="78" x2="540" y2="330" stroke="#BBB" stroke-dasharray="4 4"/>
|
||||
<rect x="554" y="96" width="26" height="94" rx="3" fill="#EAE9E7" stroke="#BFBEBA" stroke-width="1"/>
|
||||
<text x="590" y="139" class="sub b" style="fill:#444">① 等待数据</text>
|
||||
<text x="590" y="155" class="sub">例如等对方发来 hello</text>
|
||||
<rect x="554" y="244" width="26" height="46" rx="3" fill="#E6E3FA" stroke="#B8B0DE" stroke-width="1"/>
|
||||
<text x="590" y="270" class="sub b" style="fill:#444">② 复制到用户缓冲区</text>
|
||||
<text x="554" y="214" class="sub">数据到达</text>
|
||||
<line x1="200" y1="100" x2="540" y2="100" class="arrow "/>
|
||||
<text x="370" y="95" class="c sub mono" style="fill:#444">recvfrom(fd, buf, 1024)</text>
|
||||
<rect x="193" y="102" width="14" height="188" rx="3" fill="#F3C6C2" stroke="#D99A94"/>
|
||||
<text x="186" y="200" class="sub note e">两个阶段都阻塞</text>
|
||||
<line x1="540" y1="290" x2="200" y2="290" class="arrow dash"/>
|
||||
<text x="370" y="285" class="c sub" style="fill:#444">返回 5(读到 hello)</text>
|
||||
<text x="30" y="356" class="sub">本机测试:对方 300 ms 后才发送,recv 阻塞 0.31 秒后返回。等待期间线程不占用 CPU,但也不能做别的事。</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.2 KiB |
@@ -0,0 +1,66 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="760" height="330" viewBox="0 0 760 330">
|
||||
<style>
|
||||
text { font-family: "PingFang SC", "Microsoft YaHei", Helvetica, Arial, sans-serif; fill: #3F3F3F; font-size: 12px; }
|
||||
.title { font-weight: bold; font-size: 15px; fill: #333; text-anchor: middle; }
|
||||
.b { font-weight: bold; }
|
||||
.c { text-anchor: middle; }
|
||||
.e { text-anchor: end; }
|
||||
.sub { font-size: 11px; fill: #6E6E6E; }
|
||||
.note { fill: #C0605A; }
|
||||
.ok { fill: #6A9F68; }
|
||||
.mono { font-family: Menlo, Consolas, monospace; }
|
||||
.arrow { stroke: #555; stroke-width: 1.1; fill: none; marker-end: url(#a); }
|
||||
.red { stroke: #C0605A; marker-end: url(#r); }
|
||||
.green { stroke: #6A9F68; marker-end: url(#g); }
|
||||
.dash { stroke-dasharray: 5 4; }
|
||||
.line { stroke: #555; stroke-width: 1.1; fill: none; }
|
||||
.frame { fill: none; stroke: #999; stroke-width: 1; stroke-dasharray: 4 3; }
|
||||
.shadow { fill: #DADADA; }
|
||||
</style>
|
||||
<defs>
|
||||
<marker id="a" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
|
||||
<path d="M1,1.5 L9.5,5 L1,8.5 z" fill="#555"/>
|
||||
</marker>
|
||||
<marker id="r" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
|
||||
<path d="M1,1.5 L9.5,5 L1,8.5 z" fill="#C0605A"/>
|
||||
</marker>
|
||||
<marker id="g" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
|
||||
<path d="M1,1.5 L9.5,5 L1,8.5 z" fill="#6A9F68"/>
|
||||
</marker>
|
||||
</defs>
|
||||
<rect width="100%" height="100%" fill="#FFFFFF"/>
|
||||
|
||||
<text x="380" y="28" class="title">五种 I/O 模型的比较</text>
|
||||
<text x="108" y="129" class="sub b e" style="fill:#444">① 等待数据</text>
|
||||
<text x="108" y="224" class="sub b e" style="fill:#444">② 复制数据</text>
|
||||
<line x1="110" y1="180" x2="720" y2="180" stroke="#DDD" stroke-dasharray="4 4"/>
|
||||
<text x="180" y="58" class="c b" style="fill:#444">阻塞式</text>
|
||||
<rect x="172.0" y="76" width="16" height="98" rx="3" fill="#F3C6C2" stroke="#D99A94"/>
|
||||
<text x="194" y="129" class="sub">阻塞</text>
|
||||
<rect x="172.0" y="186" width="16" height="68" rx="3" fill="#F3C6C2" stroke="#D99A94"/>
|
||||
<text x="194" y="224" class="sub">阻塞</text>
|
||||
<text x="300" y="58" class="c b" style="fill:#444">非阻塞式</text>
|
||||
<rect x="292.0" y="76" width="16" height="98" rx="3" fill="#FFFFFF" stroke="#D99A94" stroke-dasharray="4 3"/>
|
||||
<text x="314" y="129" class="sub">反复轮询</text>
|
||||
<rect x="292.0" y="186" width="16" height="68" rx="3" fill="#F3C6C2" stroke="#D99A94"/>
|
||||
<text x="314" y="224" class="sub">阻塞</text>
|
||||
<text x="420" y="58" class="c b" style="fill:#444">I/O 复用</text>
|
||||
<rect x="412.0" y="76" width="16" height="98" rx="3" fill="#F3C6C2" stroke="#D99A94"/>
|
||||
<text x="434" y="129" class="sub">阻塞在 select</text>
|
||||
<rect x="412.0" y="186" width="16" height="68" rx="3" fill="#F3C6C2" stroke="#D99A94"/>
|
||||
<text x="434" y="224" class="sub">阻塞</text>
|
||||
<text x="540" y="58" class="c b" style="fill:#444">信号驱动</text>
|
||||
<rect x="532.0" y="76" width="16" height="98" rx="3" fill="#C6ECE9" stroke="#7DBCB7"/>
|
||||
<text x="554" y="129" class="sub">不阻塞</text>
|
||||
<rect x="532.0" y="186" width="16" height="68" rx="3" fill="#F3C6C2" stroke="#D99A94"/>
|
||||
<text x="554" y="224" class="sub">阻塞</text>
|
||||
<text x="660" y="58" class="c b" style="fill:#444">异步</text>
|
||||
<rect x="652.0" y="76" width="16" height="98" rx="3" fill="#C6ECE9" stroke="#7DBCB7"/>
|
||||
<text x="674" y="129" class="sub">不阻塞</text>
|
||||
<rect x="652.0" y="186" width="16" height="68" rx="3" fill="#C6ECE9" stroke="#7DBCB7"/>
|
||||
<text x="674" y="224" class="sub">不阻塞</text>
|
||||
<path d="M126,272 q0,8 8,8 H592 q8,0 8,-8" class="line"/>
|
||||
<text x="360" y="296" class="c sub">同步 I/O:第二阶段由进程自己 recvfrom,都会阻塞</text>
|
||||
<text x="660" y="296" class="c sub">异步 I/O</text>
|
||||
<text x="30" y="320" class="sub">红色表示进程阻塞,浅青色表示进程可以做别的事。前四种的区别只在第一阶段。</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.0 KiB |
@@ -0,0 +1,59 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="760" height="380" viewBox="0 0 760 380">
|
||||
<style>
|
||||
text { font-family: "PingFang SC", "Microsoft YaHei", Helvetica, Arial, sans-serif; fill: #3F3F3F; font-size: 12px; }
|
||||
.title { font-weight: bold; font-size: 15px; fill: #333; text-anchor: middle; }
|
||||
.b { font-weight: bold; }
|
||||
.c { text-anchor: middle; }
|
||||
.e { text-anchor: end; }
|
||||
.sub { font-size: 11px; fill: #6E6E6E; }
|
||||
.note { fill: #C0605A; }
|
||||
.ok { fill: #6A9F68; }
|
||||
.mono { font-family: Menlo, Consolas, monospace; }
|
||||
.arrow { stroke: #555; stroke-width: 1.1; fill: none; marker-end: url(#a); }
|
||||
.red { stroke: #C0605A; marker-end: url(#r); }
|
||||
.green { stroke: #6A9F68; marker-end: url(#g); }
|
||||
.dash { stroke-dasharray: 5 4; }
|
||||
.line { stroke: #555; stroke-width: 1.1; fill: none; }
|
||||
.frame { fill: none; stroke: #999; stroke-width: 1; stroke-dasharray: 4 3; }
|
||||
.shadow { fill: #DADADA; }
|
||||
</style>
|
||||
<defs>
|
||||
<marker id="a" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
|
||||
<path d="M1,1.5 L9.5,5 L1,8.5 z" fill="#555"/>
|
||||
</marker>
|
||||
<marker id="r" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
|
||||
<path d="M1,1.5 L9.5,5 L1,8.5 z" fill="#C0605A"/>
|
||||
</marker>
|
||||
<marker id="g" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
|
||||
<path d="M1,1.5 L9.5,5 L1,8.5 z" fill="#6A9F68"/>
|
||||
</marker>
|
||||
</defs>
|
||||
<rect width="100%" height="100%" fill="#FFFFFF"/>
|
||||
|
||||
<text x="380" y="28" class="title">I/O 复用</text>
|
||||
<rect x="120" y="46" width="160" height="30" rx="6" fill="#C6ECE9" stroke="#7DBCB7"/>
|
||||
<text x="200" y="65.5" class="c sub b">应用进程</text>
|
||||
<rect x="460" y="46" width="160" height="30" rx="6" fill="#C6E4FB" stroke="#7FB2D6"/>
|
||||
<text x="540" y="65.5" class="c sub b">内核</text>
|
||||
<line x1="200" y1="78" x2="200" y2="330" stroke="#BBB" stroke-dasharray="4 4"/>
|
||||
<line x1="540" y1="78" x2="540" y2="330" stroke="#BBB" stroke-dasharray="4 4"/>
|
||||
<rect x="554" y="96" width="26" height="94" rx="3" fill="#EAE9E7" stroke="#BFBEBA" stroke-width="1"/>
|
||||
<text x="590" y="139" class="sub b" style="fill:#444">① 等待数据</text>
|
||||
<text x="590" y="155" class="sub">例如等对方发来 hello</text>
|
||||
<rect x="554" y="244" width="26" height="46" rx="3" fill="#E6E3FA" stroke="#B8B0DE" stroke-width="1"/>
|
||||
<text x="590" y="270" class="sub b" style="fill:#444">② 复制到用户缓冲区</text>
|
||||
<text x="554" y="214" class="sub">数据到达</text>
|
||||
<line x1="200" y1="100" x2="540" y2="100" class="arrow "/>
|
||||
<text x="370" y="95" class="c sub mono" style="fill:#444">select([fd1, fd2, …])</text>
|
||||
<rect x="193" y="102" width="14" height="88" rx="3" fill="#F3C6C2" stroke="#D99A94"/>
|
||||
<text x="186" y="150" class="sub note e">阻塞在 select</text>
|
||||
<line x1="540" y1="190" x2="200" y2="190" class="arrow dash"/>
|
||||
<text x="370" y="185" class="c sub" style="fill:#444">fd1 可读</text>
|
||||
<line x1="200" y1="244" x2="540" y2="244" class="arrow "/>
|
||||
<text x="370" y="239" class="c sub mono" style="fill:#444">recvfrom(fd1)</text>
|
||||
<rect x="193" y="246" width="14" height="44" rx="3" fill="#F3C6C2" stroke="#D99A94"/>
|
||||
<text x="186" y="272" class="sub note e">复制时阻塞</text>
|
||||
<line x1="540" y1="290" x2="200" y2="290" class="arrow dash"/>
|
||||
<text x="370" y="285" class="c sub" style="fill:#444">返回 5</text>
|
||||
<text x="30" y="356" class="sub">和阻塞式 I/O 一样要等,但一次可以等很多个连接,任何一个就绪就返回,一个线程就能处理大量连接。</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.6 KiB |
@@ -0,0 +1,63 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="760" height="380" viewBox="0 0 760 380">
|
||||
<style>
|
||||
text { font-family: "PingFang SC", "Microsoft YaHei", Helvetica, Arial, sans-serif; fill: #3F3F3F; font-size: 12px; }
|
||||
.title { font-weight: bold; font-size: 15px; fill: #333; text-anchor: middle; }
|
||||
.b { font-weight: bold; }
|
||||
.c { text-anchor: middle; }
|
||||
.e { text-anchor: end; }
|
||||
.sub { font-size: 11px; fill: #6E6E6E; }
|
||||
.note { fill: #C0605A; }
|
||||
.ok { fill: #6A9F68; }
|
||||
.mono { font-family: Menlo, Consolas, monospace; }
|
||||
.arrow { stroke: #555; stroke-width: 1.1; fill: none; marker-end: url(#a); }
|
||||
.red { stroke: #C0605A; marker-end: url(#r); }
|
||||
.green { stroke: #6A9F68; marker-end: url(#g); }
|
||||
.dash { stroke-dasharray: 5 4; }
|
||||
.line { stroke: #555; stroke-width: 1.1; fill: none; }
|
||||
.frame { fill: none; stroke: #999; stroke-width: 1; stroke-dasharray: 4 3; }
|
||||
.shadow { fill: #DADADA; }
|
||||
</style>
|
||||
<defs>
|
||||
<marker id="a" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
|
||||
<path d="M1,1.5 L9.5,5 L1,8.5 z" fill="#555"/>
|
||||
</marker>
|
||||
<marker id="r" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
|
||||
<path d="M1,1.5 L9.5,5 L1,8.5 z" fill="#C0605A"/>
|
||||
</marker>
|
||||
<marker id="g" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
|
||||
<path d="M1,1.5 L9.5,5 L1,8.5 z" fill="#6A9F68"/>
|
||||
</marker>
|
||||
</defs>
|
||||
<rect width="100%" height="100%" fill="#FFFFFF"/>
|
||||
|
||||
<text x="380" y="28" class="title">非阻塞式 I/O</text>
|
||||
<rect x="120" y="46" width="160" height="30" rx="6" fill="#C6ECE9" stroke="#7DBCB7"/>
|
||||
<text x="200" y="65.5" class="c sub b">应用进程</text>
|
||||
<rect x="460" y="46" width="160" height="30" rx="6" fill="#C6E4FB" stroke="#7FB2D6"/>
|
||||
<text x="540" y="65.5" class="c sub b">内核</text>
|
||||
<line x1="200" y1="78" x2="200" y2="330" stroke="#BBB" stroke-dasharray="4 4"/>
|
||||
<line x1="540" y1="78" x2="540" y2="330" stroke="#BBB" stroke-dasharray="4 4"/>
|
||||
<rect x="554" y="96" width="26" height="94" rx="3" fill="#EAE9E7" stroke="#BFBEBA" stroke-width="1"/>
|
||||
<text x="590" y="139" class="sub b" style="fill:#444">① 等待数据</text>
|
||||
<text x="590" y="155" class="sub">例如等对方发来 hello</text>
|
||||
<rect x="554" y="244" width="26" height="46" rx="3" fill="#E6E3FA" stroke="#B8B0DE" stroke-width="1"/>
|
||||
<text x="590" y="270" class="sub b" style="fill:#444">② 复制到用户缓冲区</text>
|
||||
<text x="554" y="214" class="sub">数据到达</text>
|
||||
<line x1="200" y1="96" x2="540" y2="96" class="arrow "/>
|
||||
<text x="370" y="91" class="c sub mono" style="fill:#444">recvfrom</text>
|
||||
<line x1="540" y1="110" x2="200" y2="110" class="arrow dash"/>
|
||||
<text x="370" y="124" class="c sub" style="fill:#444">EAGAIN(没有数据)</text>
|
||||
<line x1="200" y1="150" x2="540" y2="150" class="arrow "/>
|
||||
<text x="370" y="145" class="c sub mono" style="fill:#444">recvfrom</text>
|
||||
<line x1="540" y1="164" x2="200" y2="164" class="arrow dash"/>
|
||||
<text x="370" y="178" class="c sub" style="fill:#444">EAGAIN ……共 6 次</text>
|
||||
<line x1="200" y1="206" x2="540" y2="206" class="arrow "/>
|
||||
<text x="370" y="201" class="c sub mono" style="fill:#444">recvfrom</text>
|
||||
<rect x="193" y="100" width="14" height="100" rx="3" fill="#C6ECE9" stroke="#7DBCB7"/>
|
||||
<text x="186" y="154" class="sub ok e">轮询</text>
|
||||
<rect x="193" y="208" width="14" height="82" rx="3" fill="#F3C6C2" stroke="#D99A94"/>
|
||||
<text x="186" y="253" class="sub note e">复制时阻塞</text>
|
||||
<line x1="540" y1="290" x2="200" y2="290" class="arrow dash"/>
|
||||
<text x="370" y="285" class="c sub" style="fill:#444">返回 5</text>
|
||||
<text x="30" y="356" class="sub">本机测试:每 50 ms 调用一次 recv,前 6 次返回 EAGAIN(没有数据),第 7 次读到 hello。轮询本身要消耗 CPU。</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.9 KiB |
@@ -0,0 +1,61 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="760" height="380" viewBox="0 0 760 380">
|
||||
<style>
|
||||
text { font-family: "PingFang SC", "Microsoft YaHei", Helvetica, Arial, sans-serif; fill: #3F3F3F; font-size: 12px; }
|
||||
.title { font-weight: bold; font-size: 15px; fill: #333; text-anchor: middle; }
|
||||
.b { font-weight: bold; }
|
||||
.c { text-anchor: middle; }
|
||||
.e { text-anchor: end; }
|
||||
.sub { font-size: 11px; fill: #6E6E6E; }
|
||||
.note { fill: #C0605A; }
|
||||
.ok { fill: #6A9F68; }
|
||||
.mono { font-family: Menlo, Consolas, monospace; }
|
||||
.arrow { stroke: #555; stroke-width: 1.1; fill: none; marker-end: url(#a); }
|
||||
.red { stroke: #C0605A; marker-end: url(#r); }
|
||||
.green { stroke: #6A9F68; marker-end: url(#g); }
|
||||
.dash { stroke-dasharray: 5 4; }
|
||||
.line { stroke: #555; stroke-width: 1.1; fill: none; }
|
||||
.frame { fill: none; stroke: #999; stroke-width: 1; stroke-dasharray: 4 3; }
|
||||
.shadow { fill: #DADADA; }
|
||||
</style>
|
||||
<defs>
|
||||
<marker id="a" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
|
||||
<path d="M1,1.5 L9.5,5 L1,8.5 z" fill="#555"/>
|
||||
</marker>
|
||||
<marker id="r" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
|
||||
<path d="M1,1.5 L9.5,5 L1,8.5 z" fill="#C0605A"/>
|
||||
</marker>
|
||||
<marker id="g" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
|
||||
<path d="M1,1.5 L9.5,5 L1,8.5 z" fill="#6A9F68"/>
|
||||
</marker>
|
||||
</defs>
|
||||
<rect width="100%" height="100%" fill="#FFFFFF"/>
|
||||
|
||||
<text x="380" y="28" class="title">信号驱动 I/O</text>
|
||||
<rect x="120" y="46" width="160" height="30" rx="6" fill="#C6ECE9" stroke="#7DBCB7"/>
|
||||
<text x="200" y="65.5" class="c sub b">应用进程</text>
|
||||
<rect x="460" y="46" width="160" height="30" rx="6" fill="#C6E4FB" stroke="#7FB2D6"/>
|
||||
<text x="540" y="65.5" class="c sub b">内核</text>
|
||||
<line x1="200" y1="78" x2="200" y2="330" stroke="#BBB" stroke-dasharray="4 4"/>
|
||||
<line x1="540" y1="78" x2="540" y2="330" stroke="#BBB" stroke-dasharray="4 4"/>
|
||||
<rect x="554" y="96" width="26" height="94" rx="3" fill="#EAE9E7" stroke="#BFBEBA" stroke-width="1"/>
|
||||
<text x="590" y="139" class="sub b" style="fill:#444">① 等待数据</text>
|
||||
<text x="590" y="155" class="sub">例如等对方发来 hello</text>
|
||||
<rect x="554" y="244" width="26" height="46" rx="3" fill="#E6E3FA" stroke="#B8B0DE" stroke-width="1"/>
|
||||
<text x="590" y="270" class="sub b" style="fill:#444">② 复制到用户缓冲区</text>
|
||||
<text x="554" y="214" class="sub">数据到达</text>
|
||||
<line x1="200" y1="100" x2="540" y2="100" class="arrow "/>
|
||||
<text x="370" y="95" class="c sub mono" style="fill:#444">sigaction(SIGIO, handler)</text>
|
||||
<line x1="540" y1="114" x2="200" y2="114" class="arrow dash"/>
|
||||
<text x="370" y="109" class="c sub" style="fill:#444">立即返回</text>
|
||||
<rect x="193" y="118" width="14" height="72" rx="3" fill="#C6ECE9" stroke="#7DBCB7"/>
|
||||
<text x="186" y="158" class="sub ok e">继续执行其它代码</text>
|
||||
<line x1="540" y1="190" x2="200" y2="190" class="arrow dash"/>
|
||||
<text x="370" y="185" class="c sub mono" style="fill:#444">SIGIO 信号</text>
|
||||
<line x1="200" y1="244" x2="540" y2="244" class="arrow "/>
|
||||
<text x="370" y="239" class="c sub mono" style="fill:#444">在处理函数中 recvfrom</text>
|
||||
<rect x="193" y="246" width="14" height="44" rx="3" fill="#F3C6C2" stroke="#D99A94"/>
|
||||
<text x="186" y="272" class="sub note e">复制时阻塞</text>
|
||||
<line x1="540" y1="290" x2="200" y2="290" class="arrow dash"/>
|
||||
<text x="370" y="285" class="c sub" style="fill:#444">返回 5</text>
|
||||
<text x="30" y="356" class="sub">等待阶段不阻塞,数据到达时内核发信号通知“可以读了”,读取仍由进程自己完成。</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.7 KiB |