1. 0.0.0.0
表示监听所有IP地址,一台服务器可能同时有多个IP,如127.0.0.1
本地回环IP、192.168.1.100
局域网IP、210.127.20.2
外网IP。
2. WebSocket服务器是建立在Http服务器之上的长连接服务器,客户端首先会发送一个Http的请求与服务器进行握手。握手成功后会触发onOpen事件,表示连接已就绪,onOpen函数中可以得到$request
对象,包含了Http握手的相关信息,如GET参数、Cookie、Http头信息等。
建立连接后客户端与服务器端就可以双向通信了。
3.不能直接使用swoole_client与websocket服务器通信,swoole_client是TCP客户端
必须实现WebSocket协议才能和WebSocket服务器通信,可以使用swoole/framework提供的PHP WebSocket客户端
WebSocket服务器除了提供WebSocket功能之外,实际上也可以处理Http长连接。只需要增加onRequest
事件监听即可实现Comet方案Http长轮询。
4.swoole提供了类似JavaScript的setInterval
/setTimeout
异步高精度定时器,粒度为毫秒级。使用也非常简单。
5.TCP协议在底层机制上解决了UDP协议的顺序和丢包重传问题。但相比UDP又带来了新的问题,TCP协议是流式的,数据包没有边界。应用程序使用TCP通信就会面临这些难题。
因为TCP通信是流式的,在接收1个大数据包时,可能会被拆分成多个数据包发送。多次Send底层也可能会合并成一次进行发送。这里就需要2个操作来解决:
- 分包:Server收到了多个数据包,需要拆分数据包
- 合包:Server收到的数据只是包的一部分,需要缓存数据,合并成完整的包
所以TCP网络通信时需要设定通信协议。常见的TCP网络通信协议有HTTP
、HTTPS
、FTP
、SMTP
、POP3
、IMAP
、SSH
、Redis
、Memcache
、MySQL
。
如果要设计一个通用协议的Server,那么就要按照通用协议的标准去处理网络数据。
6.EOF协议处理的原理是每个数据包结尾加一串特殊字符表示包已结束。如memcache
、ftp
、stmp
都使用\r\n
作为结束符。发送数据时只需要在包末尾增加\r\n
即可。使用EOF协议处理,一定要确保数据包中间不会出现EOF,否则会造成分包错误。
7.固定包头的协议非常通用,在BAT的服务器程序中经常能看到。这种协议的特点是一个数据包总是由包头+包体2部分组成。包头由一个字段指定了包体或整个包的长度,长度一般是使用2字节/4字节整数来表示。服务器收到包头后,可以根据长度值来精确控制需要再接收多少数据就是完整的数据包。Swoole的配置可以很好的支持这种协议,可以灵活地设置4项参数应对所有情况。
8.PHP底层对stat
系统调用增加了Cache,在使用stat
、fstat
、fitlemtime
等函数时,底层可能会命中缓存,返回历史数据。
可以使用clearstatcache
函数清理文件stat
缓存。
9.版本类型
- alpha 特性预览版本,表示开发计划中的任务已完成,进行开放预览,可能会存在较多BUG
- beta 测试版本,表示已经可以用于开发环境测试,可能存在BUG
- rc[1-n] 候选发布版本,表示进入发布周期,正在做大范围的测试,在此期间仍可能发现BUG
- stable 稳定版,表示此版本已完毕,可正式投入使用
单双数版本
- 单数版本为特性新增版本,主要工作是新增功能特性、代码重构、结构调整。可能会带来一些BUG。
- 双数版本为问题修复版本,主要工作是修复现有的已知问题、提升性能、完善细节。稳定性更高
10.通常,如果一个业务请求中需要做一次redis请求和一次mysql请求,那么网络IO会是这样:
redis发包->redis收包->mysql发包->mysql收包
以上流程网络IO的时间就等于 redis网络IO时间 + mysql网络IO时间。
而对于协程版本的Client,网络IO可以是这样:
redis发包->mysql发包->redis收包->mysql收包
以上流程网络IO的时间就接近于 MAX(redis网络IO时间, mysql网络IO时间)
。
现在支持并发请求的Client有:
- Swoole\Coroutine\Client
- Swoole\Coroutine\Redis
- Swoole\Coroutine\MySQL
- Swoole\Coroutine\Http\Client
除了Swoole\Coroutine\Client
,其他Client都实现了defer特性,用于声明延迟收包。
- 全局变量:协程使得原有的异步逻辑同步化,但是在协程的切换是隐式发生的,所以在协程切换的前后不能保证全局变量以及static变量的一致性。
- 请勿在下列场景中调用协程客户端:
- 析构函数
__destruct()
- 魔术方法
__call()
- 析构函数