详解PHP Swoole与TCP三次握手
发布:smiling 来源: PHP粉丝网 添加日期:2022-04-29 08:45:20 浏览: 评论:0
TCP(Transmission Control Protocol 传输控制协议)是一种面向连接(连接导向)的、可靠的、 基于IP的传输层协议。TCP在IP报文的协议号是6。TCP是一个超级麻烦的协议,而它又是互联网的基础,也是每个程序员必备的基本功。本文将详细介绍PHP Swoole与TCP三次握手。
握手常见问题
1、连接拒绝
2、Operation now in progress 多是因为丢包、错误ip、backlog满了&阻塞&tcp_abort_on_overflow=0
3、min(maxconn, backlog) ss -lt
连接拒绝
在TCP三次握手的时候,客户端发送SYN这个包给服务端,服务端不接受这个请求,操作系统直接返回了一个RST的包,来拒绝连接的请求。
最常见的情况就是客户端去请求某个服务器,服务端没有绑定对应的端口。
测试代码如下,服务端代码:
- <?php
-
- $server = new \Swoole\Server('127.0.0.1', 9501);
-
- $server->set([
- 'work_num' => 2,
- 'backlog' => 128,
- ]);
-
- $server->on('connect', function ($server, $fd)
- {
- echo "Client: Connect.\n";
- });
-
- $server->on('receive', function ($server, $fd, $reactor_id, $data)
- {
- var_dump($data);
- });
-
- $server->on('close', function ()
- {
- var_dump('close');
- });
-
- $server->start();
这里,服务端绑定的端口是9501。
启动服务器:
1 ~/codeDir/phpCode/hyperf-skeleton # php server.php
客户端代码:
- <?php
-
- $client = new \Swoole\Client(SWOOLE_SOCK_TCP, SWOOLE_SOCK_SYNC);
- var_dump($client->connect('127.0.0.1', 9500));
这里,客户端请求的端口是9500。
启动客户端:
- ~/codeDir/phpCode/hyperf-skeleton # php client.php
-
- Warning: Swoole\Client::connect(): connect to server[127.0.0.1:9500] failed, Error: Connection refused[111] in /root/codeDir/phpCode/hyperf-skeleton/client.php on line 4
- bool(false)
- ~/codeDir/phpCode/hyperf-skeleton #
报错:
Error: Connection refused[111]
Operation now in progress
这个错误的绝大部分原因是因为连接超时了。
丢包
例如路由器、网关出现了故障,包被丢了。
错误ip
例如客户端请求了一个错误的ip,那么路由器自然也就路由不到。
测试代码如下,客户端代码:
- <?php
-
- $client = new \Swoole\Client(SWOOLE_SOCK_TCP, SWOOLE_SOCK_SYNC);
- var_dump($client->connect('8.8.8.8', 9501));
这里,我访问的是谷歌的DNS服务器。因为我没有FQ,所以是访问不了这个IP的。因此,我们发送的包是到达不了8.8.8.8服务器的。
启动客户端:
- ~/codeDir/phpCode/hyperf-skeleton # php client.php
-
- Warning: Swoole\Client::connect(): connect to server[8.8.8.8:9501] failed, Error: Operation in progress[115] in /root/codeDir/phpCode/hyperf-skeleton/client.php on line 4
- bool(false)
- ~/codeDir/phpCode/hyperf-skeleton #
报错:
Error: Operation in progress[115]
backlog
服务器在三次握手的最后一次,即收到客户端发来的ACK包的时候,会把建立好的连接放到backlog队列里面。如果Swoole一直不accept连接,那么这个backlog队列很快就会满。backlog队列满了之后,服务端就会丢弃三次握手的SYN包,让客户端重新去连接服务端。
测试代码如下,服务端代码:
- <?php
-
- $server = new \Swoole\Server('127.0.0.1', 9501, SWOOLE_BASE);
-
- $server->set([
- 'work_num' => 2,
- 'backlog' => 128,
- ]);
-
- $server->on('connect', function ($server, $fd)
- {
- echo "Client: Connect.\n";
- sleep(1000);
- });
-
- $server->on('receive', function ($server, $fd, $reactor_id, $data)
- {
- var_dump($data);
- });
-
- $server->on('close', function ()
- {
- var_dump('close');
- });
-
- $server->start();
要想测试backlog问题必须在Swoole的SWOOLE_BASE模式下,默认的SWOOLE_PROCESS模式是没有这个问题的。
这里,我们的backlog大小是128。
然后,我们通过sleep(1000);来阻塞住进程,使得Swoole不会继续accept连接,从而导致backlog队列在某个时刻变满。
客户端代码:
- <?php
-
- $i = 0;
- while (true)
- {
- $client = new \Swoole\Client(SWOOLE_SOCK_TCP, SWOOLE_SOCK_SYNC);
- if ($client->connect('127.0.0.1', 9501) == false)
- {
- break;
- }
- }
我们启动服务器:
~/codeDir/phpCode/hyperf-skeleton # php server.php
然后启动客户端:
- ~/codeDir/phpCode/hyperf-skeleton # php client.php
- 省略了其他的输出
- bool(true)
- bool(true)
- bool(true)
- bool(true)
- bool(true)
- bool(true)
- bool(true)
- bool(true)
- bool(true)
- bool(true)
- bool(true)
- bool(true)
- bool(true)
- bool(true)
- bool(true)
- bool(true)
- bool(true)
- bool(true)
- bool(true)
- bool(true)
- bool(true)
- bool(true)
- bool(true)
- bool(true)
- bool(true)
- bool(true)
- bool(true)
- bool(true)
- bool(true)
- bool(true)
- bool(true)
- bool(true)
- bool(true)
- bool(true)
-
- Warning: Swoole\Client::connect(): connect to server[127.0.0.1:9501] failed, Error: Operation in progress[115] in /root/codeDir/phpCode/hyperf-skeleton/client.php on line 7
- bool(false)
-
- Warning: Swoole\Client::connect(): connect to server[127.0.0.1:9501] failed, Error: Operation in progress[115] in /root/codeDir/phpCode/hyperf-skeleton/client.php on line 7
- bool(false)
- ^C
- ~/codeDir/phpCode/hyperf-skeleton #
我们会发现,过一段时间,客户端这边会报错:
Error: Operation in progress[115]
服务端这边输出:
~/codeDir/phpCode/hyperf-skeleton # php server.php
Client: Connect.
因为当Swoole服务器从backlog队列里面accept一个连接的时候,才会触发onReceive回调函数。所以,当服务端accept一个连接之后,Swoole自己就会陷入阻塞,不会再accept了。但是需要注意的是,尽管Swoole服务器自身是阻塞的,操作系统还会继续去把建立好的连接放入backlog队列里面。所以,backlog队列会满。
SYN Flood
除了三次握手成功之后会使用到的backlog队列,还有一个SYN队列。也就是在三次握手时候,客户端给服务端发送了SYN包,服务端会有一个SYN队列来维护。
与其有关的内核配置:
tcp_max_syn_backlog
tcp_synack_retries
tcp_syncookies
其中,tcp_max_syn_backlog就是这个SYN队列的长度。如果大量的SYN包把SYN队列塞满了,那么其他正常的连接过来,服务端就无法处理。
SYN Flood攻击就是客户端疯狂的给服务端发送SYN包,然后服务端每次都会把请求放到SYN队列里面。但是,客户端不给服务端回ACK包。如果客户端不回ACK包,那么服务端就会给客户端回SYN + ACK包,即第二次握手发送的包。而回复SYN + ACK包的次数就是由tcp_synack_retries参数决定的。如果把tcp_synack_retries设置为0,那么如果服务端没有收到ACK包,那么服务端就不会重试发送SYN + ACK包了,这样就减少了SYN队列里面那个请求的存活时间。
tcp_syncookies的原理就是,客户端发送SYN包的时候,不会维护SYN队列,而是返回一个cookie给客户端。然后客户端发送第三次握手的时候,携带这个cookie值,只有这个cookie验证通过,服务端才会给连接分配资源。
Tags: Swoole TCP
- 上一篇:详解PHP调用Go服务的正确方式
- 下一篇:最后一页
相关文章
- ·php异步多线程swoole使用实例程序(2015-04-15)
- ·PHP程序员学习使用Swoole的理由(2018-09-14)
- ·swoole_process父子进程管道通信的代码示例(2020-01-16)
- ·swoole事件处理流程(2020-04-06)
- ·Swoole协程与传统fpm同步模式比较(2020-04-09)
- ·PHP框架Swoole定时器Timer特性分析(2021-04-05)
- ·php异步多线程swoole用法实例(2021-04-26)
- ·使用php+swoole对client数据实时更新(一)(2021-07-04)
- ·PHP+swoole实现简单多人在线聊天群发(2021-07-06)
- ·基于 Swoole 的微信扫码登录功能实现代码(2021-08-30)
- ·基于swoole实现多人聊天室(2021-10-01)
- ·swoole_process实现进程池的方法示例(2021-11-01)
- ·Swoole实现异步投递task任务案例详解(2021-11-14)
- ·PHP扩展Swoole实现实时异步任务队列示例(2021-11-17)
- ·PHP+swoole+linux实现系统监控和性能优化操作示例(2021-11-17)
- ·Swoole4.4协程抢占式调度器详解(2021-11-23)
推荐文章
热门文章
最新评论文章
- 写给考虑创业的年轻程序员(10)
- PHP新手上路(一)(7)
- 惹恼程序员的十件事(5)
- PHP邮件发送例子,已测试成功(5)
- 致初学者:PHP比ASP优秀的七个理由(4)
- PHP会被淘汰吗?(4)
- PHP新手上路(四)(4)
- 如何去学习PHP?(2)
- 简单入门级php分页代码(2)
- php中邮箱email 电话等格式的验证(2)