PHPackages                             chinawilon/learn-swoole - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. chinawilon/learn-swoole

ActiveLibrary

chinawilon/learn-swoole
=======================

description

201PHP

Since Jun 18Pushed 4y ago1 watchersCompare

[ Source](https://github.com/chinawilon/learn-swoole)[ Packagist](https://packagist.org/packages/chinawilon/learn-swoole)[ RSS](/packages/chinawilon-learn-swoole/feed)WikiDiscussions main Synced 1mo ago

READMEChangelogDependenciesVersions (1)Used By (0)

SWOOLE技术培训
==========

[](#swoole技术培训)

本系列课程献给在[玩动网络](http://www.itowan.com)的技术小伙伴

Day 1 swoole基础知识
----------------

[](#day-1-swoole基础知识)

1. `corotuine`协程自身是串行执行的，只是遇到了`异步API`发生协程切换调度而已。
2. 阻塞函数`sleep`，`fread`，`fwrite`如果需要`异步`，需要开启`一健协程化`或者在协程容器内执行。(注意swoole支持的异步化函数)
3. 协程里面不允许阻塞，不然不会发生切换调度，这会导致和`php-fpm`一样的效果甚至更差，所有逻辑同步执行。
4. 协程在操作`资源流`的时候需要注意是否会引起并发读写问题，使用`协程锁`或者相关的`池`
5. 通道只能在单进程(线程)中通信(协程自身设计如此)，不能跨进程，需要跨进程通信需要使用`IPC`技术。
6. 通道最少有一个`size=1`的容量，可以实现类似`锁`,`singleflight`, `once`等机制。
7. 多路复用的几种形式，轮训、poll/select/pselect、epoll/kqueue三者的一些重要区别。
8. 5种IO模型，其中阻塞/非阻塞/多路复用/信号驱动式IO都属于同步IO。(想想打炒粉的场景，一直看着炒/不停的问好了没/叫你一声去拿/送你桌子上就吃，多路复用就是你同时点了炒粉另一家肠粉，坐着等人家叫你去拿)
9. 自定义协议的通用做法，定义长度或分隔符。(想想你有一块布料，不同的人需要不同长度，你一直拉，拉多了满足裁剪，拉少继续拉直到满足裁剪，如果继续拉没有了说明断了)
10. 网络字节序(大端)，只有数字才会有的大小端问题，单字节或字符串没有这个问题。因为一个单字节就8(16)位，没有高8(16)位/低8(16)位之分。

Day 2 进程间通信技术
-------------

[](#day-2-进程间通信技术)

1. PHP的匿名管道功能非常有限，只有一个`popen`以及`pclose`，同时只能用读或者写打开，不需要主动关闭不用的一端。返回的是一个字节流，可以用`f系列`函数操作。只能用于父子进程间通信，属于单向传输，退化为`单工`。实际上`匿名管道`属于`半双工`。
2. 命名管道可以用于没有关系的2个进程中，可以通过`fifo`文件进行通信。多个进程可以同时对一个fifo写入数据(需要自己保重原子性写入，一般情况下数据量小于`PIPE_BUF`可以原子性写入)，但是不可以多个进程对同一个fifo读取，会出现竞态问题，无法保证数据会被哪个进程读取到。
3. Socket对有2种形式，一种是`stream`流，一种是`dgram`消息。在流套接字下同样不能并发读取，但是可以并发写入(PIPE\_BUF)。在信息套接字下是可以并发读写的(PIPE\_BUF)，内核保证读取的时候是一条条的消息。套接字是属于`全双工`传输模式。
4. Unix域套接字有多种形式，根据提供的`local_socket`（**`AF_INET`**)提供相关的实现，可以创建(tcp/udp/unix/udg)套接字。unix域套接字可以在多个不相关的进程间通信，比如常见的`unix:///mysql.sock`mysql服务器和客户端通信，`unix:///supervisor.sock`supervisor服务器和客户端通信。其他`tcp://`和`udp://`可以实现网络通信套接字，可以在2台主机间通信。
5. `stream_socket_server`函数可以用创建unix域套接字，这个函数相当于实现了`socket`,`bind`, `listen`3个系统调用。所以接下来只需要使用`stream_socket_accept`接受请求，获取到`connection`文件描述符进行`f系列`函数操作。
6. 在网络编程中遇到的主要问题是`多路复用问题`以及`异步问题`，多个请求如何在一个进程中公平得到处理，否则的话容易被某一个耗时的请求阻塞住，这个时候往往需要使用多路复用机制来公平处理每个请求。`轮训`可以实现多路复用，但是会出现空转，如果一直都有数据进来，这种场景下，效率非常高。php提供了一种较为低级的`select_stream`多路复用机制，该机制可以通知有监听的流发生了监听的事件，但是自身并不知道具体是什么流和事件，是一种无差别的轮训。
7. 关于`异步`问题，多路复用自身还是属于同步。php自身没有实现异步，即使非阻塞io模型也是属于同步，所以异步需要借助swoole的异步化处理。`异步`使得多个请求能被公平的得到处理，而不是阻塞在某个请求之上。这也是swoole为什么要做异步化的最根本的原因。

Day 3 网络服务器设计
-------------

[](#day-3-网络服务器设计)

1. sockets/unixsocket都属于`全双工(full duplex)`通讯特殊文件，即同时可以读写。pipe/fifo属于`半双工(half duplex)`特殊文件，可读可写，但是同一时刻只能读或者写。只读或者只写的设备如`键盘`，`屏幕`属于`单工（simplex)`设备。
2. 多路复用的几种形式: 循环/select/epoll，其中epoll在处理高并发的时候非常有优势。php没有epoll/kqueue的api接口，swoole提供了 一个初级的封装(EventLoop)。仔细阅读`PHPServer`和`EpollServer`领悟它们的区别和编程规范。
3. Swoole的异步TCP/UDP服务器有2种模式：`SWOOLE_BASE`以及`SWOOLE_PROCESS`模式，其中`Base`模式类似`PHPServer`服务器的实现，连接/协议/io读写/数据收发都在这个进程里面，这也导致了它不能热更新/重启会丢失连接。相反`Process`模式，使用了一个Master进程的`Reactor`线程去处理这些请求，把接收的数据根据配置分发给特定的worker进程，这导致worker进程热重启而不中断连接成为可能。其他特性，请仔细阅读`PHPServer`和`SwooleServer`的代码，结合官方文档自行体会。
4. 编写网络服务器的时候，我们往往会拿到很多不同的数据模式，比如流对象/数据片段/数据报，其中流和数据片需要我们自己去拼接和切割，这个地方也就是所谓的"粘包"发生的地方。数据报是完整的消息(udp)，但是是不可靠的，需要根据自身对数据的敏感程度去使用，比如视频/广播/这些场景丢掉1,2个数据报没什么关系。
5. WebSocket协议是基于tcp协议之上定义的一套协议，使用了类似http协议的握手过程，和http协议本身没有关系。websocket的帧里面特别注意`opcode`有几个需要注意的值，0x8/0x9/0xA即关闭/ping/pong帧，也就是协议自身设计了心跳检测的帧位，使用这些帧的时候是不会携带`payload`数据的。还有一个`FIN`位，用于TCP数据流的切割，表示一段消息的最后一帧。
6. websocket协程服务器里面的参数配置不一定适合异步服务器，比如`open_websocket_ping_frame`测试发现并不会自动回复`pong`帧，其他参数请自行测试。websocket是`全双工`通讯，所以不能使用`半全工`的http通讯思维去编程。比如不能理所当然的认为`request/response`是一对一的。
7. websocket的服务端有`socket_read_timeout`超时，默认是60s。如果使用nginx，也会有`proxy_read_timeout`超时问题。超时之后服务端会主动关闭连接，这个时候我们需要使用心跳包去维持这个连接。

`Informative References:`

1. [swoole服务器进程模型](https://wiki.swoole.com/#/server/init)
2. [websocket协议RFC](https://datatracker.ietf.org/doc/html/rfc6455)
3. [Linux手册之Epoll系统调用](https://man7.org/linux/man-pages/man2/epoll_ctl.2.html)
4. [nginx手册之proxy timeout](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_read_timeout)

Day 4 信号和进程控制
-------------

[](#day-4-信号和进程控制)

1. 信号大部分是可以捕获和忽略的，但其中有个2信号是例外`sigkill`和`sigstop`是不可捕获和忽略。系统小于**SIGRTMIN**（例如32）值的信号是不可靠的，有可能丢失或者使用默认行为处理。
2. 信号是异步执行的，会中断进程，需要考虑在信号处理器中函数的可重入性，不会影响进程中的函数执行。所以，我们需要在信号处理器中使用安全的可重入函数避免发生不可预知的错误。
3. php原生信号默认情况下是不能捕获的需要配合`declare(ticks=1)`或者主动调用`pcntl_signal_dispatch`或者在当前进程中执行`posix_kill`。使用`declare`的时候需要注意循环里面的语句不能阻塞或者类似`continue`或者空，都不会被信号处理器捕获，因为它没有任何机会去执行。
4. php信号里面有2个非常重要的参数`$signo`以及`$siginfo`，其中siginfo里面的pid可以判断信号是来着管理员还是其他进程。
5. swoole的信号处理器使用了`signalfd4`系统调用，使之生成一个描述符加入到`EventLoop`中去监听，如果当前进程是阻塞的，同样信号处理器无法得到执行，也就是epoll没有机会运行， 即使同样适用`declare`也是无效的。需要放入到`run`协程调度器，使之类似`sleep`函数异步化，从而使得epoll能够有机会运行。
6. `Ctrl+D`不是发送信号，而是表示一个特殊的二进制值，表示EOF。其他有`ctrl+Z`发送信号`sigtstp`，`ctrl+C`发送信号`sigint`，`ctrl+\`发生信号`sigquit`，其中信号`sigtstp`表示进程被`stop`，并不是在后台继续运行，如果需要继续运行可以使用shell的`fg`或者发送`sigcont`信号。如果进程被`sigstop`也可以使用`sigcont`信号重新运行。
7. 拉起一个新进程使用`pcntl_fork`，这个时候新的进程描述符指向的是同一进程地址空间，这个时候包括进程之前的所有打开的文件描述符/信号都是一样的。只有当新进程有新的内存需要写入的时候，这个时候才会复制父进程内容。线程，其实也是属于特殊的进程(linux)，只是它的地址空间和父进程一样而已，但是它有自己独立的栈。
8. 如果父进程有信号处理，自身只是单纯的`fork`，需要子进程去处理信号，比如使用`SIG_DFL`或者`SIG_IGN`或者重新其他为其他信号处理器。
9. 子进程退出如果父进程没有去监听或者主动忽略，这个时候子进程会成为`僵尸进程`残留在系统里面，占用文件描述符和一定的内存资源。如果子进程的父进程比子进程先退出，子进程会变成孤儿进程(这里需要分情况，有可能被兄弟进程收养)，默认会被`init=1`的进程收养，如果子进程退出了，`init`进程会回收它。父进程先退出这种技术一般用来实现`daemon守护进程`。
10. 子进程退出的时候会向父进程发送`sigchld`信号，如果大量子进程同时退出，由于信号是不可靠的，父进程可能无法监听到，所以如果想要监听子进程状态，不建议使用监听`sigchld`信号的方式，而是在循环里面使用`pcntl_wait`或者`pcntl_waitpid`，其中有一个`$status`参数，可以判断子进程的状态变化，注意子进程有可能并不是退出，所以需要使用`pcntl_wif系列函数`判断其状态。
11. 使用php原生编写多进程网络服务器的时候，需要注意当前逻辑是在什么进程里面，这里往往会让人`抓狂`。进程间需要进程通信，选择合适的ipc技术，一般会使用unixsocket进行通信，双全工非常方便，注意流的并发读问题。
12. 进程配合信号处理可以实现优雅的关闭服务器，一般是处理死循环的逻辑。可以实现热重启，这个时候需要设计好进程模型，比如使用`master-manager-worker`模型，可以热重启worker进程。如果只是`manager-worker`模型，可以考虑新进程继续重用worker的socket套接字，重而实现热重启。以此，避免使用`单进程`模型设计网络服务器。

Informative References:

1. TCP/IP 《TCP/IP Illustrated Volume 1: The Protocols》
2. APUE《Advanced Programming in the UNIX® Environment 3rd》
3. UNP 《UNIX Network Programming 3rd》

###  Health Score

16

—

LowBetter than 5% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity4

Limited adoption so far

Community5

Small or concentrated contributor base

Maturity29

Early-stage or recently created project

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

### Community

Maintainers

![](https://www.gravatar.com/avatar/da06ddb8c9a2a0310fe536066a1d5e99e3657032251768aec014e03e0241bf45?d=identicon)[chinawilon](/maintainers/chinawilon)

### Embed Badge

![Health badge](/badges/chinawilon-learn-swoole/health.svg)

```
[![Health](https://phpackages.com/badges/chinawilon-learn-swoole/health.svg)](https://phpackages.com/packages/chinawilon-learn-swoole)
```

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
