一:玩转网络通信引擎

本节知识点:

一:创建一个Tcp server

二:swoole驱动模式及相应事件

三:同步client

四:server和client交互

五:tcp的特点以及粘包处理

 

一:创建一个Tcp server

创建server的步骤:

  (1):实例化server对象

  (2):设置运行时参数

  (3):注册事件回调函数

  (4):启动服务器

tcp异步服务端

 

 

 

 server的创建,只需要绑定要监听的ip和端口,如果ip指定为127.0.0.1,则表示客户端只能位于本机才能连接,其他计算机无法连接,如果需要所有的客户端都能连接则可以设置0.0.0.0

 

端口这里指定为9501,可以通过netstat查看下该端口是否被占用。如果该端口被占用,可更改为其他端口,如9502,9503等。

 

 

 该文件目录下执行命令:php tcp_server.php

 

 

 新开窗口测试9501端口是否开启:执行命令:netstat -anp|grep 9501

 

 

 如果报错:

 

 

 执行安装命令:

 

 yum list telnet*              列出telnet相关的安装包

 

   yum install telnet-server          安装telnet服务

 

   yum install telnet.*           安装telnet客户端

 

再次执行客户端监听命令:telnet 127.0.0.1 9501

 

 

 tcp同步客户端

 

 

 使用命令 ps aft |grep 开启的服务(这里为tcp.php) ps aft |grep tcp.php 可以查看开启的进程数

 二:swoole驱动模式及相应事件

swoole监听的事件

 

 

 

 

 

让我们来看看几种常见的事件回调

 

参数$serv是我们一开始创建的swoole_server对象,

 

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

 

 

 

1600W个连接够用吗?单机业务百万连接,已经是很厉害了,不用担心;

 

监听客户端数据发送,触发回调

 

 

 第三个参数$reactor_id指的是哪一个reactor线程,具体我们会在多进程模型当中详细分析,先忽略

 

我们看第四个参数,这个参数就是服务端接受到的数据,注意是字符串或者二进制内容,注意我们在Receive回调内,调用了$serv的send方法,我们可以使用send方法,向client发起通知。

 

监听客户端关闭,触发回调

 

 

 

这个很简单,当客户端关闭,或者服务端主动关闭连接的时候会触发。

到此呢,我们基本上已经搭建到了一个高性能的server当然,非常简单,下面我们只需要调用start方法启动server即可

 

 

 

 由于swoole_server只能运行在CLI模式下,所以不要试图通过浏览器进行访问,有听说过apache是基于nginx运行的吗,大家地位相同,只能配合,没有上下关系

 

server启动好了能干什么呢?常见的网络编程模式都是client-server的,也就是说我们还需要模拟一个客户端与之交互;

三:同步client

TCP和UDP介绍

 

1、TCP面向连接(如打电话要先拨号建立连接);UDP是无连接的,即发送数据之前不需要建立连接

 

2TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即不保证可靠交付

 

3tcp通过校验和,重传控制,序号标识,滑动窗口、确认应答实现可靠传输。如丢包时的重发控制,还可以对次序乱掉的分包进行顺序控制。

 

3UDP具有较好的实时性,工作效率比TCP高,适用于对高速传输和实时性有较高的通信或广播通信。

 

4TCP对系统资源要求较多,UDP对系统资源要求较少。

 

 

Swoole\Client 以下简称 Client,提供了 TCP/UDPsocket 的客户端的封装代码,使用时仅需 new Swoole\Client 即可。可用于 FPM/Apache 环境。
相对传统的 streams 系列函数,有几大优势:

(1):stream 函数存在超时设置的陷阱和 Bug,一旦没处理好会导致 Server 端长时间阻塞

(2):stream 函数的 fread 默认最大 8192 长度限制,无法支持 UDP 的大包

(3):Client 支持 waitall,在有确定包长度时可一次取完,不必循环读取

(4):Client 支持 UDP Connect,解决了 UDP 串包问题

(5):Client 是纯 C 的代码,专门处理 socketstream 函数非常复杂。Client 性能更好

(6):Client 支持长连接

(7):可以使用 swoole_client_select 函数实现多个 Client 的并发控制

 

 

 

 
五:tcp的特点以及粘包处理

 

因为 TCP 通信是流式的,在接收 1 个大数据包时,可能会被拆分成多个数据包发送。多次 Send 底层也可能会合并成一次进行发送。这里就需要 2 个操作来解决:

(1):分包:Server 收到了多个数据包,需要拆分数据包

(2):合包:Server 收到的数据只是包的一部分,需要缓存数据,合并成完整的包

粘包处理  Swoole 支持了 2 种类型的自定义网络通信协议。

(1):EOF 结束符协议

  EOF 协议处理的原理是每个数据包结尾加一串特殊字符表示包已结束。发送数据时只需要在包末尾增加 \r\n 即可。使用 EOF 协议处理,一定要确保数据包中间不会出现 EOF,否则会造成分包错误。

ServerClient 的代码中只需要设置 3 个参数就可以使用 EOF 协议处理。

 

 

 开启open_eof_check=true,并用package_eof来设置一个完整数据结尾字符,同时设置自动拆分open_eof_split;

(2):固定包头 + 包体协议

 

这种方式也非常常见,原理是通过约定数据流的前几个字节来表示一个完整的数据有多长,从第一个数据到达之后,先通过读取固定的几个字节,解出数据包的长度,然后按这个长度继续取出后面的数据,依次循环

 

 

 

相关配置:

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 长度值的类型

长度值的类型,接受一个字符参数,与phppack函数一致。目前swoole支持10种类型:

c:有符号、1字节

C:无符号、1字节

s:有符号、主机字节序、2字节

S:无符号、主机字节序、2字节

n:无符号、网络字节序、2字节 (常用)

N:无符号、网络字节序、4字节 (常用)

l:有符号、主机字节序、4字节(小写L

L:无符号、主机字节序、4字节(大写L

v:无符号、小端字节序、2字节

V:无符号、小端字节序、4字节

 

 

posted @ 2022-03-31 20:00  痞子胥  阅读(74)  评论(0)    收藏  举报