详解PHP Swoole与TCP三次握手


Posted in PHP onMay 27, 2021

握手常见问题

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验证通过,服务端才会给连接分配资源。

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

PHP 相关文章推荐
用文本作数据处理
Oct 09 PHP
PHP判断远程url是否有效的几种方法小结
Oct 08 PHP
php中批量修改文件后缀名的函数代码
Oct 23 PHP
php使用websocket示例详解
Mar 12 PHP
php中通过DirectoryIterator删除整个目录的方法
Mar 13 PHP
使用 PHPStorm 开发 Laravel
Mar 24 PHP
php实现插入排序
Mar 29 PHP
php判断邮箱地址是否存在的方法
Feb 13 PHP
提交表单后 PHP获取提交内容的实现方法
May 25 PHP
Yii框架用户登录session丢失问题解决方法
Jan 07 PHP
PHP将字符串首字母大小写转换的实例
Jan 21 PHP
PHP实现的大文件切割与合并功能示例
Apr 10 PHP
如何用PHP实现分布算法之一致性哈希算法
如何用PHP实现多线程编程
May 26 #PHP
如何用PHP websocket实现网页实时聊天
详解PHP用mb_string处理windows中文字符
May 26 #PHP
详解PHP服务器如何在有限的资源里最大提升并发能力
详解PHP设计模式之依赖注入模式
阿里云服务器搭建Php+Apache运行环境的详细过程
You might like
第八节 访问方式 [8]
2006/10/09 PHP
PHP基于GD库的图像处理方法小结
2016/09/27 PHP
PHPstorm激活码2020年5月13日亲测有效
2020/09/17 PHP
EXTJS FORM HIDDEN TEXTFIELD 赋值 使用value不好用的问题
2011/04/16 Javascript
Jquery原生态实现表格header头随滚动条滚动而滚动
2014/03/18 Javascript
JavaScript设计模式之单件模式介绍
2014/12/28 Javascript
js实现获取当前时间是本月第几周的方法
2015/08/11 Javascript
检查表单元素的值是否为空的实例代码
2016/06/16 Javascript
jQuery插件 Jqplot图表实例
2016/06/18 Javascript
AngularJS 表达式详解及实例代码
2016/09/14 Javascript
Angular2 多级注入器详解及实例
2016/10/30 Javascript
AngularJS实现的输入框字数限制提醒功能示例
2017/10/26 Javascript
小程序如何获取多个formId实现详解
2019/09/20 Javascript
es6函数name属性功能与用法实例分析
2020/04/18 Javascript
解决vue bus.$emit触发第一次$on监听不到问题
2020/07/28 Javascript
vue通过接口直接下载java生成好的Excel表格案例
2020/10/26 Javascript
[03:48]2014DOTA2 TI专访71DK夺冠不靠小组赛高排名
2014/07/11 DOTA
python在windows下实现备份程序实例
2014/07/04 Python
python文件读写操作与linux shell变量命令交互执行的方法
2015/01/14 Python
python引用DLL文件的方法
2015/05/11 Python
深入解析Python中的lambda表达式的用法
2015/08/28 Python
Python的dict字典结构操作方法学习笔记
2016/05/07 Python
Python字符编码判断方法分析
2016/07/01 Python
python 定时修改数据库的示例代码
2018/04/08 Python
Python3爬虫爬取百姓网列表并保存为json功能示例【基于request、lxml和json模块】
2018/12/05 Python
对python中Librosa的mfcc步骤详解
2019/01/09 Python
Django配置MySQL数据库的完整步骤
2019/09/07 Python
解决Python二维数组赋值问题
2019/11/28 Python
python新式类和经典类的区别实例分析
2020/03/23 Python
使用python客户端访问impala的操作方式
2020/03/28 Python
Python模拟伯努利试验和二项分布代码实例
2020/05/27 Python
小学三年级学生评语
2014/04/22 职场文书
新学期开学演讲稿
2014/05/24 职场文书
入党积极分子培养人意见
2015/06/02 职场文书
2019年房屋委托租赁合同范本(通用版)!
2019/07/17 职场文书
CentOS7安装MySQL8的超级详细教程(无坑!)
2022/06/10 Servers