(2) swoole 特性、原理

特性

Swoole 使用纯 C 语言编写,提供了 PHP 语言的异步多线程服务器

  1. 事件驱动的异步编程模式
  2. 异步TCP/UDP/HTTP/WebSocket/HTTP2协议的服务器端/客户端
  3. 支持IPv4/IPv6/UnixSocket/TCP/UDP
  4. 支持SSL/TLS隧道加密
  5. 支持并发百万TCP长连接
  6. 支持毫秒定时器
  7. 支持异步/同步/协程
  8. 支持CPU亲和性设置/守护进程

swoole_server是事件驱动的。我们在使用的过程中不需要关注底层是怎么实现的,底层是C写的php只是做了个传递的作用,所以只需要对底层相应的动作注册相应的回调,在回调函数中处理业务逻辑即可

参数$serv是我们一开始创建的swoole_server对象,
参数$fd是唯一标识,用于区分不同的客户端,同时该参数是1-1600万之间可以复用的整数。简单解释下复用:假设现在客户端1、2、3处于连接中,客户端4要连接的话$fd就是4,但是不巧的是客户端3连接不稳定,断掉了,客户端4连接到server的话,$fd就是3。

常用socket函数来创建TCP连接,用CURL库来创建Http连接。同样的,为了简化操作,Swoole也提供了同样的Client类用于实现客户端的功能,并且增加了异步非阻塞的模式,让用户在客户端也能使用事件循环

通讯协议

特点 TCP UDP
连接性 面向连接 面向非连接
可靠性 可靠 不可靠
传输效率

1、TCP面向连接(如打电话要先拨号建立连接);UDP是无连接的,即发送数据之前不需要建立连接
2、TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即不保证可靠交付
3、tcp通过校验和,重传控制,序号标识,滑动窗口、确认应答实现可靠传输。如丢包时的重发控制,还可以对次序乱掉的分包进行顺序控制。
3、UDP具有较好的实时性,工作效率比TCP高,适用于对高速传输和实时性有较高的通信或广播通信。
4、TCP对系统资源要求较多,UDP对系统资源要求较少。

创建server的步骤:

1、实例化Server对象
2、设置运行时参数
3、注册事件回调函数
4、启动服务器

心跳

1、客户端定时给服务端发送点数据,防止连接由于长时间没有通讯而被某些节点的防火墙关闭导致连接断开的情况。

2、服务端可以通过心跳来判断客户端是否在线,如果客户端在规定时间内没有发来任何数据,就认为客户端下线。这样可以检测到客户端由于极端情况(断电、断网等)下线的事件。

1
2
heartbeat_check_interval: 服务器定时检测在线列表的时间
heartbeat_idle_time: 连接最大的空闲时间 (如果最后一个心跳包的时间与当前时间之差超过这个值,则认为该连接失效)
1
2
3
4
5
$server->set([
'worker_num'=>1, //设置进程
'heartbeat_idle_time'=>10,//连接最大的空闲时间
'heartbeat_check_interval'=>3 //服务器定时检查
]);

建议 heartbeat_idle_time 为 heartbeat_check_interval 的两倍多一点。
这个两倍是为了进行容错,允许丢一个包而多一点是考虑到网络的延时。

粘包

TCP 粘包是指发送方发送的若干包数据 到 接收方接收时粘成一包,从接收缓冲区看,后一包数据的头紧接着前一包数据的尾。

发送方:发送方需要等缓冲区满才发送出去,造成粘包
接收方:接收方不及时接收缓冲区的包,造成多个包接收

通过约定结束符,来确定包数据是否发送完毕

1
2
3
open_eof_check=true 开启
package_eof = '\r\n' 来设置一个完整数据结尾字符
open_eof_split => true 设置自动拆分

进程与线程

进程

1、进程之间不共享任何状态
2、进程的调度由操作系统完成
3、每个进程都有自己独立的内存空间
4、进程间通讯主要是通过信号传递的方式来实现的,实现方式有多种,信号量、管道、事件等,任何一种方式的通讯效率都需要过内核,导致通讯效率比较低
5、由于是独立的内存空间,上下文切换的时候需要保存先调用栈的信息、cpu各寄存器的信息、虚拟内存、以及打开的相关句柄等信息,所以导致上下文进程间切换开销很大,通讯麻烦。

线程

1、线程之间共享变量,解决了通讯麻烦的问题对于变量的访问需要锁
2、一个进程可以拥有多个线程,但是其中每个线程会共享父进程像操作系统申请资源,这个包括虚拟内存、文件等,由于是共享资源,所以创建线程所需要的系统资源占用比进程小很多,相应的可创建的线程数量也变得相对多很多。
3、另外在调度方面也是由于内存是共享的,所以上下文切换的时候需要保存的东西就像对少一些,这样一来上下文的切换也变得高效。