一、Swoole-server介绍php
二、建立一个Tcp serverreact
三、swoole驱动模式及相应事件nginx
4、server跟client交互web
5、同步client跟异步clientapache
6、tcp的特色及粘包处理编程
server,顾名思义,就是服务端。咱们平时接触比较多的无非就是nginx和apache。做为webServer,两者都是经过监听某端口对外提供服务,swoole的server也不例外一样须要绑定端口,同时可以提供给客户端相关的服务。浏览器
1.1建立一个server对象服务器
建立server的步骤:swoole
1、实例化Server对象网络
2、设置运行时参数
3、注册事件回调函数
4、启动服务器
示例:
server的建立,只须要绑定要监听的ip和端口,若是ip指定为127.0.0.1,则表示客户端只能位于本机才能链接,其余计算机没法链接,若是须要全部的客户端都能链接则能够设置0.0.0.0
端口这里指定为9501,能够经过netstat查看下该端口是否被占用。若是该端口被占用,可更改成其余端口,如9502,9503等。
2.2、配置
在享受swoole的server以前,一样咱们须要配置一下server,好比调几我的来提供服务(几个进程),以及是不是后台执行(守护进程)等等一些其它的配置。
这个就须要咱们作一些配置了,可是并不是像fpm直接在文件内配置,咱们能够在server建立后,经过set方法指定配置项。
同时,这个配置项也有不少,好比说咱们能够指定日志文件记录具体的错误信息等等,你均可以在官网的手册上寻找有哪些配置项,咱们也会在贯穿swoole的同时讲解一部分经常使用的配置项。
这里咱们首要说明一下worker进程数的配置,由于swoole是多进程的异步服务器因此须要设置工做进程数,提高服务器性能。
咱们能够指定配置项worker_num等于某个正整数。这个正整数设置多少合适,即我要开多少个worker进程处理们的业务逻辑才好呢我?官方建议咱们设置为CPU核数的1-4倍。由于咱们开的进程越多,内存的占用也就更多,进程间切换也就须要耗费更多的资源。咱们这里设置开启两个worker进程。默认该参数的值等于你机器的CPU核数。
swoole另一个比较吸引人的地方,就是swoole_server是事件驱动的。咱们在使用的过程当中不须要关注底层是怎么实现的,底层是C写的php只是作了个传递的做用,因此只须要对底层相应的动做注册相应的回调,在回调函数中处理业务逻辑便可。
什么意思呢?我举个例子:
你启动了一个server,当客户端链接的时候(触发事件),你不须要关心它是怎么链接的,你就单纯的注册一个connect函数,作一些链接后的业务处理便可(执行业务)。相似于js的事件监听,好比触发了click事件,就会执行相应的闭包。
Swoole监听的事件:
让咱们来看看几种常见的事件回调。
参数$serv是咱们一开始建立的swoole_server对象,
参数$fd是惟一标识,用于区分不一样的客户端,同时该参数是1-1600万之间能够复用的整数。简单解释下复用:假设如今客户端一、二、3处于链接中,客户端4要链接的话$fd就是4,可是不巧的是客户端3链接不稳定,断掉了,客户端4链接到server的话,$fd就是3,这样看的话。
1600W个链接够用吗?单机业务百万链接,已是很厉害了,不用担忧
监听客户端数据发送,触发回调
worker进程内触发的。第三个参数$fromId指的是哪个reactor线程,具体咱们会在多进程模型当中详细分析,先忽略。。
咱们看第四个参数,这个参数就是服务端接受到的数据,注意是字符串或者二进制内容,注意咱们在Receive回调内,调用了$serv的send方法,咱们可使用send方法,向client发起通知。
监听客户端关闭,触发回调
这个很简单,当客户端关闭,或者服务端主动关闭链接的时候会触发。
到此呢,咱们基本上已经搭建到了一个高性能的server。固然,很是简单,下面咱们只须要调用start方法启动server便可。
因为swoole_server只能运行在CLI模式下,因此不要试图经过浏览器进行访问,有据说过apache是基于nginx运行的吗,你们地位相同,只能配合,没有上下关系
咱们在命令行下面执行,自行去链接,这里不补充基础知识,tese.php就是刚刚服务器的方法
咱们平时执行完一个指令,执行完就结束了,可是如今的状况正好相反,当前程序一直处于执行中的状态,并无退出终端。同时由于swoole的server是常驻内存运行的,因此若是
修改了代码,须要ctrl+c中断,从新运行才行。
在咱们第一步初始化server所填写的ip和端口吗,也就是说server如今正在监听9501端口提供服务。
当前终端暂时不动,咱们新开一个终端,查看端口发现确实如此。
server启动好了能干什么呢?常见的网络编程模式都是client-server的,也就是说咱们还须要模拟一个客户端与之交互。
默认的swoole的server是能够提供tcp/udp socket请求协议,而后根据请求数据,执行相应的逻辑
在PHP中,咱们经常使用socket函数来建立TCP链接,用CURL库来建立Http链接。一样的,为了简化操做,Swoole也提供了一样的Client类用于实现客户端的功能,而且增长了异步非阻塞的模式,让用户在客户端也能使用事件循环。
swoole_client的构造函数以下所示:
swoole_client->__construct($sock_type,SWOOLE_SOCK_SYNC, $key);
第一个参数:
SWOOLE_SOCK_TCP 建立tcp socket
SWOOLE_SOCK_TCP6 建立tcp ipv6 socket
SWOOLE_SOCK_UDP 建立udp socket
SWOOLE_SOCK_UDP6 建立udp ipv6 socket
第二个参数表示是同步仍是异步
SWOOLE_SOCK_SYNC 同步客户端
SWOOLE_SOCK_ASYNC 异步客户端
第三个参数(暂不了解)
用于长链接的Key,默认使用IP:PORT做为key。相同key的链接会被复用
网络协议为计算机网络中进行数据交换而创建的规则、标准或约定的集合
一、TCP面向链接(如打电话要先拨号创建链接);UDP是无链接的,即发送数据以前不须要创建链接
2、TCP提供可靠的服务。也就是说,经过TCP链接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即不保证可靠交付
3、tcp经过校验和,重传控制,序号标识,滑动窗口、确认应答实现可靠传输。如丢包时的重发控制,还能够对次序乱掉的分包进行顺序控制。
3、UDP具备较好的实时性,工做效率比TCP高,适用于对高速传输和实时性有较高的通讯或广播通讯。
4、TCP对系统资源要求较多,UDP对系统资源要求较少。
代码如图所示:
同步client是同步阻塞的。一整套connect->send()->rev()->close()是同步进行的。若是须要大量的数据处理,后台不能在规定的时间内返回数据会致使接收超时,而且由于是同步执行因此须要等待后台数据的返回。
swoole是既支持全异步,也支持同步,同步跟异步的概念,咱们须要了解
同步与异步的重点在消息通知的方式上,也就是调用结果通知的方式。
同步: 当一个同步调用发出去后,调用者要一直等待调用结果的通知后,才能进行后续的执行。
异步:当一个异步调用发出去后,调用者不能当即获得调用结果的返回。
生活中的例子:
同步买奶茶:小明点单交钱,而后等着拿奶茶;
异步买奶茶:小明点单交钱,店员给小明一个小票,等小明奶茶作好了,再来取。
当设定swoole_client为异步模式后,swoole_client就不能使用recv方法了,而须要经过on方法提供指定的回调函数,而后在回调函数当中处理,也就是小明等待奶茶作好了异步通知,消息发送跟接收并非同步运行的。
客户端设备发送一个请求,服务端接收,根据业务逻辑的需求服务端A须要发送一个请求到服务端B获取数据,再返回给服务端A,服务端A返回给客户端A。
服务端A既是客户端也是服务器,服务端A要发送请求到服务端B,而后服务端B返回消息给服务端A
TCP通讯特色
1. TCP 是流式协议没有消息边界,客户端向服务器端发送一次数据,可能会被服务器端分红屡次收到。客户端向服务器端发送多少数据。服务器端可能一次所有收到。
2.保证传输的可靠性,顺序。
3.TCP拥有拥塞控制,因此数据包可能会延后发送。
没有消息边界:
能够理解为水在一个水管里的流动,咱们不知道哪段数据是一个咱们须要的完整数据
收发有缓冲区:
好比:当水从一端流到了另外一端,咱们在收数据的时候,不可能每来一滴水就处理一次,这个缓冲区就至关于有了一个水桶,再接了必定的水以后内核再给数据交到用户空间,这样能够大大提高性能。
TCP 粘包是指发送方发送的若干包数据 到 接收方接收时粘成一包,从接收缓冲区看,后一包数据的头紧接着前一包数据的尾。
发送方:发送方须要等缓冲区满才发送出去,形成粘包
接收方:接收方不及时接收缓冲区的包,形成多个包接收
模拟下产生问题的场景,下面的结果确实是出现了粘包的问题
经过约定结束符,来肯定包数据是否发送完毕
开启open_eof_check=true,并用package_eof来设置一个完整数据结尾字符,同时设置自动拆分open_eof_split
举个例子:
注意:
一、要保证业务数据里不能出现package_eof设置的字符,不然将致使数据错误了。
2、能够手动拆包,去掉open_eof_split,自行 explode("\r\n", $data),而后循环发送
这种方式也很是常见,原理是经过约定数据流的前几个字节来表示一个完整的数据有多长,从第一个数据到达以后,先经过读取固定的几个字节,解出数据包的长度,而后按这个长度继续取出后面的数据,依次循环。
案例:
相关配置:
open_length_check:打开包长检测特性
package_length_type:长度字段的类型,固定包头中用一个4字节或2字节表示包体长度。
package_length_offset:从第几个字节开始是长度,好比包头长度为120字节,第10个字节为长度值,这里填入9(从0开始计数)
package_body_offset:从第几个字节开始计算长度,好比包头为长度为120字节,第10个字节为长度值,包体长度为1000。若是长度包含包头,这里填入0,若是不包含包头,这里填入120
package_max_length:最大容许的包长度。由于在一个请求包完整接收前,须要将全部数据保存在内存中,因此须要作保护。避免内存占用过大。
package_length_type 长度值的类型
长度值的类型,接受一个字符参数,与php的pack函数一致。目前swoole支持10种类型:
c:有符号、1字节
C:无符号、1字节
s:有符号、主机字节序、2字节
S:无符号、主机字节序、2字节
n:无符号、网络字节序、2字节 (经常使用)
N:无符号、网络字节序、4字节 (经常使用)
l:有符号、主机字节序、4字节(小写L)
L:无符号、主机字节序、4字节(大写L)
v:无符号、小端字节序、2字节
V:无符号、小端字节序、4字节