文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

stream_socket_client的异步使用方式

2023-09-10 20:06

关注

PHP 5、7、8,stream_socket_client用于建立网络或IPC socket连接。函数的参数和返回为:

stream_socket_client(    string $address,    int &$error_code = null,    string &$error_message = null,    ?float $timeout = null,    int $flags = STREAM_CLIENT_CONNECT,    ?resource $context = null): resource|false

其中第一个参数必填,其它为可选:

  1. address:传输协议、域名/IP、端口
  2. error_code:一个变量,调用结束后里面存储调用时发生的错误编号
  3. error_message:一个变量,调用结束后里面存储调用时发生的错误的文字提示
  4. timeout:超时时间,单位是秒,只在发起连接的时候有用,且只有在非异步连接的情况下才有用
  5. flags:标志位,四种可能的常量、功能可以通过位运算来启用:STREAM_CLIENT_CONNECT、STREAM_CLIENT_ASYNC_CONNECT、STREAM_CLIENT_PERSISTENT,分别是:默认的同步、异步、持久连接
  6. context:作用于流的上下文选项

函数返回值:调用成功会返回一个流的资源,如果失败返回false。

本地测试的样例:

if (false === ($r = stream_socket_client('tcp://www.baidu.com:443', $error_code, $error_message, 3))) {    echo '连接失败' . PHP_EOL;    var_dump($error_code, $error_message);    exit(1);}echo '连接成功' . PHP_EOL;fclose($r);

样例使用同步的方式打开到www.baidu.com站点的443端口的TCP连接,在连接成功之后输出"连接成功"并关闭连接。如果失败那么输出失败的error_code和error_message。本地网络正常的情况下样例执行情况是:

$ php test.php连接成功$

如果遇到连接失败,比如将端口号从443改成一个没用的端口,比如8000,那么执行情况类似于:

$ time php test.phpPHP Warning:  stream_socket_client(): unable to connect to tcp://www.baidu.com:8000 (由于连接方在一段时间后没有正确答复或连接的主机没有反应,连接尝试失败。) in D:\test.php on line 3Warning: stream_socket_client(): unable to connect to tcp://www.baidu.com:8000 (由于连接方在一段时间后没有正确答复或连接的主机没有反应,连接尝试失败。) in D:\test.php on line 3连接失败int(10060)string(107) "由于连接方在一段时间后没有正确答复或连接的主机没有反应,连接尝试失败。"real    0m3.069suser    0m0.000ssys     0m0.000s$

结合执行时间可以看出,这个错误是因为超时时间3秒后远程服务器8000端口并不能响应连接,所以超时连接失败。此外因为默认是通过同步的方式连接远程服务器的,所以网络连接建立的时间内脚本阻塞在stream_socket_client。

if (false === ($r = stream_socket_client('tcp://www.baidu.com:8000', $error_code, $error_message, 3, STREAM_CLIENT_ASYNC_CONNECT))) {    echo '连接失败' . PHP_EOL;    var_dump($error_code, $error_message);    exit(1);}echo '连接成功' . PHP_EOL;fclose($r);

和第一个样例类似,端口号8000,超时时间设置3秒和设置flags为STREAM_CLIENT_ASYNC_CONNECT。执行情况:

$ time php test.php连接成功real    0m0.832suser    0m0.000ssys     0m0.000s

所以,在情况不变,还是需要等待一段时间才能确定网络连接是不是成功的前提下,异步方式调用很快地stream_socket_client函数就返回了一个流资源,而不是false。并且你可以对这个流资源调用fclose关闭它。

当然,如果这时候调用函数发送数据是会报错的,样例代码和执行结果:

if (false === ($r = stream_socket_client('tcp://www.baidu.com:8000', $error_code, $error_message, 3, STREAM_CLIENT_ASYNC_CONNECT))) {    echo '连接失败' . PHP_EOL;    var_dump($error_code, $error_message);    exit(1);}echo '连接成功' . PHP_EOL;if(!stream_set_blocking($r, false)) {    echo '设置流为非阻塞状态失败' . PHP_EOL;    exit(1);}if (false === stream_socket_sendto($r, 'Hello here.')) {    echo '发送数据失败' . PHP_EOL;    exit(1);}fclose($r);

执行结果:

$ php test.php连接成功PHP Warning:  stream_socket_sendto(): 由于套接字没有连接并且(当使用一个 sendto 调用发送数据报套接字时)没有提供地址,发送或接收数据的请求没有被接受。 in D:\test.php on line 16Warning: stream_socket_sendto(): 由于套接字没有连接并且(当使用一个 sendto 调用发送数据报套接字时)没有提供地址,发送或接 收数据的请求没有被接受。 in D:\test.php on line 16$

就算这里将端口从8000改回443也是一样的,连接远程服务器的函数是异步时执行下面的代码是无法保证连接是否就绪的。这时需要使用stream_select之类的机制等待连接就绪:

if (false === ($r = stream_socket_client('tcp://www.baidu.com:443', $error_code, $error_message, 3, STREAM_CLIENT_ASYNC_CONNECT))) {    echo '连接失败' . PHP_EOL;    var_dump($error_code, $error_message);    exit(1);}echo '连接成功' . PHP_EOL;if(!stream_set_blocking($r, false)) {    echo '设置流为非阻塞状态失败' . PHP_EOL;    exit(1);}$read = $except = null;while (true) {    $write = [$r];    $total = stream_select($read, $write, $except, 0, 1000);    if (false === $total || $total <= 0) {        continue;    }    foreach ($write as $ready) {        if (false === stream_socket_sendto($ready, 'Hello here.')) {            echo '发送数据失败' . PHP_EOL;            exit(1);        } else {            echo '发送数据成功' . PHP_EOL;            break 2;        }    }}fclose($r);

执行情况:

$ php test.php连接成功发送数据成功

顺便记录一个情况。stream_socket_sendto在这里一次调用可以发送的数据量是不小的,并不会受到TCP连接一个包数据负载65495字节的限制。当一次发送的数据量很大的时候,底层会对数据拆分成多个部分发送。另外一端在使用stream_get_contents接收数据的时候,我用stream_select做测试发现,一次可以读取到65495字节的数据,也可能是更大或者更小的字节数。所以在接收数据时需要考虑如何确保数据接收结束。

来源地址:https://blog.csdn.net/sinat_35576477/article/details/128481115

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯