[Multiple and faster]php ping ipv4 by socket

本文介绍了一种基于socket_select的高性能ping工具xfping的设计与实现。相较于传统工具,xfping通过优化socket_select的使用方式显著减少了ping操作的整体耗时,并支持批量ping操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前文

在之前【读源码】workerman中的2种Timer中,我就已经接触到了stream_select,其中基于该函数实现的微秒级延迟更是让我大开眼界,甚至于有人另外将其简化成一个定时器。而有另外一个有相似用法的函数是socket_select,在[udpate]php ping ipv4 by socket中实现xping的实现中也有用到,而之后,我就一直思考是否也可以用workerman中事件的思路实现更高性能的ping呢?在经过workerman启发还有几天的努力,终于还是有点眉目了。

exec ping 和 xping

exec ping

一次只能ping一个ip,并且每次ping会间隔1秒。
所以所花费的时间是:

(1s + (ttl or timeout)) * ping 次数

xping

一次只能ping一个ip,ping间隔可以忽略

所以所花费的时间是:

((ttl or timeout)) * ping 次数

而 ttl计算 和 timeout 恰恰都是同个socket_select阻塞实现的。也就是说每次ping的花费时间是

ttl < ping一次时间 < timeout

  • 大概流程
    在这里插入图片描述

  • 最大的问题
    可以看到,运行是线性的,时间也是线性增加的。并且大部分时间都是花在socket_select,其阻塞的时间太浪费了

xfping新思路

socket_select 是用于检测在限定时间内有被修改的套接字。那么我的思路是,把其等待的时间缩小,先发下个ping包,再一起等回包。其流程则会变成:
在这里插入图片描述

可以发现,按这个思路整体运行时间将大大减少,那么开干。

主要会有几个变化

  1. 新的timeout机制
    socket_select 单纯用于检测套接字状态了,那timeout机制则需另外设计
  2. 非阻塞的socket_recvfrom
    多个回包需要socket_recvfrom多次读取,如果设置为阻塞,那么会阻塞至下个回包,影响退出其他部分运行
  3. TTL计算
    之前的单个ping周期甚至可以不用去检测数据的正确与否,而并发ping则需要明确每个回包的对应关系,才可以准确计算出TTL
  4. 结束机制
    之前socket_select 的阻塞和超时可以视为一个ping的结束,现在需要通过回包和超时的计数去判断ping 任务是否结束

xfping 示例

类exec ping 配置

  • 代码
(xfping::init())
    ->setDebug(0)
    ->setCallbackDnsError(function($host){
        echo 'DnsError :'.$host.PHP_EOL;
    })
    ->setCallbackTimeOut(function($ip){
        echo 'timeout :'.$ip.PHP_EOL;
    })
    ->setCallbackOneIp(function($ip,$ret){
       echo formet($ip,$ret).PHP_EOL;
    })
    ->setCallbackSingle(function($ip,$seq,$t){
        echo 'from ip='.$ip.' seq='.$seq.' t_ms='.($t*1000).PHP_EOL;
    })
    ->setCallback(function ($ret,$t){
        echo 'ret '.PHP_EOL;
        foreach ($ret as $ip=>$r){
            echo formet($ip,$r).PHP_EOL;
        }
        echo 'total time_ms '.$t;
})->doit('127.0.0.1',4,1000,1000);
// ping 4 次 127.0.0.1 ,1s 超时,每次间隔1s
  • 结果
from ip=127.0.0.1 seq=0 t_ms=0.3049373626709
from ip=127.0.0.1 seq=1 t_ms=0.26607513427734
from ip=127.0.0.1 seq=2 t_ms=0.24986267089844
from ip=127.0.0.1 seq=3 t_ms=0.26988983154297
ip=127.0.0.1 send=4 recive=4 loss=0.00%  min=0.25ms max=0.30ms avg=0.27ms
ret
ip=127.0.0.1 send=4 recive=4 loss=0.00%  min=0.25ms max=0.30ms avg=0.27ms
total time_ms 3022.8109359741

批量ping

  • 代码
(xfping::init())
    ->setDebug(0)
    ->setCallbackDnsError(function($host){
        echo 'DnsError :'.$host.PHP_EOL;
    })
    ->setCallbackTimeOut(function($ip){
        echo 'timeout :'.$ip.PHP_EOL;
    })
// 不输出 OneIp ping 和 Single ping
//    ->setCallbackOneIp(function($ip,$ret){
//       echo formet($ip,$ret).PHP_EOL;
//    })
//    ->setCallbackSingle(function($ip,$seq,$t){
//        echo 'from ip='.$ip.' seq='.$seq.' t_ms='.($t*1000).PHP_EOL;
//    })

    ->setCallback(function ($ret,$t){
        echo 'ret '.PHP_EOL;
        foreach ($ret as $ip=>$r){
            echo formet($ip,$r).PHP_EOL;
        }
        echo 'total time_ms '.$t;
})->doit('127.0.0.1;127.0.0.2;127.0.0.3',1,1000,10);
//分别ping 2 次 127.0.0.1 、127.0.0.2、127.0.0.3 ,1s 超时,每次间隔10ms
  • 结果
ret
ip=127.0.0.1 send=2 recive=2 loss=0.00%  min=0.26ms max=0.30ms avg=0.28ms
ip=127.0.0.2 send=2 recive=2 loss=0.00%  min=0.26ms max=0.26ms avg=0.26ms
ip=127.0.0.3 send=2 recive=2 loss=0.00%  min=0.25ms max=0.26ms avg=0.26ms
total time_ms 72.15690612793

项目源码

Xxx-Bin/php-scoket-ping-Ipv4 xfping

原文地址

[Multiple and faster]php ping ipv4 by socket https://bjun.tech/blog/xphp/125

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值