ThinkChat🤖让你学习和工作更高效,注册即送10W Token,即刻开启你的AI之旅 广告
# 网络通信协议设计 [TOC] ## 为什么需要通信协议 TCP协议在底层机制上解决了UDP协议的顺序和丢包重传问题。但相比UDP又带来了新的问题,TCP协议是流式的,数据包没有边界。应用程序使用TCP通信就会面临这些难题。 因为TCP通信是流式的,在接收1个大数据包时,可能会被拆分成多个数据包发送。多次Send底层也可能会合并成一次进行发送。这里就需要2个操作来解决: * 分包:Server收到了多个数据包,需要拆分数据包 * 合包:Server收到的数据只是包的一部分,需要缓存数据,合并成完整的包 所以TCP网络通信时需要设定通信协议。常见的TCP网络通信协议有`HTTP`、`HTTPS`、`FTP`、`SMTP`、`POP3`、`IMAP`、`SSH`、`Redis`、`Memcache`、`MySQL`。 如果要设计一个通用协议的Server,那么就要按照通用协议的标准去处理网络数据。除了通用协议外还可以自定义协议。Swoole支持了2种类型的自定义网络通信协议。 ## EOF结束符协议 EOF协议处理的原理是每个数据包结尾加一串特殊字符表示包已结束。如`memcache`、`ftp`、`stmp`都使用`\r\n`作为结束符。发送数据时只需要在包末尾增加`\r\n`即可。使用EOF协议处理,一定要确保数据包中间不会出现EOF,否则会造成分包错误。 在`swoole_server`和`swoole_client`的代码中只需要设置2个参数就可以使用EOF协议处理。 ~~~ $server->set(array( 'open_eof_split' => true, 'package_eof' => "\r\n", )); $client->set(array( 'open_eof_split' => true, 'package_eof' => "\r\n", )); ~~~ ## 固定包头+包体协议 固定包头的协议非常通用,在BAT的服务器程序中经常能看到。这种协议的特点是一个数据包总是由包头+包体2部分组成。包头由一个字段指定了包体或整个包的长度,长度一般是使用2字节/4字节整数来表示。服务器收到包头后,可以根据长度值来精确控制需要再接收多少数据就是完整的数据包。Swoole的配置可以很好的支持这种协议,可以灵活地设置4项参数应对所有情况。 Swoole的Server和异步Client都是在`onReceive`回调函数中处理数据包,当设置了协议处理后,只有收到一个完整数据包时才会触发`onReceive`事件。同步客户端在设置了协议处理后,调用`$client->recv()`不再需要传入长度,recv函数在收到完整数据包或发生错误后返回。 ~~~ $server->set(array( 'open_length_check' => true, 'package_max_length' => 81920, 'package_length_type' => 'n', //see php pack() 'package_length_offset' => 0, 'package_body_offset' => 2, )); ~~~