您的位置:首页技术文章
文章详情页

详解PHP Swoole与TCP三次握手

浏览:2日期:2022-09-07 10:54:09
目录握手常见问题连接拒绝Operation now in progress丢包错误ipbacklogSYN Flood握手常见问题

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 SwooleServer(’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 SwooleClient(SWOOLE_SOCK_TCP, SWOOLE_SOCK_SYNC);var_dump($client->connect(’127.0.0.1’, 9500));

这里,客户端请求的端口是9500。

启动客户端:

~/codeDir/phpCode/hyperf-skeleton # php client.php ​Warning: SwooleClient::connect(): connect to server[127.0.0.1:9500] failed, Error: Connection refused[111] in /root/codeDir/phpCode/hyperf-skeleton/client.php on line 4bool(false)~/codeDir/phpCode/hyperf-skeleton #

报错:

Error: Connection refused[111]

Operation now in progress

这个错误的绝大部分原因是因为连接超时了。

丢包

例如路由器、网关出现了故障,包被丢了。

错误ip

例如客户端请求了一个错误的ip,那么路由器自然也就路由不到。

测试代码如下,客户端代码:

<?php​$client = new SwooleClient(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: SwooleClient::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 4bool(false)~/codeDir/phpCode/hyperf-skeleton #

报错:

Error: Operation in progress[115]

backlog

服务器在三次握手的最后一次,即收到客户端发来的ACK包的时候,会把建立好的连接放到backlog队列里面。如果Swoole一直不accept连接,那么这个backlog队列很快就会满。backlog队列满了之后,服务端就会丢弃三次握手的SYN包,让客户端重新去连接服务端。

测试代码如下,服务端代码:

<?php​$server = new SwooleServer(’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 SwooleClient(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: SwooleClient::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 7bool(false)​Warning: SwooleClient::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 7bool(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_backlogtcp_synack_retriestcp_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验证通过,服务端才会给连接分配资源。

以上就是详解PHP Swoole与TCP三次握手的详细内容,更多关于PHP Swoole与TCP三次握手的资料请关注好吧啦网其它相关文章!

标签: PHP
相关文章: