PHP socket跨机器丢失数据问题

发布于 2022-09-12 00:26:34 字数 1737 浏览 28 评论 0

发现socket跨机器访问时,客户端读不到完整数据,下面是简化了一些流程的关键代码

服务端代码

<?php


$uri = 'tcp://0.0.0.0:8522';
$context = stream_context_create([]);
$errno = 0;
$errStr = '';
$server = stream_socket_server($uri, $errno, $errStr, STREAM_SERVER_BIND | STREAM_SERVER_LISTEN, $context);
$socket = socket_import_stream($server);
socket_set_option($socket, SOL_SOCKET, SO_KEEPALIVE, 1);
socket_set_option($socket, SOL_TCP, TCP_NODELAY, 1);

while ($conn = stream_socket_accept($server, 10000)) {
    stream_set_blocking($conn, 0);

    $data = [];
    $count = 0;
    while ($count < 8000) {
        $data[] = [
            'id'   => 'qwertyuiop123456',
            'name' => 'abcdef123的撒第五期红地球完活i都会去的',
        ];
        $count++;
    }

    $data = json_encode($data);
    $length = strlen($data);
    echo $length . chr(10);
    fwrite($conn, $data);
    fclose($conn);
}
fclose($server);

客户端

<?php

$uri = 'tcp://0.0.0.0:8522';
$errno = 0;
$errStr = '';
$stream = stream_socket_client($uri, $errno, $errStr, 30, STREAM_CLIENT_CONNECT | STREAM_CLIENT_PERSISTENT, stream_context_create([]));
$socket = socket_import_stream($stream);
socket_set_option($socket, SOL_SOCKET, SO_KEEPALIVE, 1);
socket_set_option($socket, SOL_TCP, TCP_NODELAY, 1);


$read[] = $stream;
$write = $e = [];
$response = '';
while (stream_select($read, $write, $e, 1)) {
    $response .= fread($stream, 1040001);
    if (strlen($response) >= 1040001) {
        break;
    }
}
echo $response . chr(10);
echo strlen($response) . chr(10);

这个问题需要服务端访问数据大才能复现,同一台机器上客户端可以收到完整报文,但是不同机器时就收不到了

后来我把服务端的stream_set_blocking设置为 1,客户端就可以收到完整报文,非阻塞下收不到完整报文,请问是哪里有问题?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

紅太極 2022-09-19 00:26:34

stream_set_blocking引起的问题。
由于非阻塞模式,fwrite的数据有可能写入不完整就返回了(阻塞模式不会,一定是写完才返回,写不完就阻塞直到写完),所以客户端收到的数据被截断了。

系统的I/O是有速度限制的,比如100KB/s,超过该限制的话需要等待网卡就绪才能写入。

  • 阻塞模式下,fwrite一直等待,直到系统底层可写才发送,数据最终也会被完整写入。
  • 非阻塞模式下, fwrite会返回当前写入成功的字节数,如果写入成功的字节数小于你传递的数据长度,则证明可写字节不够,需要调用stream_select对可写流进行可写状态监听,然后把剩余的数据进行fwrite
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文