├── .gitignore
├── README
├── README.md
├── SUMMARY.md
├── book.json
├── book
├── addendum
│ ├── callback.md
│ ├── function.md
│ ├── property.md
│ └── set.md
├── chapter01
│ ├── chapter01.md
│ ├── echo_server.md
│ └── install.md
├── chapter02
│ ├── chapter02.md
│ ├── port.md
│ ├── process.md
│ ├── sendfile.md
│ ├── ssl.md
│ ├── table.md
│ ├── task_worker.md
│ ├── timer.md
│ └── worker.md
└── preface.md
└── code
├── .gitignore
├── process
└── process.php
├── protocol
├── WebSocketClient.php
├── async_client.php
├── client.php
└── cross_send.php
├── server.php
├── task
└── simple_task.php
├── test.php
└── udp
├── udp_client.php
└── udp_server.php
/.gitignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LinkedDestiny/swoole-concise-guide/50801e3f4fa7eae39ab0274cff45a8a04ce085e4/.gitignore
--------------------------------------------------------------------------------
/README:
--------------------------------------------------------------------------------
1 | Concise Guide to Swoole
2 | ===================
3 |
4 | ##Author
5 | Lancelot(李丹阳 ID: 会敲代码的喵) from **LinkedDestiny Studio**(**牵机工作室**
6 |
7 | ###Description
8 | A concise guide to php swoole extension.
9 |
10 | ###Contact
11 | simonarthur2012@gmail.com (Lancelot)
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Concise Guide to Swoole
2 | ===================
3 |
4 | ##Author
5 | Lancelot(李丹阳 ID: 会敲代码的喵) from **LinkedDestiny Studio**(**牵机工作室**)
6 | Company:[Bilibili](http://www.bilibili.com/)
7 |
8 | ##Description
9 | A concise guide to php swoole extension.
10 |
11 | ##Contact
12 | simonarthur2012@gmail.com (Lancelot)
13 |
14 | ##Notice
15 | I'm sorry that I can't translate my book to English. If someone wants to help me, Please send an email to me, thanks
16 |
--------------------------------------------------------------------------------
/SUMMARY.md:
--------------------------------------------------------------------------------
1 | # 目录
2 | * [序章](book/preface.md)
3 |
4 | * [1 环境搭建](book/chapter01/chapter01.md)
5 | * [1.1 环境搭建](book/chapter01/install.md)
6 | * [1.2 搭建Echo服务器](book/chapter01/echo_server.md)
7 | * [2 初识Swoole](book/chapter02/chapter02.md)
8 | * [2.1 Worker进程](book/chapter02/worker.md)
9 | * [2.2 TaskWorker进程](book/chapter02/task_worker.md)
10 | * [2.3 Timer定时器](book/chapter02/timer.md)
11 | * [2.4 Process进程](book/chapter02/process.md)
12 | * [2.5 Table内存表](book/chapter02/table.md)
13 | * [2.6 多端口监听](book/chapter02/port.md)
14 | * [2.7 sendfile文件支持](book/chapter02/sendfile.md)
15 | * [2.8 SSL支持](book/chapter02/ssl.md)
16 | * [3 Swoole协议](book/chapter03/chapter03.md)
17 | * [3.1 EOF协议](book/chapter03/eof.md)
18 | * [3.2 固定包头协议](book/chapter03/head.md)
19 | * [3.3 Http协议](book/chapter03/http.md)
20 | * [3.4 WebSocket协议](book/chapter03/websocket.md)
21 | * [3.5 MTQQ协议](book/chapter03/mtqq.md)
22 | * [4 Swoole客户端](book/chapter04/chapter04.md)
23 | * [4.1 Client](book/chapter04/client.md)
24 | * [4.2 异步Http客户端](book/chapter04/http.md)
25 | * [4.3 异步WebSocket客户端](book/chapter04/websocket.md)
26 | * [4.4 异步MySQL客户端](book/chapter04/mysql.md)
27 | * [4.5 异步Redis客户端](book/chapter04/redis.md)
28 | * [5 Swoole异步IO](book/chapter05/chapter05.md)
29 | * [5.1 AsyncIO](book/chapter05/async.md)
30 | * [5.2 EventLoop](book/chapter05/event_loop.md)
31 | * [6 Swoole使用](book/chapter06/chapter06.md)
32 | * [7 框架应用](book/chapter07/chapter07.md)
33 | * [7.1 ZPHP](book/chapter07/zphp.md)
34 | * [7.2 TSF](book/chapter07/tsf.md)
35 | * [7.3 Hprose](book/chapter07/hprose.md)
36 | * [7.4 Dora-rpc](book/chapter07/dora-rpc.md)
37 | * [8 已有框架支持](book/chapter08/chapter08.md)
38 | * [8.1 Yaf](book/chapter08/yaf.md)
39 | * [8.2 Phalcon](book/chapter08/phalcon.md)
40 | * [8.3 Thinkphp](book/chapter08/thinkphp.md)
41 | * [9 项目实战](book/chapter09/chapter09.md)
42 | * [附录*配置选项](book/addendum/set.md)
43 | * [附录*回调函数](book/addendum/callback.md)
44 | * [附录*属性列表](book/addendum/property.md)
45 | * [附录*函数列表](book/addendum/function.md)
46 |
--------------------------------------------------------------------------------
/book.json:
--------------------------------------------------------------------------------
1 | {
2 | "plugins": ["atoc","flowchart"],
3 | "pluginsConfig":
4 | {
5 | "atoc":
6 | {
7 | "addClass": true,
8 | "className": "atoc"
9 | },
10 | "flowchart":
11 | {
12 | "line-color": "black"
13 | }
14 | }
15 | }
--------------------------------------------------------------------------------
/book/addendum/callback.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LinkedDestiny/swoole-concise-guide/50801e3f4fa7eae39ab0274cff45a8a04ce085e4/book/addendum/callback.md
--------------------------------------------------------------------------------
/book/addendum/function.md:
--------------------------------------------------------------------------------
1 | # 03.swoole_server函数列表
2 | ---
3 |
4 | [TOC]
5 |
6 | ##**swoole_server::__construct**
7 | **功能描述**:创建一个swoole_server资源对象
8 | **函数原型**:
9 | ```php
10 | // 类成员函数
11 | public function swoole_server::__construct(string $host, int $port, int $mode = SWOOLE_PROCESS,
12 | int $sock_type = SWOOLE_SOCK_TCP);
13 | // 公共函数
14 | function swoole_server_create(string $host, int $port, int $mode = SWOOLE_PROCESS,
15 | int $sock_type = SWOOLE_SOCK_TCP);
16 | ```
17 | **返回**:一个swoole_server对象
18 | **参数说明**:
19 |
20 | | 参数 | 说明 |
21 | | -------- | -------- |
22 | | string host | 监听的IP地址 |
23 | | int port | 监听的端口号 |
24 | | int mode | 运行模式 |
25 | | int sock_type | 指定的socket类型 |
26 |
27 | **说明**:
28 | host、port、socket_type的详细说明见[swoole_server::addlistener](#swoole_serveraddlistener)。
29 | mode指定了swoole_server的运行模式,共有如下三种:
30 |
31 | | mode | 类型 | 说明 |
32 | | -------- | -------- | -------- |
33 | | SWOOLE_BASE | Base模式 | 传统的异步非阻塞Server。在Reactor内直接回调PHP的函数。如果回调函数中有阻塞操作会导致Server退化为同步模式。worker_num参数对与BASE模式仍然有效,swoole会启动多个Reactor进程 |
34 | | SWOOLE_THREAD | 线程模式(已废弃)| 多线程Worker模式,Reactor线程来处理网络事件轮询,读取数据。得到的请求交给Worker线程去处理。多线程模式比进程模式轻量一些,而且线程之间可以共享堆栈和资源。 访问共享内存时会有同步问题,需要使用Swoole提供的锁机制来保护数据。 |
35 | | SWOOLE_PROCESS | 进程模式(默认) | Swoole提供了完善的进程管理、内存保护机制。 在业务逻辑非常复杂的情况下,也可以长期稳定运行,适合业务逻辑非常复杂的场景。 |
36 |
37 | **样例**:
38 | ```php
39 | $serv = new swoole_server("127.0.0.1" , 8888 , SWOOLE_PROCESS , SWOOLE_SOCK_TCP);
40 | ```
41 |
42 | ##**swoole_server::set**
43 | **功能描述**:设置swoole_server运行时的各项参数
44 | **函数原型**:
45 | ```php
46 | // 类成员函数
47 | public function swoole_server::set(array $setting);
48 | // 公共函数
49 | function swoole_server_set(swoole_server $server, array $setting);
50 | ```
51 | **返回**:无
52 | **参数说明**:
53 |
54 | | 参数 | 说明 |
55 | | -------- | -------- |
56 | | array setting | 配置选项数组,采用key-value形式 |
57 |
58 | **说明**:
59 | 该函数必须在[swoole_server::start](#swoole_serverstart)函数调用前调用。
60 | 全部swoole_server的配置参数[点此查看](https://github.com/LinkedDestiny/swoole-doc/blob/master/doc/01.%E9%85%8D%E7%BD%AE%E9%80%89%E9%A1%B9.md)
61 | **样例**:
62 | ```php
63 | $serv->set(
64 | array(
65 | 'worker_num' => 8,
66 | 'max_request' => 10000,
67 | 'max_conn' => 100000,
68 | 'dispatch_mode' => 2,
69 | 'debug_mode'=> 1,
70 | 'daemonize' => false,
71 | )
72 | );
73 | ```
74 |
75 | ##**swoole_server::on**
76 | **功能描述**:绑定swoole_server的相关回调函数
77 | **函数原型**:
78 | ```php
79 | // 类成员函数
80 | public function bool swoole_server->on(string $event, mixed $callback);
81 | ```
82 | **返回**:设置成功返回true,否则返回false
83 | **参数说明**:
84 |
85 | | 参数 | 说明 |
86 | | -------- | -------- |
87 | | string event | 回调的名称(大小写不敏感) |
88 | | mixed callback | 回调的PHP函数,可以是函数名的字符串,类静态方法,对象方法数组,匿名函数 |
89 |
90 | **说明**:
91 | 该函数必须在[swoole_server::start](#swoole_serverstart)函数调用前调用。
92 | 此方法与[swoole_server::handler](#swoole_serverhandler)功能相同,作用是与swoole_client风格保持一致。
93 | [swoole_server::on](#swoole_serveron)中事件名称字符串不要加on。
94 | 全部的回调函数列表[点此查看](https://github.com/LinkedDestiny/swoole-doc/blob/master/doc/02.%E4%BA%8B%E4%BB%B6%E5%9B%9E%E8%B0%83%E5%87%BD%E6%95%B0.md)
95 | **样例**:
96 | ```php
97 | $serv->on('connect', function ($serv, $fd){
98 | echo "Client:Connect.\n";
99 | });
100 | $serv->on('receive', array( $myclass, 'onReceive' ) ); // onReceive是myclass的成员函数
101 | ```
102 |
103 | ##**swoole_server::addlistener**
104 | **功能描述**:给swoole_server增加一个监听的地址和端口
105 | **函数原型**:
106 | ```php
107 | // 类成员函数
108 | public function swoole_server::addlistener(string $host, int $port, $type = SWOOLE_SOCK_TCP);
109 | // 公共函数
110 | function swoole_server_addlisten(swoole_server $serv, string $host, int $port, $type = SWOOLE_SOCK_TCP);
111 | ```
112 | **返回**:无
113 | **参数说明**:
114 |
115 | | 参数 | 说明 |
116 | | -------- | -------- |
117 | | string host | 监听的IP地址 |
118 | | int port | 监听的端口号 |
119 | | int sock_type | 指定的socket类型 |
120 |
121 | **说明**:
122 | swoole支持如下socket类型:
123 |
124 | | sock_type | 说明 |
125 | | -------- | -------- |
126 | | SWOOLE_TCP/SWOOLE_SOCK_TCP | TCP IPv4 Socket |
127 | | SWOOLE_TCP6/SWOOLE_SOCK_TCP6 | TCP IPv6 Socket |
128 | | SWOOLE_UDP/SWOOLE_SOCK_UDP | UDP IPv4 Socket |
129 | | SWOOLE_UDP6/SWOOLE_SOCK_UDP6 | UDP IPv4 Socket |
130 | | SWOOLE_UNIX_DGRAM | Unix UDP Socket |
131 | | SWOOLE_UNIX_STREAM | Unix TCP Socket |
132 |
133 | > Unix Socket仅在1.7.1+后可用,此模式下**host**参数必须填写可访问的文件路径,**port**参数忽略
134 | Unix Socket模式下,客户端**fd**将不再是数字,而是一个文件路径的字符串
135 | SWOOLE_TCP等是1.7.0+后提供的简写方式,与1.7.0前的SWOOLE_SOCK_TCP是等同的
136 |
137 | **样例**:
138 | ```php
139 | $serv->addlistener("127.0.0.1", 9502, SWOOLE_SOCK_TCP);
140 | $serv->addlistener("192.168.1.100", 9503, SWOOLE_SOCK_TCP);
141 | $serv->addlistener("0.0.0.0", 9504, SWOOLE_SOCK_UDP);
142 | $serv->addlistener("/var/run/myserv.sock", 0, SWOOLE_UNIX_STREAM);
143 |
144 | swoole_server_addlisten($serv, "127.0.0.1", 9502, SWOOLE_SOCK_TCP);
145 | ```
146 |
147 | ##**swoole_server::handler**
148 | **功能描述**:设置Server的事件回调函数
149 | **函数原型**:
150 | ```php
151 | // 类成员函数
152 | public function swoole_server::handler(string $event_name, mixed $event_callback_function);
153 | // 公共函数
154 | function swoole_server_handler(swoole_server $serv, string $event_name, mixed $event_callback_function);
155 | ```
156 | **返回**:设置成功返回true,否则返回false
157 | **参数说明**:
158 |
159 | | 参数 | 说明 |
160 | | -------- | -------- |
161 | | string event_name | 回调的名称(大小写不敏感) |
162 | | mixed event_callback_function | 回调的PHP函数,可以是函数名的字符串,类静态方法,对象方法数组,匿名函数 |
163 |
164 | **说明**:
165 | 该函数必须在[swoole_server::start](#swoole_server::start)函数调用前调用。
166 | 事件名称字符串要加on。
167 | 全部的回调函数列表[点此查看](https://github.com/LinkedDestiny/swoole-doc/blob/master/doc/02.%E4%BA%8B%E4%BB%B6%E5%9B%9E%E8%B0%83%E5%87%BD%E6%95%B0.md)
168 | > onConnect/onClose/onReceive这3个回调函数必须设置。其他事件回调函数可选
169 | 如果设定了timer定时器,onTimer事件回调函数也必须设置
170 | 如果启用了task_worker,onTask/onFinish事件回调函数必须设置
171 |
172 | **样例**:
173 | ```php
174 | $serv->handler('onStart', 'my_onStart');
175 | $serv->handler('onStart', array($this, 'my_onStart'));
176 | $serv->handler('onStart', 'myClass::onStart');
177 | ```
178 |
179 | ##**swoole_server::start**
180 | **功能描述**:启动server,开始监听所有TCP/UDP端口
181 | **函数原型**:
182 | ```php
183 | // 类成员函数
184 | public function swoole_server::start()
185 | ```
186 | **返回**:启动成功返回true,否则返回false
187 | **参数说明**:无
188 | **说明**:
189 | 启动成功后会创建worker_num+2个进程:Master进程+Manager进程+worker_num 个 Worker进程。
190 | 另外。启用task_worker会增加task_worker_num个Worker进程
191 | 三种进程的说明如下:
192 |
193 | | 进程类型 | 说明 |
194 | | -------- | -------- |
195 | | Master进程 | 主进程内有多个Reactor线程,基于epoll/kqueue进行网络事件轮询。收到数据后转发到Worker进程去处理 |
196 | | Manager进程 | 对所有Worker进程进行管理,Worker进程生命周期结束或者发生异常时自动回收,并创建新的Worker进程 |
197 | | Worker进程 | 对收到的数据进行处理,包括协议解析和响应请求 |
198 |
199 | **样例**:
200 | ```php
201 | $serv->start();
202 | ```
203 |
204 | ##**swoole_server::reload**
205 | **功能描述**:重启所有worker进程。
206 | **函数原型**:
207 | ```php
208 | // 类成员函数
209 | public function swoole_server::reload()
210 | ```
211 | **返回**:调用成功返回true,否则返回false
212 | **参数说明**:无
213 | **说明**:
214 | 调用后会向Manager发送一个SIGUSR1信号,平滑重启全部的Worker进程(所谓平滑重启,是指重启动作会在Worker处理完正在执行的任务后发生,并不会中断正在运行的任务。)
215 |
216 | 小技巧:在[onWorkerStart](https://github.com/LinkedDestiny/swoole-doc/blob/master/doc/02.%E4%BA%8B%E4%BB%B6%E5%9B%9E%E8%B0%83%E5%87%BD%E6%95%B0.md#3onworkerstart)回调中require相应的php文件,当这些文件被修改后,只需要通过SIGUSR1信号即可实现服务器热更新。
217 |
218 | 1.7.7版本增加了仅重启task_worker的功能。只需向服务器发送SIGUSR2即可
219 | **样例**:
220 | ```php
221 | $serv->reload();
222 | ```
223 |
224 | ##**swoole_server::shutdown**
225 | **功能描述**:关闭服务器。
226 | **函数原型**:
227 | ```php
228 | // 类成员函数
229 | public function swoole_server::shutdown()
230 | ```
231 | **返回**:调用成功返回true,否则返回false
232 | **参数说明**:无
233 | **说明**:
234 | 此函数可以用在worker进程内,平滑关闭全部的Worker进程。
235 | 也可向Master进程发送SIGTERM信号关闭服务器。
236 | **样例**:
237 | ```php
238 | $serv->shutdown();
239 | ```
240 |
241 | ##**swoole_server::addtimer**
242 | **功能描述**:设置一个固定间隔的定时器
243 | **函数原型**:
244 | ```php
245 | // 类成员函数
246 | public function swoole_server::addtimer(int $interval);
247 | // 公共函数
248 | function swoole_server_addtimer(swoole_server $serv, int $interval);
249 | ```
250 | **返回**:设置成功返回true,否则返回false
251 | **参数说明**:
252 |
253 | | 参数 | 说明 |
254 | | -------- | -------- |
255 | | int interval | 定时器的时间间隔,单位为毫秒ms |
256 |
257 | **说明**:
258 | swoole定时器的最小颗粒是1毫秒,支持多个不同间隔的定时器。
259 | 注意不能存在2个相同间隔时间的定时器。
260 | 使用多个定时器时,其他定时器必须为最小定时器时间间隔的整数倍。
261 |
262 | 该函数只能在onWorkerStart/onConnect/onReceive/onClose回调函数中调用。
263 | 增加定时器后需要为Server设置[onTimer](https://github.com/LinkedDestiny/swoole-doc/blob/master/doc/02.%E4%BA%8B%E4%BB%B6%E5%9B%9E%E8%B0%83%E5%87%BD%E6%95%B0.md#8ontimer)回调函数,否则Server将无法启动。
264 |
265 | **样例**:
266 | ```php
267 | $serv->addtimer(1000); //1s
268 | swoole_server_addtimer($serv,20); //20ms
269 | ```
270 |
271 | ##**swoole_server::deltimer**
272 | **功能描述**:删除指定的定时器。
273 | **函数原型**:
274 | ```php
275 | // 类成员函数
276 | public function swoole_server::deltimer(int $interval);
277 | ```
278 |
279 | **返回**:无
280 | **参数说明**:
281 |
282 | | 参数 | 说明 |
283 | | -------- | -------- |
284 | | int interval | 定时器的时间间隔,单位为毫秒ms |
285 |
286 | **说明**:
287 | 删除间隔为interval的定时器
288 |
289 | **样例**:
290 | ```php
291 | $serv->deltimer(1000);
292 | ```
293 |
294 | ##**swoole_server::after**
295 | **功能描述**:在指定的时间后执行函数
296 | **函数原型**:
297 | ```php
298 | // 类成员函数
299 | public function swoole_server::after(int $after_time_ms, mixed $callback_function, mixed params);
300 | // 公共函数
301 | function swoole_timer_after(swoole_server $serv, int $after_time_ms, mixed $callback_function, mixed params);
302 | ```
303 | **返回**:无
304 | **参数说明**:
305 |
306 | | 参数 | 说明 |
307 | | -------- | -------- |
308 | | int after_time_ms | 指定时间,单位为毫秒ms |
309 | | mixed callback_function | 指定的回调函数 |
310 | | mixed params | 指定的回调函数的参数 |
311 |
312 | **说明**:
313 | 创建一个一次性定时器,在指定的after_time_ms时间后调用callback_funciton回调函数,执行完成后就会销毁。
314 | callback_function函数的参数为指定的params
315 | 需要swoole-1.7.7以上版本。
316 |
317 | **样例**:
318 | ```php
319 | $serv->after(1000, function( $params ){
320 | echo "Do something\n";
321 | } , "data" );
322 | ```
323 |
324 | ##**swoole_server::close**
325 | **功能描述**:关闭客户端连接
326 | **函数原型**:
327 | ```php
328 | // 类成员函数
329 | public function swoole_server::close(int $fd, int $from_id = 0);
330 | ```
331 | **返回**:关闭成功返回true,失败返回false
332 | **参数说明**:
333 |
334 | | 参数 | 说明 |
335 | | -------- | -------- |
336 | | int fd | 指定关闭的fd |
337 | | int from_id | fd来自于哪个Reactor(swoole-1.6以后已废弃该参数) |
338 |
339 | **说明**:
340 | 调用close关闭连接后,连接并不会马上关闭,因此不要在close之后立即写清理逻辑,而是应该在[onClose](https://github.com/LinkedDestiny/swoole-doc/blob/master/doc/02.%E4%BA%8B%E4%BB%B6%E5%9B%9E%E8%B0%83%E5%87%BD%E6%95%B0.md#5onclose)回调中处理
341 |
342 | **样例**:
343 | ```php
344 | $serv->close( $fd );
345 | ```
346 |
347 | ##**swoole_server::send**
348 | **功能描述**:向客户端发送数据
349 | **函数原型**:
350 | ```php
351 | // 类成员函数
352 | public function swoole_server::send(int $fd, string $data, int $from_id = 0);
353 | ```
354 | **返回**:发送成功返回true,失败返回false
355 | **参数说明**:
356 |
357 | | 参数 | 说明 |
358 | | -------- | -------- |
359 | | int fd | 指定发送的fd |
360 | | string data | 发送的数据 |
361 | | int from_id | fd来自于哪个Reactor |
362 |
363 | **说明**:
364 |
365 | - data,发送的数据,最大不得超过2M。send操作具有原子性,多个进程同时调用send向同一个连接发送数据,不会发生数据混杂。
366 | - 如果要发送超过2M的数据,建议将数据写入临时文件,然后通过sendfile接口直接发送文件
367 | - UDP协议,send会直接在worker进程内发送数据包
368 | - 向UDP客户端发送数据,必须要传入from_id
369 | - 发送成功会返回true,如果连接已被关闭或发送失败会返回false
370 | - swoole-1.6以上版本不需要from_id
371 | - UDP协议使用fd保存客户端IP,from_id保存from_fd和port
372 | - UDP协议如果是在onReceive后立即向客户端发送数据,可以不传from_id
373 |
374 | **样例**:
375 | ```php
376 | $serv->send( $fd , "Hello World");
377 | ```
378 |
379 | ##**swoole_server::sendfile**
380 | **功能描述**:发送文件到TCP客户端连接
381 | **函数原型**:
382 | ```php
383 | // 类成员函数
384 | public function swoole_server::sendfile(int $fd, string $filename);
385 | ```
386 | **返回**:发送成功返回true,失败返回false
387 | **参数说明**:
388 |
389 | | 参数 | 说明 |
390 | | -------- | -------- |
391 | | int fd | 指定发送的fd |
392 | | string filename | 发送的文件名 |
393 |
394 | **说明**:
395 | sendfile函数调用OS提供的sendfile系统调用,由操作系统直接读取文件并写入socket。sendfile只有2次内存拷贝,使用此函数可以降低发送大量文件时操作系统的CPU和内存占用。
396 |
397 | **样例**:
398 | ```php
399 | $serv->sendfile($fd, __DIR__.'/test.jpg');
400 | ```
401 |
402 | ##**swoole_server::connection_info**
403 | **功能描述**:获取连接的信息
404 | **函数原型**:
405 | ```php
406 | // 类成员函数
407 | public function swoole_server::connection_info(int $fd, int $from_id = 0);
408 | ```
409 | **返回**:如果fd存在,返回一个数组,连接不存在或已关闭返回false
410 | **参数说明**:
411 |
412 | | 参数 | 说明 |
413 | | -------- | -------- |
414 | | int fd | 指定发送的fd |
415 | | int from_id | 来自于哪个Reactor |
416 |
417 | **说明**:
418 | UDP socket调用该参数时必须传入from_id.
419 | 返回的结果如下:
420 |
421 | | 名称 | 说明 |
422 | | -------- | -------- |
423 | | int from_id | 来自于哪个Reactor |
424 | | int from_fd | 来自哪个Server Socket |
425 | | int from_port | 来自哪个Server端口 |
426 | | int remote_port | 客户端连接的端口 |
427 | | string remote_ip | 客户端连接的ip |
428 | | int connect_time | 连接到Server的时间,单位秒 |
429 | | int last_time | 最后一次发送数据的时间,单位秒 |
430 |
431 | sendfile函数调用OS提供的sendfile系统调用,由操作系统直接读取文件并写入socket。sendfile只有2次内存拷贝,使用此函数可以降低发送大量文件时操作系统的CPU和内存占用。
432 |
433 | **样例**:
434 | ```php
435 | $fdinfo = $serv->connection_info($fd);
436 | $udp_client = $serv->connection_info($fd, $from_id);
437 | ```
438 |
439 | ##**swoole_server::connection_list**
440 | **功能描述**:遍历当前Server的全部客户端连接
441 | **函数原型**:
442 | ```php
443 | // 类成员函数
444 | public function swoole_server::connection_list(int $start_fd = 0, int $pagesize = 10);
445 | ```
446 | **返回**:调用成功将返回一个数字索引数组,元素是取到的fd。数组会按从小到大排序。最后一个fd作为新的start_fd再次尝试获取。
447 | 调用失败返回false
448 | **参数说明**:
449 |
450 | | 参数 | 说明 |
451 | | -------- | -------- |
452 | | int start_fd | 起始fd |
453 | | int pagesize | 每页取多少条,最大不得超过100. |
454 |
455 | **说明**:
456 | connection_list仅可用于TCP,UDP服务器需要自行保存客户端信息
457 |
458 | **样例**:
459 | ```php
460 | $start_fd = 0;
461 | while(true)
462 | {
463 | $conn_list = $serv->connection_list($start_fd, 10);
464 | if($conn_list===false)
465 | {
466 | echo "finish\n";
467 | break;
468 | }
469 | $start_fd = end($conn_list);
470 | var_dump($conn_list);
471 | foreach($conn_list as $fd)
472 | {
473 | $serv->send($fd, "broadcast");
474 | }
475 | }
476 | ```
477 |
478 | ##**swoole_server::stats**
479 | **功能描述**:获取当前Server的活动TCP连接数,启动时间,accpet/close的总次数等信息。
480 | **函数原型**:
481 | ```php
482 | // 类成员函数
483 | public function swoole_server->stats();
484 | ```
485 | **返回**:结果数组
486 | **参数说明**:无
487 | **说明**:
488 | stats方法在1.7.5+后可用
489 |
490 | | 名称 | 说明 |
491 | | -------- | -------- |
492 | | int start_time | 启动时间 |
493 | | int connection_num | 当前的连接数 |
494 | | int accept_count | accept总次数 |
495 | | int close_count | close连接的总数 |
496 |
497 | **样例**:
498 | ```php
499 | $status = $serv->stats();
500 | ```
501 |
502 | ##**swoole_server::task**
503 | **功能描述**:投递一个异步任务到task_worker池中
504 | **函数原型**:
505 | ```php
506 | // 类成员函数
507 | public function swoole_server::task(string $data, int $dst_worker_id = -1);
508 | ```
509 | **返回**:调用成功返回task_worker_id,失败返回false
510 | **参数说明**:
511 |
512 | | 参数 | 说明 |
513 | | -------- | -------- |
514 | | string data | task数据 |
515 | | int dst_worker_id | 指定投递给哪个task进程,默认随机投递 |
516 |
517 | **说明**:
518 | 此功能用于将慢速的任务异步地去执行,调用task函数会立即返回,Worker进程可以继续处理新的请求。
519 | 函数会返回一个`$task_id`数字,表示此任务的ID
520 | 任务完成后,可以通过return(低于swoole-1.7.2版本使用[finish](#swoole_serverfinish)函数)将结果通过[onFinish](https://github.com/LinkedDestiny/swoole-doc/blob/master/doc/02.%E4%BA%8B%E4%BB%B6%E5%9B%9E%E8%B0%83%E5%87%BD%E6%95%B0.md#7onfinish)回调返回给Worker进程。
521 | 发送的data必须为字符串,如果是数组或对象,请在业务代码中进行serialize处理,并在[onTask](https://github.com/LinkedDestiny/swoole-doc/blob/master/doc/02.%E4%BA%8B%E4%BB%B6%E5%9B%9E%E8%B0%83%E5%87%BD%E6%95%B0.md#6ontask)/[onFinish](https://github.com/LinkedDestiny/swoole-doc/blob/master/doc/02.%E4%BA%8B%E4%BB%B6%E5%9B%9E%E8%B0%83%E5%87%BD%E6%95%B0.md#7onfinish)中进行unserialize。
522 | data可以为二进制数据,最大长度为**8K**(超过8K可以使用临时文件共享)。字符串可以使用gzip进行压缩。
523 | 使用task必须为Server设置[onTask](https://github.com/LinkedDestiny/swoole-doc/blob/master/doc/02.%E4%BA%8B%E4%BB%B6%E5%9B%9E%E8%B0%83%E5%87%BD%E6%95%B0.md#6ontask)和[onFinish](https://github.com/LinkedDestiny/swoole-doc/blob/master/doc/02.%E4%BA%8B%E4%BB%B6%E5%9B%9E%E8%B0%83%E5%87%BD%E6%95%B0.md#7onfinish)回调,并指定[task_worker_num](https://github.com/LinkedDestiny/swoole-doc/blob/master/doc/01.%E9%85%8D%E7%BD%AE%E9%80%89%E9%A1%B9.md#6task_worker_num)配置参数。
524 |
525 |
526 | **样例**:
527 | ```php
528 | $task_id = $serv->task("some data");
529 | ```
530 |
531 | ##**swoole_server::taskwait**
532 | **功能描述**:投递一个同步任务到task_worker池中
533 | **函数原型**:
534 | ```php
535 | // 类成员函数
536 | public function swoole_server::taskwait(string $task_data, float $timeout = 0.5, int $dst_worker_id = -1);
537 | ```
538 | **返回**:task执行的结果
539 | **参数说明**:
540 |
541 | | 参数 | 说明 |
542 | | -------- | -------- |
543 | | string data | task数据 |
544 | | float timeout | 超时时间 |
545 | | int dst_worker_id | 指定投递给哪个task进程,默认随机投递 |
546 |
547 | **说明**:
548 | taskwait与task方法作用相同,用于投递一个异步的任务到task进程池去执行。与task不同的是taskwait是阻塞等待的,直到任务完成或者超时返回。
549 | 任务完成后,可以通过return直接返回结果
550 |
551 | **样例**:
552 | ```php
553 | $task_id = $serv->taskwait("some data", 30);
554 | ```
555 |
556 | ##**swoole_server::finish**
557 | **功能描述**:传递Task结果数据给worker进程
558 | **函数原型**:
559 | ```php
560 | // 类成员函数
561 | public function swoole_server::finish(string $task_data);
562 | ```
563 | **返回**:无
564 | **参数说明**:
565 |
566 | | 参数 | 说明 |
567 | | -------- | -------- |
568 | | string data | 结果数据 |
569 |
570 | **说明**:
571 | 使用swoole_server::finish函数必须为Server设置[onFinish](https://github.com/LinkedDestiny/swoole-doc/blob/master/doc/02.%E4%BA%8B%E4%BB%B6%E5%9B%9E%E8%B0%83%E5%87%BD%E6%95%B0.md#7onfinish)回调函数。此函数只可用于Task Worker进程的[onTask](https://github.com/LinkedDestiny/swoole-doc/blob/master/doc/02.%E4%BA%8B%E4%BB%B6%E5%9B%9E%E8%B0%83%E5%87%BD%E6%95%B0.md#6ontask)回调中
572 | swoole_server::finish是可选的。如果Worker进程不关心任务执行的结果,可以不调用此函数
573 | 此函数在swoole-1.7.2以上版本已废弃,使用return代替。
574 | **样例**:
575 | ```php
576 | $serv->finish("result data");
577 | ```
578 |
579 | ##**swoole_server::heartbeat**
580 | **功能描述**:进行心跳检测
581 | **函数原型**:
582 | ```php
583 | // 类成员函数
584 | public function swoole_server::heartbeat(bool $if_close_connection = true);
585 | ```
586 | **返回**:无
587 | **参数说明**:
588 |
589 | | 参数 | 说明 |
590 | | -------- | -------- |
591 | | bool if_close_connection | 是否关闭超时的连接,默认为true |
592 |
593 | **说明**:
594 | 该函数会主动发起一次检测,遍历全部连接,根据设置的[heartbeat_check_interval](https://github.com/LinkedDestiny/swoole-doc/blob/master/doc/01.%E9%85%8D%E7%BD%AE%E9%80%89%E9%A1%B9.md#11heartbeat_check_interval)和[heartbeat_idle_time](https://github.com/LinkedDestiny/swoole-doc/blob/master/doc/01.%E9%85%8D%E7%BD%AE%E9%80%89%E9%A1%B9.md#12heartbeat_idle_time)参数,找到那些处于idle闲置状态的连接
595 | swoole默认会直接关闭这些连接,heartbeat会返回这些连接的fd
596 | 如果if_close_connection为false,则heartbeat会返回这些idle连接的fd,但不会关闭这些连接
597 | if_close_connection参数 在swoole-1.7.4以上版本可用
598 | **样例**:
599 | ```php
600 | $serv->heartbeat();
601 | ```
602 |
603 | ##**swoole_get_mysqli_sock**
604 | **功能描述**:获取mysqli的socket文件描述符
605 | **函数原型**:
606 | ```php
607 | // 公共函数
608 | int swoole_get_mysqli_sock(mysqli $db)
609 | ```
610 | **返回**:mysqli的fd
611 | **参数说明**:
612 |
613 | | 参数 | 说明 |
614 | | -------- | -------- |
615 | | mysqli db | mysqli的连接 |
616 |
617 | **说明**:
618 | 可将mysql的socket增加到swoole中,执行异步MySQL查询。如果想要使用异步MySQL,需要在编译swoole时制定--enable-async-mysql
619 | swoole_get_mysqli_sock仅支持mysqlnd驱动
620 | 即使是异步MySQL也需要一个连接池,并发SQL必须有多个连接。
621 | **样例**:
622 | ```php
623 | $db = new mysqli;
624 | $db->connect('127.0.0.1', 'root', 'root', 'test');
625 | $db->query("show tables", MYSQLI_ASYNC);
626 | swoole_event_add(swoole_get_mysqli_sock($db), function($db_sock) {
627 | global $db;
628 | $res = $db->reap_async_query();
629 | var_dump($res->fetch_all(MYSQLI_ASSOC));
630 | swoole_event_exit();
631 | });
632 | ```
633 |
634 | ##**swoole_set_process_name**
635 | **功能描述**:设置进程的名称
636 | **函数原型**:
637 | ```php
638 | // 公共函数
639 | void swoole_set_process_name(string $name);
640 | ```
641 | **返回**:无
642 | **参数说明**:
643 |
644 | | 参数 | 说明 |
645 | | -------- | -------- |
646 | | string name | 进程名称 |
647 |
648 | **说明**:
649 | 修改进程名称后,通过ps命令看到的将不再是php your_file.php,而是设定的字符串
650 |
651 | > 在swoole_server_create之前修改为manager进程名称
652 | onStart调用时修改为主进程名称
653 | onWorkerStart修改为worker进程名称
654 |
655 | swoole_set_process_name存在兼容性问题,优先使用PHP内置的cli_set_process_title函数
656 | **样例**:
657 | ```php
658 | woole_set_process_name("swoole server");
659 | ```
660 |
661 | ##**swoole_version**
662 | **功能描述**:获取swoole扩展的版本号
663 | **函数原型**:
664 | ```php
665 | // 公共函数
666 | string swoole_version();
667 | ```
668 | **返回**:swoole扩展的版本号
669 | **参数说明**:无
670 | **说明**:
671 | **样例**:
672 | ```php
673 | echo swoole_version();
674 | ```
675 |
676 | ##**swoole_strerror**
677 | **功能描述**:将标准的Unix Errno错误码转换成错误信息
678 | **函数原型**:
679 | ```php
680 | // 公共函数
681 | string swoole_strerror(int $errno);
682 | ```
683 | **返回**:转化后的错误信息
684 | **参数说明**:
685 |
686 | | 参数 | 说明 |
687 | | -------- | -------- |
688 | | int errno | errno错误码 |
689 |
690 | **说明**:
691 | **样例**:
692 | ```php
693 | echo swoole_strerror( $errno );
694 | ```
695 |
696 | ##**swoole_errno**
697 | **功能描述**:获取最近一次系统调用的错误码
698 | **函数原型**:
699 | ```php
700 | // 公共函数
701 | int swoole_errno();
702 | ```
703 | **返回**:最近一次系统调用的错误码
704 | **参数说明**:无
705 | **说明**:
706 | 错误码的值与操作系统有关。可是使用swoole_strerror将错误转换为错误信息。
707 | **样例**:
708 | ```php
709 | echo swoole_strerror(swoole_errno());
710 | ```
711 |
712 | ##**swoole_get_local_ip**
713 | **功能描述**:此函数用于获取本机所有网络接口的IP地址
714 | **函数原型**:
715 | ```php
716 | // 公共函数
717 | array swoole_get_local_ip();
718 | ```
719 | **返回**:以interface名称为key的关联数组
720 | **参数说明**:无
721 | **说明**:
722 | 目前只返回IPv4地址,返回结果会过滤掉本地loop地址127.0.0.1
723 | 返回结果样例array("eth0" => "192.168.1.100");
724 | **样例**:
725 | ```php
726 | var_dump(swoole_get_local_ip());
727 | ```
--------------------------------------------------------------------------------
/book/addendum/property.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LinkedDestiny/swoole-concise-guide/50801e3f4fa7eae39ab0274cff45a8a04ce085e4/book/addendum/property.md
--------------------------------------------------------------------------------
/book/addendum/set.md:
--------------------------------------------------------------------------------
1 | # 配置选项
2 |
3 | ---
4 |
5 | [TOC]
6 |
7 | 在swoole中,一个swoole_server的相关属性可以通过
8 | ```php
9 | $serv->set( array $configs );
10 | ```
11 | 函数来配置,这些配置选项使得swoole更加灵活。
12 | 示例:
13 | ```php
14 | $serv = new swoole_server("0.0.0.0", 9501);
15 | $serv->set(array(
16 | 'worker_num' => 8,
17 | 'max_request' => 10000,
18 | 'max_conn' => 100000,
19 | 'dispatch_mode' => 2,
20 | 'debug_mode'=> 1,
21 | 'daemonize' => false,
22 | ));
23 | ```
24 | 配置选项以及相关介绍如下:
25 |
26 | ##reactor_num
27 | 描述:指定Reactor线程数
28 | 说明:设置主进程内事件处理线程的数量,默认会启用CPU核数相同的数量,
29 | 一般设置为CPU核数的**1-4倍**,最大不得超过CPU核数*4。
30 | 示例:
31 | ```php
32 | 'reactor_num' => 8
33 | ```
34 |
35 | ## worker_num
36 | 描述:指定启动的worker进程数
37 | 说明:开启的worker进程数越多,server负载能力越大,但是相应的server占有的内存也会更多。同时,当worker进程数过多时,进程间切换带来的系统开销也会更大。因此建议开启的worker进程数为cpu核数的**1-4**倍。
38 | 示例:
39 | ```php
40 | 'worker_num' => 8
41 | ```
42 |
43 | ##max_request
44 | 描述:每个worker进程允许处理的最大任务数。
45 | 说明:设置该值后,每个worker进程在处理完max_request个请求后就会自动重启。设置该值的主要目的是为了防止worker进程处理大量请求后可能引起的内存溢出。
46 | 示例:
47 | ```php
48 | 'max_request' => 10000
49 | ```
50 |
51 | ##max_conn
52 | 描述:服务器允许维持的最大TCP连接数
53 | 说明:设置此参数后,当服务器已有的连接数达到该值时,新的连接会被拒绝。另外,该参数的值不能超过操作系统**ulimit -n**的值,同时此值也不宜设置过大,因为swoole_server会**一次性申请一大块内存**用于存放每一个connection的信息。
54 | 示例:
55 | ```php
56 | 'max_conn' => 10000
57 | ```
58 |
59 | ##ipc_mode
60 | 描述:设置进程间的通信方式。
61 | 说明:共有三种通信方式,参数如下:
62 | >- 1 => 使用unix socket通信
63 | - 2 => 使用消息队列通信
64 | - 3 => 使用消息队列通信,并设置为争抢模式
65 |
66 | 示例:
67 | ```php
68 | 'ipc_mode' => 1
69 | ```
70 |
71 | ##dispatch_mode
72 | 描述:指定数据包分发策略。
73 | 说明:共有三种模式,参数如下:
74 | >- 1 => 轮循模式,收到会轮循分配给每一个worker进程
75 | >- 2 => 固定模式,根据连接的文件描述符分配worker。这样可以保证同一个连接发来的数据只会被同一个worker处理
76 | - 3 => 抢占模式,主进程会根据Worker的忙闲状态选择投递,只会投递给处于闲置状态的Worker
77 |
78 | 示例:
79 | ```php
80 | 'dispatch_mode' => 2
81 | ```
82 |
83 | ##task_worker_num
84 | 描述:服务器开启的task进程数。
85 | 说明:设置此参数后,服务器会开启异步task功能。此时可以使用**task**方法投递异步任务。
86 | >设置此参数后,必须要给swoole_server设置onTask/onFinish两个回调函数,否则启动服务器会报错。
87 |
88 | 示例:
89 | ```php
90 | 'task_worker_num' => 8
91 | ```
92 |
93 | ##task_max_request
94 | 描述:每个task进程允许处理的最大任务数。
95 | 说明:参考[max_request](#2max_request)
96 | task_worker_num
97 | 示例:
98 | ```php
99 | 'task_max_request' => 10000
100 | ```
101 |
102 | ##task_ipc_mode
103 | 描述:设置task进程与worker进程之间通信的方式。
104 | 说明:参考[ipc_mode](#4ipc_mode)
105 | 示例:
106 | ```php
107 | 'task_ipc_mode' => 2
108 | ```
109 |
110 | ##task_tmpdir
111 | 描述:设置task的数据临时目录
112 | 说明:在swoole_server中,如果投递的数据超过8192字节,将启用临时文件来保存数据。这里的task_tmpdir就是用来设置临时文件保存的位置。
113 |
114 | >需要swoole-1.7.7+
115 |
116 | 示例:
117 | ```php
118 | 'task_tmpdir' => '/tmp/task/'
119 | ```
120 |
121 | ##daemonize
122 | 描述:设置程序进入后台作为守护进程运行。
123 | 说明:长时间运行的服务器端程序必须启用此项。如果不启用守护进程,当ssh终端退出后,程序将被终止运行。启用守护进程后,标准输入和输出会被重定向到 [log_file](#10log_file),如果 [log_file](#10log_file)未设置,则所有输出会被丢弃。
124 | 示例:
125 | ```php
126 | 'daemonize' => 0
127 | ```
128 |
129 | ##log_file
130 | 描述:指定日志文件路径
131 | 说明:在swoole运行期发生的异常信息会记录到这个文件中。默认会打印到屏幕。注意log_file **不会自动切分文件**,所以需要定期清理此文件。
132 | 示例:
133 | ```php
134 | 'log_file' => '/data/log/swoole.log'
135 | ```
136 |
137 | ## log_level
138 | 描述:设置`swoole_server`错误日志打印的等级
139 | 说明:等级范围是0-5,低于log_level设置的日志信息不会抛出。
140 |
141 | 示例:
142 | ```php
143 | 'log_level' => '1
144 | ```
145 |
146 | ##heartbeat_check_interval
147 | 描述:设置心跳检测间隔
148 | 说明:此选项表示每隔多久轮循一次,单位为秒。每次检测时遍历所有连接,如果某个连接在间隔时间内没有数据发送,则强制关闭连接(会有onClose回调)。
149 | 示例:
150 | ```php
151 | 'heartbeat_check_interval' => 60
152 | ```
153 |
154 | ##heartbeat_idle_time
155 | 描述:设置某个连接允许的最大闲置时间。
156 | 说明:该参数配合[heartbeat_check_interval](#11heartbeat_check_interval)使用。每次遍历所有连接时,如果某个连接在[heartbeat_idle_time](#12heartbeat_idle_time)时间内没有数据发送,则强制关闭连接。默认设置为[heartbeat_check_interval](#11heartbeat_check_interval) * 2。
157 | 示例:
158 | ```php
159 | 'heartbeat_idle_time' => 600
160 | ```
161 |
162 | ##open_eof_split
163 | 描述:打开eof检测功能
164 | 说明:与[package_eof ](#14package_eof )配合使用。此选项将检测客户端连接发来的数据,当数据包结尾是指定的[package_eof ](#14package_eof )字符串时才会将数据包投递至Worker进程,否则会一直拼接数据包直到缓存溢出或超时才会终止。一旦出错,该连接会被判定为恶意连接,数据包会被丢弃并强制关闭连接。
165 | > EOF检测不会从数据中间查找eof字符串,所以Worker进程可能会同时收到多个数据包,需要在应用层代码中自行**explode("\r\n", $data)** 来拆分数据包
166 |
167 | 示例:
168 | ```php
169 | 'open_eof_split' => true
170 | ```
171 |
172 | ##package_eof
173 | 描述:设置EOF字符串
174 | 说明:package_eof最大只允许传入**8个**字节的字符串
175 | 示例:
176 | ```php
177 | 'package_eof ' => '/r/n'
178 | ```
179 |
180 | ##open_length_check
181 | 描述:打开包长检测
182 | 说明:包长检测提供了**固定包头+包体**这种格式协议的解析,。启用后,可以保证Worker进程onReceive每次都会收到一个完整的数据包。
183 | 示例:
184 | ```php
185 | 'open_length_check' => true
186 | ```
187 |
188 | ##package_length_offset
189 | 描述:包头中第几个字节开始存放了长度字段
190 | 说明:配合[open_length_check](#15open_length_check)使用,用于指明长度字段的位置。
191 | 示例:
192 | ```php
193 | 'package_length_offset' => 5
194 | ```
195 |
196 | ##package_body_offset
197 | 描述:从第几个字节开始计算长度。
198 | 说明:配合[open_length_check](#15open_length_check)使用,用于指明包头的长度。
199 | 示例:
200 | ```php
201 | 'package_body_offset' => 10
202 | ```
203 |
204 | ##package_length_type
205 | 描述:指定包长字段的类型
206 | 说明:配合[open_length_check](#15open_length_check)使用,指定长度字段的类型,参数如下:
207 | >- 's' => int16_t 机器字节序
208 | - 'S' => uint16_t 机器字节序
209 | - 'n' => uint16_t 大端字节序
210 | - ’N‘ => uint32_t 大端字节序
211 | - 'L' => uint32_t 机器字节序
212 | - 'l' => int 机器字节序
213 |
214 | 示例:
215 | ```php
216 | 'package_length_type' => 'N'
217 | ```
218 |
219 | ##package_max_length
220 | 描述:设置最大数据包尺寸
221 | 说明:该值决定了数据包缓存区的大小。如果缓存的数据超过了该值,则会引发错误。具体错误处理由开启的协议解析的类型决定。
222 | 示例:
223 | ```php
224 | 'package_max_length' => 8192
225 | ```
226 |
227 | ##open_cpu_affinity
228 | 描述:启用CPU亲和性设置
229 | 说明:在多核的硬件平台中,启用此特性会将swoole的reactor线程/worker进程绑定到固定的一个核上。可以避免进程/线程的运行时在多个核之间互相切换,提高CPU Cache的命中率。
230 | 示例:
231 | ```php
232 | 'open_cpu_affinity' => true
233 | ```
234 |
235 | ## cpu_affinity_ignore
236 | 描述:设置不使用指定的CPU核
237 | 说明:IO密集型程序中,所有网络中断都是用CPU0来处理,如果网络IO很重,CPU0负载过高会导致网络中断无法及时处理,那网络收发包的能力就会下降。此参数用于设置将特定的CPU内核空出专门用于处理网络中断。
238 | 接受一个数组作为参数,array(0, 1) 表示不使用CPU0,CPU1
239 |
240 | >此选项必须与open_cpu_affinity同时设置才会生效
241 |
242 | 示例:
243 | ```php
244 | 'cpu_affinity_ignore' => array(0, 1)
245 | ```
246 |
247 | ##open_tcp_nodelay
248 | 描述:启用open_tcp_nodelay
249 | 说明:开启后TCP连接发送数据时会无关闭Nagle合并算法,立即发往客户端连接。在某些场景下,如http服务器,可以提升响应速度。
250 | 示例:
251 | ```php
252 | 'open_tcp_nodelay' => true
253 | ```
254 |
255 | ##tcp_defer_accept
256 | 描述:启用tcp_defer_accept特性
257 | 说明:启动后,只有一个TCP连接有数据发送时才会触发accept。
258 | 示例:
259 | ```php
260 | 'tcp_defer_accept' => true
261 | ```
262 |
263 | ##open_tcp_keepalive
264 | 描述:打开TCP的KEEP_ALIVE选项
265 | 说明:使用TCP内置的keep_alive属性,用于保证连接不会因为长时闲置而被关闭。
266 | 示例:
267 | ```php
268 | 'open_tcp_keepalive' => true
269 | ```
270 |
271 | ##tcp_keepidle
272 | 描述:指定探测间隔。
273 | 说明:配合[open_tcp_keepalive](#24open_tcp_keepalive)使用,如果某个连接在[tcp_keepidle](#25tcp_keepidle)内没有任何数据来往,则进行探测。
274 | 示例:
275 | ```php
276 | 'tcp_keepidle' => 600
277 | ```
278 |
279 | ##tcp_keepinterval
280 | 描述:指定探测时的发包间隔
281 | 说明:配合[open_tcp_keepalive](#24open_tcp_keepalive)使用
282 | 示例:
283 | ```php
284 | 'tcp_keepinterval' => 60
285 | ```
286 |
287 | ##tcp_keepcount
288 | 描述:指定探测的尝试次数
289 | 说明:配合[open_tcp_keepalive](#24open_tcp_keepalive)使用,若[tcp_keepcount](#27tcp_keepcount)次尝试后仍无响应,则判定连接已关闭。
290 | 示例:
291 | ```php
292 | 'tcp_keepcount' => 5
293 | ```
294 |
295 | ##backlog
296 | 描述:指定Listen队列长度
297 | 说明:此参数将决定最多同时有多少个等待accept的连接。
298 | 示例:
299 | ```php
300 | 'backlog' => 128
301 | ```
302 |
303 | ## chroot
304 | 描述:重定向Worker进程的文件系统根目录
305 | 说明:此设置可以使进程对文件系统的读写与实际的操作系统文件系统隔离。提升安全性。
306 |
307 | >需要swoole-1.7.9+
308 |
309 | 示例:
310 | ```php
311 | 'chroot' => '/data/server/'
312 | ```
313 |
314 | ## user/group
315 | 描述:设置worker/task子进程的所属用户/用户组
316 | 说明:此设置可以使进程对文件系统的读写与实际的操作系统文件系统隔离。提升安全性。
317 |
318 | >需要swoole-1.7.9+
319 | 仅在使用root用户启动时有效
320 |
321 | 示例:
322 | ```php
323 | 'user' => 'www'
324 | 'group' => 'www'
325 | ```
326 |
327 | ## discard_timeout_request
328 | 描述:设置是否丢弃已经超时的请求
329 | 说明:swoole在配置dispatch_mode=1或3后,系统无法保证onConnect/onReceive/onClose的顺序,因此可能会有一些请求数据在连接关闭后,才能到达Worker进程。
330 |
331 | > discard_timeout_request配置默认为true,表示如果worker进程收到了已关闭连接的数据请求,将自动丢弃。
332 | discard_timeout_request如果设置为false,表示无论连接是否关闭Worker进程都会处理数据请求。
333 | 需要swoole-1.7.16+
334 |
335 | 示例:
336 | ```php
337 | 'discard_timeout_request' => true
338 | ```
339 |
340 | ## enable_reuse_port
341 | 描述:设置端口重用
342 | 说明:此参数用于优化TCP连接的Accept性能,启用端口重用后多个进程可以同时进行Accept操作。
343 |
344 | >仅在Linux-3.9.0以上版本的内核可用
345 |
346 | 示例:
347 | ```php
348 | 'enable_reuse_port' => true
349 | ```
350 |
351 | ##ssl_cert_file和ssl_key_file
352 | 描述:设置SSL隧道加密
353 | 说明:设置值为一个文件名字符串,指定**cert证书**和**key**的路径。
354 | 示例:
355 | ```php
356 | 'ssl_cert_file' => '/config/ssl.crt',
357 | 'ssl_key_file' => '/config//ssl.key',
358 | ```
359 |
360 | ## ssl_client_cert_file
361 | 描述:指定CA证书路径
362 | 说明:开启双向SSL认证时,需要指定客户端所使用的CA证书
363 |
364 | 示例:
365 | ```php
366 | 'ssl_client_cert_file' => '../ca.crt'
367 | ```
368 |
369 | ## ssl_verify_depth
370 | 描述:设置客户证书认证链的长度
371 | 说明:开启双向SSL认证时使用
372 |
373 | 示例:
374 | ```php
375 | 'ssl_verify_depth' => 1
376 | ```
377 |
378 | ## ssl_method
379 | 描述:设置OpenSSL隧道加密的算法
380 | 说明:Server与Client使用的算法必须一致,否则SSL/TLS握手会失败,连接会被切断。 默认算法为 SWOOLE_SSLv23_METHOD
381 |
382 | >SWOOLE_SSLv3_METHOD
383 | SWOOLE_SSLv3_SERVER_METHOD
384 | SWOOLE_SSLv3_CLIENT_METHOD
385 | SWOOLE_SSLv23_METHOD(默认加密方法)
386 | SWOOLE_SSLv23_SERVER_METHOD
387 | SWOOLE_SSLv23_CLIENT_METHOD
388 | SWOOLE_TLSv1_METHOD
389 | SWOOLE_TLSv1_SERVER_METHOD
390 | SWOOLE_TLSv1_CLIENT_METHOD
391 | SWOOLE_TLSv1_1_METHOD
392 | SWOOLE_TLSv1_1_SERVER_METHOD
393 | SWOOLE_TLSv1_1_CLIENT_METHOD
394 | SWOOLE_TLSv1_2_METHOD
395 | SWOOLE_TLSv1_2_SERVER_METHOD
396 | SWOOLE_TLSv1_2_CLIENT_METHOD
397 | SWOOLE_DTLSv1_METHOD
398 | SWOOLE_DTLSv1_SERVER_METHOD
399 | SWOOLE_DTLSv1_CLIENT_METHOD
400 |
401 |
402 | 示例:
403 | ```php
404 | 'ssl_method' => SWOOLE_SSLv23_METHOD
405 | ```
406 |
407 | ## ssl_ciphers
408 | 描述:配置SSL加密套件
409 | 说明:启用http2协议后,Chrome/Firefox等浏览器要求必须使用高强度加密套件。某些低版本浏览器可能不支持默认的加密套件,可设置为空字符串兼容低版本浏览器
410 |
∂
411 |
412 | 示例:
413 | ```php
414 | 'ssl_ciphers' => 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH'
415 | ```
416 |
417 |
418 |
--------------------------------------------------------------------------------
/book/chapter01/chapter01.md:
--------------------------------------------------------------------------------
1 | # 环境搭建 Environment Setup
2 |
3 | ---
4 |
5 | 本章将详细介绍如何搭建Swoole的开发环境,包括PHP的安装、Swoole的安装、相关扩展的安装等等。
6 | This Chapter will introduce how to set up the development environment of Swoole, including the installation of PHP, Swoole extension and other related extensions.
7 | 通过学习本章,你可以学到如何快速搭建一套完整的Swoole开发环境。
8 | Going through this chapter, we can learn how to quick set up a complete Swoole development environment.
9 |
10 | ## 相关软件 Essentials
11 |
12 | | 类别 Type | 名称 Name | 版本 Version |
13 | | --- | --- | --- |
14 | | OS(Linux) | Ubuntu | 16.04 |
15 | | OS(Mac) | OSX | 10.11 |
16 | | 语言 Server Script | PHP | 5.6.22 |
17 | | 扩展 Extension | Swoole | 1.8.5-stable |
18 | | 扩展 Extension | Redis | 3.0.0 |
19 | | 数据库 Database | MySQL | 5.7.12 |
20 | | 数据库 Database | Redis | 3.0.7 |
21 |
22 | ## 相关框架 Related Frameworks
23 | | 类别 Type | 名称 Name | 版本 Version |
24 | | --- | --- | --- |
25 | | MVC | ZPHP | Master 分支 Branch |
26 | | MVC | Yaf | Master 分支 Branch |
27 | | RPC | Hprose | Master 分支 Branch |
28 | | PRC | Dora-RPC | Master 分支 Branch |
29 | | DB Model | ThinkPHP | 3.2.2 (仅使用Model模块 Only Model Used) |
30 |
--------------------------------------------------------------------------------
/book/chapter01/echo_server.md:
--------------------------------------------------------------------------------
1 | # 搭建Echo服务器 Start With An Echo Server!
2 |
3 | ---
4 |
5 | [TOC]
6 |
7 | 所有讲解网络通信编程的书籍都会最先讲解如何编写一个Echo服务器,本书也不例外。本章将讲解如何快速编写一个基于Swoole扩展的Echo服务器。
8 | Almost all network programming books start with teaching how to build an Echo Server. Well, we will do the same for this guide. In this chapter, we will learn how to quickly build an Echo Server based on Swoole!
9 |
10 | ## 服务端 Server
11 | 创建一个`Server.php`文件并输入如下内容:
12 | Create a file named 'Server.php' and type in following codes:
13 | ```php
14 | // Server
15 | class Server
16 | {
17 | private $serv;
18 |
19 | public function __construct() {
20 | $this->serv = new swoole_server("0.0.0.0", 9501);
21 | $this->serv->set(array(
22 | 'worker_num' => 8,
23 | 'daemonize' => false,
24 | ));
25 |
26 | $this->serv->on('Start', array($this, 'onStart'));
27 | $this->serv->on('Connect', array($this, 'onConnect'));
28 | $this->serv->on('Receive', array($this, 'onReceive'));
29 | $this->serv->on('Close', array($this, 'onClose'));
30 |
31 | $this->serv->start();
32 | }
33 |
34 | public function onStart( $serv ) {
35 | echo "Start\n";
36 | }
37 |
38 | public function onConnect( $serv, $fd, $from_id ) {
39 | $serv->send( $fd, "Hello {$fd}!" );
40 | }
41 |
42 | public function onReceive( swoole_server $serv, $fd, $from_id, $data ) {
43 | echo "Get Message From Client {$fd}:{$data}\n";
44 | $serv->send($fd, $data);
45 | }
46 |
47 | public function onClose( $serv, $fd, $from_id ) {
48 | echo "Client {$fd} close connection\n";
49 | }
50 | }
51 | // 启动服务器 Start the server
52 | $server = new Server();
53 | ```
54 |
55 | ## 客户端 Client
56 |
57 | 创建一个`Client.php`文件并输入如下内容:
58 | Create a file named 'Client.php' and type in following codes:
59 | ```php
60 | client = new swoole_client(SWOOLE_SOCK_TCP);
67 | }
68 |
69 | public function connect() {
70 | if( !$this->client->connect("127.0.0.1", 9501 , 1) ) {
71 | echo "Error: {$this->client->errMsg}[{$this->client->errCode}]\n";
72 | }
73 |
74 | fwrite(STDOUT, "请输入消息 Please input msg:");
75 | $msg = trim(fgets(STDIN));
76 | $this->client->send( $msg );
77 |
78 | $message = $this->client->recv();
79 | echo "Get Message From Server:{$message}\n";
80 | }
81 | }
82 |
83 | $client = new Client();
84 | $client->connect();
85 | ```
86 |
87 | ## 运行 Run it!
88 | 在Terminal下执行命令`php Server.php`即可启动服务器,在另一个Terminal下执行`php Client.php`,输入要发送的内容,即可发送消息到服务器,并收到来自服务器的消息。
89 | To start the Echo Server? Simply run command 'php Server.php' in Terminal. Then run command 'php Client.php' in another Terminal window and input whatever you want to send. Aha! See what's coming up in your Server's Terminal? Your messages are sent from the Client to the Server.
90 |
--------------------------------------------------------------------------------
/book/chapter01/install.md:
--------------------------------------------------------------------------------
1 |
2 | # 环境搭建 Environment Setup
3 |
4 | ---
5 |
6 | [TOC]
7 |
8 | # Linux环境下安装 Setup for Linux
9 |
10 | Linux操作系统通常都有自己的包管理软件(Ubuntu的apt-get,CentOS的yum,Mac OSX的HomeBrew等),因此一般情况下可以通过这些包管理软件直接安装PHP。但是这样安装的PHP不太适用于运行Swoole,因此本章将介绍如何通过源码编译安装。
11 | Linux has usually got its own package management tools (like apt-get for Ubuntu, yum for CentOS, HomeBrew for Mac OSX...). So for most of the cases, we can directly install php using those tools. But for Swoole, compiling the source codes to install is suggested.
12 |
13 | ## 编译环境 Compiling Environment
14 | 想要编译安装PHP首先需要安装对应的编译工具。
15 | Ubuntu上使用如下命令安装编译工具和依赖包:
16 | To successfully compile PHP, we have to get our compilers and other related tools ready.
17 | We can install compiling tools and dependencies by using commands:
18 |
19 | ```shell
20 | sudo apt-get install \
21 | build-essential \
22 | gcc \
23 | g++ \
24 | autoconf \
25 | libiconv-hook-dev \
26 | libmcrypt-dev \
27 | libxml2-dev \
28 | libmysqlclient-dev \
29 | libcurl4-openssl-dev \
30 | libjpeg8-dev \
31 | libpng12-dev \
32 | libfreetype6-dev \
33 | ```
34 |
35 | ## PHP安装 PHP Installation
36 |
37 | [PHP下载地址 Download](http://php.net/)
38 | 在这里挑选你想用的版本即可。下载源码包后,解压至本地任意目录(保证读写权限)。
39 | Download PHP of the version you want. Once done with that, extract it to any R/W directory.
40 |
41 | 使用如下命令编译安装PHP:
42 | Use following commands to compile and install PHP:
43 |
44 | ```shell
45 | cd php-5.6.22/
46 | ./configure --prefix=/usr/local/php \
47 | --with-config-file-path=/etc/php \
48 | --enable-fpm \
49 | --enable-pcntl \
50 | --enable-mysqlnd \
51 | --enable-opcache \
52 | --enable-sockets \
53 | --enable-sysvmsg \
54 | --enable-sysvsem \
55 | --enable-sysvshm \
56 | --enable-shmop \
57 | --enable-zip \
58 | --enable-soap \
59 | --enable-xml \
60 | --enable-mbstring \
61 | --disable-rpath \
62 | --disable-debug \
63 | --disable-fileinfo \
64 | --with-mysql=mysqlnd \
65 | --with-mysqli=mysqlnd \
66 | --with-pdo-mysql=mysqlnd \
67 | --with-pcre-regex \
68 | --with-iconv \
69 | --with-zlib \
70 | --with-mcrypt \
71 | --with-gd \
72 | --with-openssl \
73 | --with-mhash \
74 | --with-xmlrpc \
75 | --with-curl \
76 | --with-imap-ssl
77 |
78 | sudo make
79 | sudo make install
80 | sudo mkdir /etc/php
81 | sudo cp php.ini-development /etc/php/php.ini
82 | ```
83 | 注意,以上PHP编译选项根据实际情况可调整。
84 | To be sure, any of these compiling options is adjustable according to your specific needs.
85 |
86 | 另外,还需要将PHP的可执行目录添加到环境变量中。
87 | 使用Vim/Sublime打开~/.bashrc,在末尾添加如下内容:
88 | Also, we need to add PHP's bin directory to environment variables.
89 | Open file '~/.bashrc' by Vim/Sublime. And add following contents to the end of the file:
90 |
91 | ```shell
92 | export PATH=/usr/local/php/bin:$PATH
93 | export PATH=/usr/local/php/sbin:$PATH
94 | ```
95 | 保存后,终端输入命令:
96 | Having saved that, run following commands in Terminal:
97 |
98 | ```bash
99 | source ~/.bashrc
100 | ```
101 | 此时即可通过`php --version`查看php版本。
102 | Right now, you can check out the PHP version using `php --version`!
103 |
104 | # Mac环境下安装 Setup for Mac
105 | Mac系统自带PHP,但是Mac上对于OpenSSL的相关功能做了一些限制,使用了一个`Secure Transport`来取代OpenSSL。因此仍然建议重新编译安装PHP环境。
106 | MacOS comes with a certain version of PHP. But OpenSSL for that version is restricted and got replaced by `Secure Transport`. For that matter, reinstalling it in a code compiling way is still highly recommanded.
107 |
108 | ## 安装OpenSSL OpenSSL Installation
109 | Mac原装的0.9.8版本的OpenSSL使用的时候会有些Warning,反正我看不惯……
110 | The OpenSSL that comes with MacOS, while using, will produce some warnings. And why is that? Kill me to know...
111 | 安装命令:
112 | Installation Commands:
113 |
114 | ```shell
115 | brew install openssl
116 | ```
117 | 安装之后,还需要链接新的openssl到环境变量中。
118 | After that, we will need to link the new OpenSSL into environment variables.
119 | ```shell
120 | brew link --force openssl
121 | ```
122 |
123 | ## 安装Curl Curl Installation
124 | Mac系统原装的Curl默认使用了Secure Transport,导致通过option函数设置的证书全部无效。果断重新安装之。
125 | The Curl that comes with MacOS uses Secure Transport by default. That causes the invalid of all the certificates set by function 'option'. So reinstallation is a must.
126 |
127 | ```shell
128 | brew install curl --with-openssl && brew link curl --force
129 | ```
130 |
131 | ## 安装PHP PHP Installation
132 | PHP官网上下载某个版本的PHP(我选择的是5.6.22),使用如下命令编译安装。
133 | Download a version of PHP from PHP.net (for my case, it's 5.6.22). Compile source codes to install by using following commands:
134 |
135 | ```shell
136 | cd /path/to/php/
137 | ./configure
138 | --prefix=/usr/local/php
139 | --with-config-file-path=/etc/php
140 | --with-openssl=/usr/local/Cellar/openssl/1.0.2g/
141 | --with-curl=/usr/local/Cellar/curl/7.48.0/
142 |
143 | make && make install
144 | ```
145 | 这里我仅列出两个需要特殊设置的选项`with-openssl`和`with-curl`。
146 | Here I filled up two specific options `with-openssl` and `with-curl`.
147 | 安装完成后,执行如下命令:
148 | After installation, run following commands:
149 |
150 | ```shell
151 | sudo cp /usr/local/php/bin/php /usr/bin/
152 | sudo cp /usr/local/php/bin/phar* /usr/bin/
153 | sudo cp /usr/local/php/bin/php-config /usr/bin/
154 | sudo cp /usr/local/php/bin/phpize /usr/bin/
155 | ```
156 |
157 | 随后,设置php.ini
158 | Then, we can configure php.ini:
159 |
160 | ```shell
161 | sudo mkdir /etc/php
162 | sudo cp php.ini.development /etc/php/php.ini
163 | ```
164 |
165 | # Swoole扩展安装 Swoole Installation
166 | [Swoole扩展下载地址 Download](https://github.com/swoole/swoole-src/releases)
167 | 解压源码至任意目录,执行如下命令:
168 | Extact the codes to any directory and run following commands:
169 |
170 | ```shell
171 | cd swoole-src-swoole-1.7.6-stable/
172 | phpize
173 | ./configure
174 | sudo make
175 | sudo make install
176 | ```
177 |
178 | > swoole的./configure有很多额外参数,可以通过./configure --help命令查看,这里均选择默认项)
179 | > swoole's './configure' has got many optinal configurations. Check them out by using './configure --help'.
180 | Here we are just going to leave them default.
181 |
182 | 安装完成后,进入/etc/php目录下,打开php.ini文件,在其中加上如下一句:
183 | Having finished all that, go to the path '/etc/php' and edit php.ini. Add the following line to the file:
184 | ```bash
185 | extension=swoole.so
186 | ```
187 | 随后在终端中输入命令`php -m`查看扩展安装情况。如果在列出的扩展中看到了swoole,则说明安装成功。
188 | All Done! Use `php -m` to list all the extensions and see if swoole is around.
189 |
--------------------------------------------------------------------------------
/book/chapter02/chapter02.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LinkedDestiny/swoole-concise-guide/50801e3f4fa7eae39ab0274cff45a8a04ce085e4/book/chapter02/chapter02.md
--------------------------------------------------------------------------------
/book/chapter02/port.md:
--------------------------------------------------------------------------------
1 | # 多端口监听
2 |
3 | ---
4 |
5 | ## 多端口监听
6 |
7 | 在实际运用场景中,服务器可能需要监听不同host下的不同端口。比如,一个应用服务器,可能需要监听外网的服务端口,同时也需要监听内网的管理端口。在Swoole中,可以轻松的实现这样的功能。 Swoole提供了addlistener函数用于给服务器添加一个需要监听的host及port,并指定对应的Socket类型(TCP,UDP,Unix Socket以及对应的IPv4和IPv6版本)。 代码如下:
8 |
9 | ```php
10 | $serv = new swoole_server("192.168.1.1", 9501); // 监听外网的9501端口
11 | $serv->addlistener("127.0.0.1", 9502 , SWOOLE_TCP); // 监听本地的9502端口
12 | $serv->start(); // addlistener必须在start前调用
13 | ```
14 |
15 | 此时,swoole_server就会同时监听两个host下的两个端口。这里要注意的是,来自两个端口的数据会在同一个`onReceive`回调函数中获取到,这时就要用到swoole的另一个成员函数connection_info,通过这个函数获取到fd的from_port,就可以判定消息的类型。
16 |
17 | ```php
18 | $info = $serv->connection_info($fd, $from_id);
19 | //来自9502的内网管理端口
20 | if($info['from_port'] == 9502) {
21 | $serv->send($fd, "welcome admin\n");
22 | }
23 | //来自外网
24 | else {
25 | $serv->send($fd, 'Swoole: '.$data);
26 | }
27 |
28 | ```
29 |
30 | ## 多端口混合协议接听
31 |
32 | 通过上面的实例可以看到,使用上面的方法进行多端口监听有诸多的局限性:协议单一,回调函数无法区分等。在实际应用中,我们往往希望服务能够同时监听两个端口,并且两个端口分别采用不同的协议,比如一个端口采用RPC协议提供服务,另一个端口提供Http协议用于Web管理页面。
33 | 因此,Swoole从1.8.0版本开始提供了一套全新的多端口监听方式。在1.8.0以后的版本,Server可以监听多个端口,每个端口都可以设置不同的协议处理方式(set)和回调函数(on)
34 | 开始监听新端口的代码如下:
35 |
36 | ```php
37 | $port1 = $server->listen("127.0.0.1", 9501, SWOOLE_SOCK_TCP);
38 | $port2 = $server->listen("127.0.0.1", 9502, SWOOLE_SOCK_UDP);
39 | $port3 = $server->listen("127.0.0.1", 9503, SWOOLE_SOCK_TCP | SWOOLE_SSL);
40 | ```
41 |
42 | 可以看到,新添加的监听端口可以设置多种属性,监听的IP,端口号,TCP或者UDP,是否需要SSL加密。
43 | 除此之外,每个新建立的Port对象还可以分别设置配置选项,如下所示:
44 |
45 | ```php
46 | $port1->set( // 开启固定包头协议
47 | 'open_length_check' => true,
48 | 'package_length_type' => 'N',
49 | 'package_length_offset' => 0,
50 | 'package_max_length' => 800000,
51 | );
52 |
53 | $port3->set( // 开启EOF协议并设置SSL文件
54 | 'open_eof_split' => true,
55 | 'package_eof' => "\r\n",
56 | 'ssl_cert_file' => 'ssl.cert',
57 | 'ssl_key_file' => 'ssl.key',
58 | );
59 | ```
60 |
61 | 除了协议不同,每个Port还可以设置自己独有的回调函数,由此避免了在同一个回调函数里针对数据来源进行判定的问题。
62 |
63 | ```php
64 | $port1->on('receive', function ($serv, $fd, $from_id, $data) {
65 | $serv->send($fd, 'Swoole: '.$data);
66 | $serv->close($fd);
67 | });
68 | $port3->on('receive', function ($serv, $fd, $from_id, $data) {
69 | echo "Hello {$fd} : {$data}\n";
70 | });
71 | ```
72 |
73 | ### 注意事项
74 |
75 | * 未设置协议处理选项的监听端口,默认使用无协议模式
76 | * 未设置回调函数的监听端口,使用$server对象的回调函数
77 | * 监听端口返回的对象类型为swoole_server_port
78 | * 不同监听端口的回调函数,仍然是相同的Worker进程空间内执行
79 | * 主服务器是WebSocket或Http协议,新监听的TCP端口默认会继承主Server的协议设置。必须单独调用`set`方法设置新的协议才会启用新协议
--------------------------------------------------------------------------------
/book/chapter02/process.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LinkedDestiny/swoole-concise-guide/50801e3f4fa7eae39ab0274cff45a8a04ce085e4/book/chapter02/process.md
--------------------------------------------------------------------------------
/book/chapter02/sendfile.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LinkedDestiny/swoole-concise-guide/50801e3f4fa7eae39ab0274cff45a8a04ce085e4/book/chapter02/sendfile.md
--------------------------------------------------------------------------------
/book/chapter02/ssl.md:
--------------------------------------------------------------------------------
1 | # SSL支持
2 |
3 | ---
4 |
5 | 本章将详细讲解如何制作证书以及如何开启Swoole的SSL的单向、双向认证。
6 |
7 | ## 准备工作
8 | 选择任意路径,执行如下命令创建文件夹结构
9 |
10 | ```shell
11 | mkdir ca
12 | cd ca
13 | mkdir private
14 | mkdir server
15 | mkdir newcerts
16 | ```
17 |
18 | 在ca目录下创建`openssl.conf`文件,文件内容如下
19 | ```
20 | [ ca ]
21 | default_ca = foo # The default ca section
22 |
23 | [ foo ]
24 | dir = /path/to/ca # top dir
25 | database = /path/to/ca/index.txt # index file.
26 | new_certs_dir = /path/to/ca/newcerts # new certs dir
27 |
28 | certificate = /path/to/ca/private/ca.crt # The CA cert
29 | serial = /path/to/ca/serial # serial no file
30 | private_key = /path/to/ca/private/ca.key # CA private key
31 | RANDFILE = /path/to/ca/private/.rand # random number file
32 |
33 | default_days = 365 # how long to certify for
34 | default_crl_days= 30 # how long before next CRL
35 | default_md = md5 # message digest method to use
36 | unique_subject = no # Set to 'no' to allow creation of
37 | # several ctificates with same subject.
38 | policy = policy_any # default policy
39 |
40 | [ policy_any ]
41 | countryName = match
42 | stateOrProvinceName = match
43 | organizationName = match
44 | organizationalUnitName = match
45 | localityName = optional
46 | commonName = optional
47 | emailAddress = optional
48 | ```
49 |
50 | 其中,`/path/to/ca/`是ca目录的绝对路径。
51 |
52 | ## 创建ca证书
53 |
54 | 在ca目录下创建一个shell脚本,命名为`new_ca.sh`。文件内容如下:
55 | ```bash
56 | #!/bin/sh
57 | openssl genrsa -out private/ca.key
58 | openssl req -new -key private/ca.key -out private/ca.csr
59 | openssl x509 -req -days 365 -in private/ca.csr -signkey private/ca.key -out private/ca.crt
60 | echo FACE > serial
61 | touch index.txt
62 | openssl ca -gencrl -out private/ca.crl -crldays 7 -config "./openssl.conf"
63 | ```
64 |
65 | 执行`sh new_ca.sh`命令,创建ca证书。生成的证书存放于private目录中。
66 |
67 | > **注意**
68 | 在创建ca证书的过程中,需要输入一些信息。其中,countryName、stateOrProvinceName、organizationName、organizationalUnitName这四个选项的内容必须要填写,并且需要记住。在生成后续的证书过程中,要保证这四个选项的内容一致。
69 |
70 | ## 创建服务端证书
71 | 在ca目录下创建一个shell脚本,命名为`new_server.sh`。文件内容如下:
72 | ```bash
73 | #!/bin/sh
74 | openssl genrsa -out server/server.key
75 | openssl req -new -key server/server.key -out server/server.csr
76 | openssl ca -in server/server.csr -cert private/ca.crt -keyfile private/ca.key -out server/server.crt -config "./openssl.conf"
77 | ```
78 | 执行`sh new_ca.sh`命令,创建ca证书。生成的证书存放于server目录中。
79 |
80 | ## 创建客户端证书
81 | 在ca目录下创建一个shell脚本,命名为`new_client.sh`。文件内容如下:
82 | ```bash
83 | #!/bin/sh
84 |
85 | base="./"
86 | mkdir -p $base/users/
87 | openssl genrsa -des3 -out $base/users/client.key 1024
88 | openssl req -new -key $base/users/client.key -out $base/users/client.csr
89 | openssl ca -in $base/users/client.csr -cert $base/private/ca.crt -keyfile $base/private/ca.key -out $base/users/client.crt -config "./openssl.conf"
90 | openssl pkcs12 -export -clcerts -in $base/users/client.crt -inkey $base/users/client.key -out $base/users/client.p12
91 | ```
92 | 执行`sh new_ca.sh`命令,创建ca证书。生成的证书存放于users目录中。
93 | 进入users目录,可以看到有一个`client.p12`文件,这个就是客户端可用的证书了,但是这个证书是不能在php中使用的,因此需要做一次转换。命令如下:
94 |
95 | ```shell
96 | openssl pkcs12 -clcerts -nokeys -out cer.pem -in client.p12
97 | openssl pkcs12 -nocerts -out key.pem -in client.p12
98 | ```
99 | 以上两个命令会生成cer.pem和key.pem两个文件。其中,生成key.pem时会要求设置密码,这里记为`client_pwd`
100 |
101 | > **注意**
102 | 如果在创建客户端证书时,就已经给client.p12设置了密码,那么在转换格式的时候,需要输入密码进行转换
103 |
104 | ## 最终结果
105 | 以上步骤执行结束后,会得到不少文件,其中需要用的文件如下表所示:
106 | | 文件名 | 路径 | 说明 |
107 | | --- | --- | --- |
108 | | ca.crt | ca/private/ | ca证书 |
109 | | server.crt | ca/server/ | 服务器端证书 |
110 | | server.key | ca/server/ | 服务器端秘钥 |
111 | | cer.pem | ca/client/ | 客户端证书 |
112 | | key.pem | ca/client/ | 客户端秘钥 |
113 |
114 | # SSL单向认证
115 |
116 | ## Swoole开启SSL
117 | Swoole开启SSL功能需要如下参数:
118 |
119 | ```php
120 | $server = new swoole_server("127.0.0.1", "9501" , SWOOLE_PROCESS, SWOOLE_SOCK_TCP | SWOOLE_SSL );
121 | $server = new swoole_http_server("127.0.0.1", "9501" , SWOOLE_PROCESS, SWOOLE_SOCK_TCP | SWOOLE_SSL );
122 | ```
123 | 并在swoole的配置选项中增加如下两个选项:
124 |
125 | ```php
126 | $server->set(array(
127 | 'ssl_cert_file' => '/path/to/server.crt',
128 | 'ssl_key_file' => '/path/to/server.key',
129 | ));
130 | ```
131 |
132 | 这时,swoole服务器就已经开启了单向SSL认证,可以通过`https://127.0.0.1:9501/`进行访问。
133 |
134 | # SSL双向认证
135 |
136 | ## 服务器端设置
137 | 双向认证指服务器也要对发起请求的客户端进行认证,只有通过认证的客户端才能进行访问。
138 | 为了开启SSL双向认证,swoole需要额外的配置参数如下:
139 |
140 | ```php
141 | $server->set(array(
142 | 'ssl_cert_file' => '/path/to/server.crt',
143 | 'ssl_key_file' => '/path/to/server.key',
144 | 'ssl_client_cert_file' => '/path/to/ca.crt',
145 | 'ssl_verify_depth' => 10,
146 | ));
147 | ```
148 |
149 | ## 客户端设置
150 | 这里我们使用CURL进行https请求的发起。
151 | 首先,需要配置php.ini,增加如下配置:
152 |
153 | ```
154 | curl.cainfo=/path/to/ca.crt
155 | ```
156 |
157 | 发起curl请求时,增加如下配置项:
158 | ```php
159 | $ch = curl_init();
160 |
161 | curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, '2');
162 | curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true); // 只信任CA颁布的证书
163 | curl_setopt($ch, CURLOPT_SSLCERT, "/path/to/cer.pem");
164 | curl_setopt($ch, CURLOPT_SSLKEY, "/path/to/key.pem");
165 | curl_setopt($ch, CURLOPT_SSLCERTTYPE, 'PEM');
166 | curl_setopt($ch, CURLOPT_SSLCERTPASSWD, '******'); // 创建客户端证书时标记的client_pwd密码
167 | ```
168 |
169 | 这时,就可以发起一次https请求,并且被swoole服务器验证通过了。
170 |
171 |
172 |
173 |
174 |
175 |
--------------------------------------------------------------------------------
/book/chapter02/table.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LinkedDestiny/swoole-concise-guide/50801e3f4fa7eae39ab0274cff45a8a04ce085e4/book/chapter02/table.md
--------------------------------------------------------------------------------
/book/chapter02/task_worker.md:
--------------------------------------------------------------------------------
1 | # Task Worker
2 |
3 | ---
4 |
5 |
6 |
7 | ## 简介
8 |
9 | Task Worker是Swoole中一种特殊的工作进程,该进程的作用是处理一些耗时较长的任务,以达到释放Worker进程的目的。Worker进程可以通过`swoole_server`对象的task方法投递一个任务到Task Worker进程.
10 |
11 | Worker进程通过Unix Sock管道将数据发送给Task Worker,这样Worker进程就可以继续处理新的逻辑,无需等待耗时任务的执行。需要注意的是,由于Task Worker是独立进程,因此无法直接在两个进程之间共享全局变量,需要使用Redis、MySQL或者swoole_table来实现进程间共享数据。
12 |
13 | ## 实例
14 |
15 | 要使用Task Worker,需要进行一些必要的操作。
16 |
17 | 首先,需要设置swoole_server的配置参数:
18 |
19 | ```php
20 | $serv->set(array(
21 | 'task_worker_num' => 2, // 设置启动2个task进程
22 | ));
23 | ```
24 |
25 | 接着,绑定必要的回调函数:
26 |
27 | ```php
28 | $serv->on('Task', 'onTask');
29 | $serv->on('Finish','onFinish');
30 | ```
31 | 其中两个回调函数的原型如下所示:
32 |
33 | ```php
34 | /**
35 | * @param $serv swoole_server swoole_server对象
36 | * @param $task_id int 任务id
37 | * @param $from_id int 投递任务的worker_id
38 | * @param $data string 投递的数据
39 | */
40 | function onTask(swoole_server $serv, $task_id, $from_id, $data);
41 |
42 | /**
43 | * @param $serv swoole_server swoole_server对象
44 | * @param $task_id int 任务id
45 | * @param $data string 任务返回的数据
46 | */
47 | function onFinish(swoole_server $serv, $task_id, $data);
48 | ```
49 |
50 | 在实际逻辑中,当需要发起一个任务请求时,可以使用如下方法调用:
51 |
52 | ```php
53 | $data = "task data";
54 | $serv->task($data , -1 ); // -1代表不指定task进程
55 |
56 | // 在1.8.6+的版本中,可以动态指定onFinish函数
57 | $serv->task($data, -1, function (swoole_server $serv, $task_id, $data) {
58 | echo "Task Finish Callback\n";
59 | });
60 | ```
61 |
--------------------------------------------------------------------------------
/book/chapter02/timer.md:
--------------------------------------------------------------------------------
1 | # Timer定时器
2 |
3 | ---
4 |
5 | ## 定时器原理
6 |
7 | Timer定时器是Swoole扩展提供的一个毫秒级定时器,其作用是每隔指定的时间间隔之后执行一次指定的回调函数,以实现定时执行任务的功能。
8 | 新版本的Swoole中,定时器是基于epoll方法的timeout机制实现的,不再依赖于单独的定时线程,准确度更高。同时,Swoole扩展使用最小堆存储定时器,减少定时器的检索次数,提高了运行效率。
9 |
10 | ## 定时器使用
11 |
12 | 在Swoole中,定时器的函数原型如下:
13 |
14 | ```php
15 |
16 | // function onTimer(int $timer_id, mixed $params = null); // 回调函数的原型
17 | int swoole_timer_tick(int $ms, mixed $callback, mixed $param = null);
18 | int swoole_server::tick(int $ms, mixed $callback, mixed $param = null);
19 |
20 | // function onTimer(); // 回调函数的原型(不接受任何参数)
21 | void swoole_timer_after(int $after_time_ms, mixed $callback_function);
22 | void swoole_server::after(int $after_time_ms, mixed $callback_function);
23 | ```
24 |
25 | tick定时器是一个永久定时器,使用tick方法创建的定时器会一直运行,每隔指定的毫秒数之后执行一次callback函数。在创建定时器的时候,可以通过tick函数的第三个参数,传递一些自定义参数到callback回调函数中。另外,也可以使用PHP的闭包(use关键字)实现传参。具体实例如下:
26 |
27 | ```php
28 | $str = "Say ";
29 | $timer_id = swoole_timer_tick( 1000 , function($timer_id , $params) use ($str) {
30 | echo $str . $params; // 输出“Say Hello”
31 |
32 | } , "Hello" );
33 |
34 | ```
35 |
36 | tick函数会返回定时器的id。当我们不再需要某个定时器的时候,可以根据这个id,调用`swoole_timer_clear`函数删除定时器。需要注意的是,创建的定时器是不能跨进程的,因此,在一个Worker进程中创建的定时器,也只能在这个Worker进程中删除,这一点一定要注意(使用`$worker_id`变量来区分Worker进程);
37 |
38 | after定时器是一个临时定时器。使用after方法创建的定时器仅在指定毫秒数之后执行一次callback函数,执行完成后定时器就会删除。after定时器的回调函数不接受任何参数,可以通过闭包方式传递参数,也可以通过类成员变量的方式传递。具体实例如下:
39 |
40 | ```php
41 |
42 | class Test
43 | {
44 | private $str = "Say Hello";
45 | public function onAfter()
46 | {
47 | echo $this->str; // 输出”Say Hello“
48 | }
49 | }
50 |
51 | $test = new Test();
52 | swoole_timer_after(1000, array($test, "onAfter"); // 成员变量
53 |
54 | swoole_timer_after(2000, function() use($test){ // 闭包
55 | $test->onAfter(); // 输出”Say Hello“
56 | });
57 |
58 | ```
59 |
--------------------------------------------------------------------------------
/book/chapter02/worker.md:
--------------------------------------------------------------------------------
1 | # Worker进程
2 |
3 | ---
4 |
5 |
6 |
7 | ## Swoole进程模型
8 |
9 | 首先,我们需要了解一下Swoole的进程模型。Swoole是一个多进程模式的框架(可以类比Nginx的进程模型),当启动一个Swoole应用时,一共会创建2 + n + m个进程,其中n为Worker进程数,m为TaskWorker进程数,2为一个Master进程和一个Manager进程,它们之间的关系如下图所示。
10 |
11 | 
12 |
13 | 其中,Master进程为主进程,该进程会创建Manager进程、Reactor线程等工作进/线程。
14 |
15 | * Reactor线程实际运行epoll实例,用于accept客户端连接以及接收客户端数据;
16 | * Manager进程为管理进程,该进程的作用是创建、管理所有的Worker进程和TaskWorker进程。
17 |
18 | ## Worker进程简介
19 | Worker进程作为Swoole的工作进程,所有的业务逻辑代码均在此进程上运行。当Reactor线程接收到来自客户端的数据后,会将数据打包通过管道发送给某个Worker进程(数据分配方法见[dispatch_mode](http://www.baidu.com))。
20 |
21 |
22 | ## Worker进程生命周期
23 |
24 | 一个Worker进程的生命周期如图所示:
25 |
26 |
41 | 当一个Worker进程被成功创建后,会调用`onWorkerStart`回调,随后进入事件循环等待数据。当通过回调函数接收到数据后,开始处理数据。如果处理数据过程中出现严重错误导致进程退出,或者Worker进程处理的总请求数达到指定上限,则Worker进程调用`onWorkerStop`回调并结束进程。
42 |
43 |
--------------------------------------------------------------------------------
/book/preface.md:
--------------------------------------------------------------------------------
1 | # 写在前面的话
2 |
3 | 本书默认读者已具备如下能力:
4 |
5 | * 熟练使用PHP语言
6 | * 熟练使用MySQL、Redis数据库
7 | * 熟练使用Linux操作系统
8 | * 基本了解Unix网络编程相关知识(参阅《Unix网络编程(卷1)》)
9 | * 基本的gdb使用
10 |
11 | 第一章将讲解如何配置PHP&Swoole的开发环境,会一步步列出安装所需的依赖和命令。
12 |
13 | 第二章将讲解Swoole的基本功能和配置选项,包括Worker进程、Task Worker进程、Timer计时器、Process进程、swoole_table内存表等,也会讲解这些功能的基本使用方法。
14 |
15 | 第三章将讲解Swoole的内置协议部分,讲解如何自定义TCP的应用层通信协议。同时也会介绍Swoole内置的多种协议解析方式,比如Http服务器、WebSocket服务器等等。
16 |
17 | 第四章将讲解Swoole Client的相关内容,讲解如何创建和使用Swoole提供的多种Client,如TCP Client、异步Http Client、异步MySQL Client等。
18 |
19 | 第五章将讲解Swoole的异步IO部分,包括异步文件读写和异步EventLoop事件循环。
20 |
21 | 第六章将讲解Swoole的一些实战用法,比如使用Task进程进行异步任务处理、使用Process执行监控命令等
22 |
23 | 第七章将讲解Swoole的一些相关框架,比如ZPHP,Hprose,Dora-rpc等等
24 |
25 | 第八章将讲解Swoole与一些现有框架的结合,比如Swoole-Yaf,Swoole-Phalcon等
26 |
27 | 第九章开始将讲解Swoole实战,通过一些实际项目来深入了解Swoole的应用。(构思中)
--------------------------------------------------------------------------------
/code/.gitignore:
--------------------------------------------------------------------------------
1 | .idea/
2 | ./
--------------------------------------------------------------------------------
/code/process/process.php:
--------------------------------------------------------------------------------
1 | name("new worker");
13 | sleep(1);
14 | echo "process shtudown\n";
15 | $worker->exit(0);
16 | });
17 |
18 | $pid = $process->start();
19 | swoole_process::wait();
20 | });
--------------------------------------------------------------------------------
/code/protocol/WebSocketClient.php:
--------------------------------------------------------------------------------
1 | host = $host;
61 | $this->port = $port;
62 | $this->path = $path;
63 | $this->origin = $origin;
64 | $this->key = $this->generateToken(self::TOKEN_LENGHT);
65 | }
66 |
67 | /**
68 | * Disconnect on destruct
69 | */
70 | function __destruct()
71 | {
72 | $this->disconnect();
73 | }
74 |
75 | /**
76 | * Connect client to server
77 | *
78 | * @return $this
79 | */
80 | public function connect()
81 | {
82 | $this->socket = new \swoole_client(SWOOLE_SOCK_TCP);
83 | if (!$this->socket->connect($this->host, $this->port))
84 | {
85 | return false;
86 | }
87 | $this->socket->send($this->createHeader());
88 | return $this->recv();
89 | }
90 |
91 | public function getSocket()
92 | {
93 | return $this->socket;
94 | }
95 |
96 | /**
97 | * Disconnect from server
98 | */
99 | public function disconnect()
100 | {
101 | $this->connected = false;
102 | $this->socket->close();
103 | }
104 |
105 | public function close($code = self::CLOSE_NORMAL, $reason = '')
106 | {
107 | $data = pack('n', $code) . $reason;
108 | return $this->socket->send(swoole_websocket_server::pack($data, self::OPCODE_CONNECTION_CLOSE, true));
109 | }
110 |
111 | public function recv()
112 | {
113 | $data = $this->socket->recv();
114 | if ($data === false)
115 | {
116 | echo "Error: {$this->socket->errMsg}";
117 | return false;
118 | }
119 | $this->buffer .= $data;
120 | $recv_data = $this->parseData($this->buffer);
121 | if ($recv_data)
122 | {
123 | $this->buffer = '';
124 | return $recv_data;
125 | }
126 | else
127 | {
128 | return false;
129 | }
130 | }
131 |
132 | /**
133 | * @param string $data
134 | * @param string $type
135 | * @param bool $masked
136 | * @return bool
137 | */
138 | public function send($data, $type = 'text', $masked = false)
139 | {
140 | switch($type)
141 | {
142 | case 'text':
143 | $_type = WEBSOCKET_OPCODE_TEXT;
144 | break;
145 | case 'binary':
146 | case 'bin':
147 | $_type = WEBSOCKET_OPCODE_BINARY;
148 | break;
149 | default:
150 | return false;
151 | }
152 | return $this->socket->send(swoole_websocket_server::pack($data, $_type, true, $masked));
153 | }
154 |
155 | /**
156 | * Parse received data
157 | *
158 | * @param $response
159 | */
160 | private function parseData($response)
161 | {
162 | if (!$this->connected)
163 | {
164 | $response = $this->parseIncomingRaw($response);
165 | if (isset($response['Sec-Websocket-Accept'])
166 | && base64_encode(pack('H*', sha1($this->key . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'))) === $response['Sec-Websocket-Accept']
167 | )
168 | {
169 | $this->connected = true;
170 | return true;
171 | }
172 | else
173 | {
174 | throw new \Exception("error response key.");
175 | }
176 | }
177 |
178 | return swoole_websocket_server::unpack($response);
179 | }
180 |
181 | /**
182 | * Create header for websocket client
183 | *
184 | * @return string
185 | */
186 | private function createHeader()
187 | {
188 | $host = $this->host;
189 | if ($host === '127.0.0.1' || $host === '0.0.0.0')
190 | {
191 | $host = 'localhost';
192 | }
193 | return "GET {$this->path} HTTP/1.1" . "\r\n" .
194 | "Origin: {$this->origin}" . "\r\n" .
195 | "Host: {$host}:{$this->port}" . "\r\n" .
196 | "Sec-WebSocket-Key: {$this->key}" . "\r\n" .
197 | "User-Agent: PHPWebSocketClient/" . self::VERSION . "\r\n" .
198 | "Upgrade: websocket" . "\r\n" .
199 | "Connection: Upgrade" . "\r\n" .
200 | "Sec-WebSocket-Protocol: wamp" . "\r\n" .
201 | "Sec-WebSocket-Version: 13" . "\r\n" . "\r\n";
202 | }
203 |
204 | /**
205 | * Parse raw incoming data
206 | *
207 | * @param $header
208 | *
209 | * @return array
210 | */
211 | private function parseIncomingRaw($header)
212 | {
213 | $retval = array();
214 | $content = "";
215 | $fields = explode("\r\n", preg_replace('/\x0D\x0A[\x09\x20]+/', ' ', $header));
216 | foreach ($fields as $field)
217 | {
218 | if (preg_match('/([^:]+): (.+)/m', $field, $match))
219 | {
220 | $match[1] = preg_replace_callback('/(?<=^|[\x09\x20\x2D])./',
221 | function ($matches)
222 | {
223 | return strtoupper($matches[0]);
224 | },
225 | strtolower(trim($match[1])));
226 | if (isset($retval[$match[1]]))
227 | {
228 | $retval[$match[1]] = array($retval[$match[1]], $match[2]);
229 | }
230 | else
231 | {
232 | $retval[$match[1]] = trim($match[2]);
233 | }
234 | }
235 | else
236 | {
237 | if (preg_match('!HTTP/1\.\d (\d)* .!', $field))
238 | {
239 | $retval["status"] = $field;
240 | }
241 | else
242 | {
243 | $content .= $field . "\r\n";
244 | }
245 | }
246 | }
247 | $retval['content'] = $content;
248 | return $retval;
249 | }
250 |
251 | /**
252 | * Generate token
253 | *
254 | * @param int $length
255 | *
256 | * @return string
257 | */
258 | private function generateToken($length)
259 | {
260 | $characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"§$%&/()=[]{}';
261 | $useChars = array();
262 | // select some random chars:
263 | for ($i = 0; $i < $length; $i++)
264 | {
265 | $useChars[] = $characters[mt_rand(0, strlen($characters) - 1)];
266 | }
267 | // Add numbers
268 | array_push($useChars, rand(0, 9), rand(0, 9), rand(0, 9));
269 | shuffle($useChars);
270 | $randomString = trim(implode('', $useChars));
271 | $randomString = substr($randomString, 0, self::TOKEN_LENGHT);
272 | return base64_encode($randomString);
273 | }
274 |
275 | /**
276 | * Generate token
277 | *
278 | * @param int $length
279 | *
280 | * @return string
281 | */
282 | public function generateAlphaNumToken($length)
283 | {
284 | $characters = str_split('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789');
285 | srand((float)microtime() * 1000000);
286 | $token = '';
287 | do
288 | {
289 | shuffle($characters);
290 | $token .= $characters[mt_rand(0, (count($characters) - 1))];
291 | } while (strlen($token) < $length);
292 | return $token;
293 | }
294 | }
295 |
--------------------------------------------------------------------------------
/code/protocol/async_client.php:
--------------------------------------------------------------------------------
1 | set(array(
10 | 'open_eof_check' => true,
11 | 'package_eof' => "\r\n",
12 | 'open_eof_split' => true,
13 | ));
14 |
15 | $client->on("connect", function(swoole_client $cli) {
16 | $data = str_repeat("1234567890" , 8);
17 |
18 | $cli->send($data . "\r\n");
19 | });
20 | $client->on("receive", function(swoole_client $cli, $data){
21 | echo "Receive: $data";
22 | });
23 |
24 | $client->on("error", function(swoole_client $cli){
25 | echo "error\n";
26 | });
27 |
28 | $client->on("close", function(swoole_client $cli){
29 | echo "Connection close\n";
30 | });
31 |
32 | $client->connect('127.0.0.1', 9502);
--------------------------------------------------------------------------------
/code/protocol/client.php:
--------------------------------------------------------------------------------
1 | connect();
8 | //echo $data;
9 | $data = "data";
10 |
11 | $client->send("hello swoole data:" . $data);
12 | $tmp = $client->recv();
13 |
--------------------------------------------------------------------------------
/code/protocol/cross_send.php:
--------------------------------------------------------------------------------
1 | serv = new swoole_websocket_server("0.0.0.0", 9501);
17 | $this->serv->set(array(
18 | 'worker_num' => 8,
19 | 'daemonize' => false,
20 | 'max_request' => 10000,
21 | 'dispatch_mode' => 2,
22 | 'debug_mode'=> 1 ,
23 | ));
24 |
25 | $this->serv->on('Message', array($this, 'onMessage'));
26 | $this->serv->on('Close', array($this, 'onWsClose'));
27 |
28 | $this->port = $this->serv->listen("0.0.0.0", 9502, SWOOLE_TCP);
29 | $this->port->set([
30 | 'open_eof_split' => true,
31 | 'package_eof' => "\r\n",
32 | ]);
33 | $this->port->on('Connect', array($this, 'onConnect'));
34 | $this->port->on('Receive', array($this, 'onReceive'));
35 | $this->serv->on('Close', array($this, 'onClose'));
36 |
37 | $this->serv->start();
38 | }
39 |
40 | public function onConnect( $serv, $fd, $from_id ) {
41 | echo "Client {$fd} connect\n";
42 | }
43 |
44 | public function onReceive( swoole_server $serv, $fd, $from_id, $data ) {
45 | echo "Get Message From Client {$fd}:{$data}\n";
46 | var_dump($serv->exist($fd));
47 | }
48 |
49 | public function onClose( $serv, $fd, $from_id ) {
50 | echo "Client {$fd} close connection\n";
51 | }
52 |
53 | public function onMessage( swoole_server $server, swoole_websocket_frame $frame) {
54 | echo "Get Message From WS {$frame->fd}:{$frame->data}\n";
55 | foreach($server->connections as $fd)
56 | {
57 | $connection_info = $server->connection_info($fd);
58 | if( $connection_info['server_port'] == 9502 )
59 | {
60 | var_dump("hello");
61 | $server->send($fd, "hello\r\n");
62 | }
63 | }
64 | }
65 |
66 | public function onOpen(swoole_websocket_server $svr, swoole_http_request $req)
67 | {
68 |
69 | }
70 | public function onWsClose( $serv, $fd, $from_id ) {
71 | echo "Client {$fd} close connection\n";
72 | }
73 | }
74 |
75 | new Server();
--------------------------------------------------------------------------------
/code/server.php:
--------------------------------------------------------------------------------
1 | serv = new swoole_server("0.0.0.0", 9501);
17 | $this->serv->set(array(
18 | 'worker_num' => 8,
19 | 'daemonize' => false,
20 | 'max_request' => 10000,
21 | 'dispatch_mode' => 2,
22 | 'debug_mode'=> 1 ,
23 | 'open_eof_split' => true,
24 | 'package_max_length' => 819200,
25 | 'open_eof_check' => true,
26 | 'package_eof' => "\r\n",
27 | ));
28 |
29 |
30 | $this->serv->on('Connect', array($this, 'onConnect'));
31 | $this->serv->on('Receive', array($this, 'onReceive'));
32 | $this->serv->on('Close', array($this, 'onClose'));
33 |
34 | $this->serv->start();
35 | }
36 |
37 | public function onConnect( $serv, $fd, $from_id ) {
38 | echo "Client {$fd} connect\n";
39 | }
40 |
41 | public function onReceive( swoole_server $serv, $fd, $from_id, $data ) {
42 | $len = strlen($data);
43 | echo "Get Message From Client {$fd}:{$len}\n";
44 | var_dump($serv->exist($fd));
45 | }
46 |
47 | public function onClose( $serv, $fd, $from_id ) {
48 | echo "Client {$fd} close connection\n";
49 | }
50 |
51 | }
52 |
53 | new Server();
--------------------------------------------------------------------------------
/code/task/simple_task.php:
--------------------------------------------------------------------------------
1 | serv = new swoole_server("0.0.0.0", 9501);
15 | $this->serv->set(array(
16 | 'worker_num' => 1,
17 |
18 | 'open_eof_split' => true,
19 | 'package_eof' => "\r\n",
20 |
21 | 'task_worker_num' => 2,
22 | ));
23 | $this->serv->on('Connect', array($this, 'onConnect'));
24 | $this->serv->on('Receive', array($this, 'onReceive'));
25 | $this->serv->on('Close', array($this, 'onClose'));
26 |
27 | $this->serv->on('Task', array($this, 'onTask'));
28 | $this->serv->on('Finish', array($this, 'onFinish'));
29 |
30 | $this->serv->start();
31 | }
32 |
33 | public function onConnect( $serv, $fd, $from_id ) {
34 | echo "Client {$fd} connect\n";
35 | }
36 |
37 | public function onReceive( swoole_server $serv, $fd, $from_id, $data ) {
38 | echo "Get Message From Client {$fd}:{$data}\n";
39 |
40 | echo "Send Task\n";
41 | $serv->task("Hello Task");
42 | }
43 |
44 | public function onClose( $serv, $fd, $from_id ) {
45 | echo "Client {$fd} close connection\n";
46 | }
47 |
48 | /**
49 | * @param $serv swoole_server swoole_server对象
50 | * @param $task_id int 任务id
51 | * @param $from_id int 投递任务的worker_id
52 | * @param $data string 投递的数据
53 | */
54 | public function onTask($serv, $task_id, $from_id, $data)
55 | {
56 | echo "Handle Task {$task_id} : {$data}\n";
57 |
58 | //$serv->finish("Task End");
59 | return "Task End";
60 | }
61 |
62 | public function onFinish(swoole_server $serv, $task_id, $data)
63 | {
64 | echo "Task {$task_id} finish: {$data}\n";
65 | }
66 | }
67 |
68 | new SimpleTask();
--------------------------------------------------------------------------------
/code/test.php:
--------------------------------------------------------------------------------
1 | on("connect", function(swoole_client $cli) {
11 | echo "connected\n";
12 | $cli->send("hello world\n");
13 | });
14 | $client->on('close', function($cli){
15 | echo "closed\n";
16 | });
17 | $client->on('error', function($cli){
18 | echo "error\n";
19 | });
20 | $client->on("receive", function(swoole_client $cli, $data){
21 | echo "received: $data\n";
22 |
23 | //$cli->send("hello_".rand(1000,9999));
24 | });
25 | $client->connect('127.0.0.1', 9501, 0.5);
--------------------------------------------------------------------------------
/code/udp/udp_server.php:
--------------------------------------------------------------------------------
1 | set(['worker_num' => 2]);
11 | $server->on('Packet', function (swoole_server $serv, $data, $addr)
12 | {
13 | // save $addr
14 | swoole_timer_tick(1000, function() use($serv, $addr){
15 | $serv->sendto($addr['address'], $addr['port'], "Swoole: Hello\n");
16 | });
17 |
18 | });
19 | //$server->on('receive', function (swoole_server $serv, $fd, $reactor_id, $data)
20 | //{
21 | // var_dump($data);
22 | // var_dump($serv->connection_info($fd, $reactor_id));
23 | //});
24 | $server->start();
--------------------------------------------------------------------------------