workerman在接收大数据的时候(也没多大也就36k左右),为什么出现了数据分段情况

lxy

这是我写的程序一部分,接收到数据通过bin2hex转换之后打印数据,为了验证是分段我加了sssss标识
[attach]2471[/attach]
下面是结果图

[attach]2472[/attach]
....
[attach]2473[/attach]
 

2670 3 0
3个回答

jis

tcp本来就是分段传输,没毛病

  • lxy 2019-10-16

    我要是想将这个整个数据存到数据库,应该怎么处理哪

jis

弄个通讯协议,发数据的时候按照协议格式发。
比如 workerman的text协议,格式就是数据末尾加一个换行符"\n",注意PHP里是双引号。
 
workerman的话就是 $tcp_worker = new Worker('text://0.0.0.0:1234');
 
客户端发数据的话在末尾加一个换行符来表示数据包结束。PHP代码类似:
$client = stream_socket_client('tcp://127.0.0.1:1234');
// 注意,text协议格式是数据末尾加换行符 "\n",注意是双引号,之前吃过这个亏
fwirte($client, '36K数据'."\n");
 
按照服务端的协议格式发就能完整接收了。当然你可以定义其它协议,workerman文档里有定义方法,自定义协议我还没用过。
http://doc.workerman.net/protocols/why-protocols.html
http://doc.workerman.net/protocols/why-protocols.html
http://doc.workerman.net/protocols/example.html

lxy

问题已经解决
问题原因:tcp协议本身是分段传输的,这个传输的大小可能就是几十k左右。
解决方法:需要自定义通讯协议(其原理还是基于tcp传输,只是在接收数据的时候进行了判断)
自定义协议方法:http://doc.workerman.net/protocols/how-protocols.html
自定义协议代码:

<?php
namespace Workerman\Protocols;

/**
 * Lxy Protocol.
 */
class Lxy
{

    // workerman接收数据的过程(workerman手册上有描述,在定制通讯协议那里) 
    //1、假设客户端发送一个数据包给服务端,服务端收到数据(可能是部分数据)后会立刻调用协议的 input 方法,用来检测这个包的长度,input方法会返回数据包长度$length(也就是通讯协议告诉workerman框架我要这么长的数据)
    // 2、workerman框架会判断当前缓冲区里面有没有这么长的数据,如果没有就继续等待,直到数据长度达到要求。
    // 3、然后框架会从缓冲区中取出这么长的数据,调用decode方法,decode方法就是将数据进行处理,处理完成之后将数据return到onMessage,这样我们就可以在onMessage编写业务代码了。

    //定义自己要接收到的数据有多长
    const PACKAGE_LEN = 36018;
    public static function input($recv_buffer)
    {
        // $recv_buffer 接收到的数据
        // $data_len 获取当前的数据长度
        $data_len = strlen($recv_buffer);
        // 如果不够数据长度,则继续等待
        if($data_len &lt; self::PACKAGE_LEN)
        {
            return 0;
        }
        // 数据达到长度,返回包长,这里返回的包长,相当于告诉decode方法,要从缓冲区中取出这么长的数据
        return $data_len;
        //================================================
            // //这里是我的项目中需要传输二进制数的逻辑,如果你只是传输较长的字符串,这里可以不用看
            // // 我的项目中,是硬件设备通过tcp协议传输数据,硬件方面传输的时候是16进制,但是不知道为什么经过tcp之后变成了二进制(这里没有管他,接收到之后直接由二进制转成十六进制)
            // $recv_buffer = bin2hex($recv_buffer);//二进制转十六进制
            // $data_len = strlen($recv_buffer);//获取转化之后的长度
            // // 如果不够数据长度,则继续等待
            // if($data_len &lt; self::PACKAGE_HEAD_LEN)
            // {
            //     return 0;
            // }
            // // 返回包长,注意:这里返回的时候又将数据从二进制转成了十六进制了,因为二进制和十六进制的长度不同,decode方法里面要处理的数据是刚传来时的二进制数,所以这里要转回二进制
            // $data_len = strlen(hex2bin($recv_buffer));
            // return $data_len;
        // =================================================
    }

    /**
     * Decode.
     *
     * @param string $buffer
     * @return string
     */
    public static function decode($recv_buffer)
    {
        // $recv_buffer : 根据返回的包长,从缓冲区中获取数据
        // 测试过程中如果不知道哪里出问题了可以将数据放到文件中查看 : file_put_contents('data_len.txt','data:'.$recv_buffer.PHP_EOL, FILE_APPEND);
        // 将数据return到onMessage,就完成了简单的自定义协议了
        return $recv_buffer;

    }

    /**
     * Encode.
     *
     * @param string $buffer
     * @return string
     * 这个是给客户端发送数据的,我没用到
     */
    public static function encode($data)
    {

        return $data;
    }

}
workerman程序代码:
&lt;?php
use Workerman\Worker;
use Workerman\Lib\Timer;
define('BASE_DIR','。。。');
require_once BASE_DIR . 'Workerman/Autoloader.php';
require_once BASE_DIR . 'worker/mysql-master/src/Connection.php';

    $tcp_worker = new Worker(&quot;Lxy://0.0.0.0:8282&quot;);
    $tcp_worker-&gt;onWorkerStart = function ($worker) {
        global $db;
        //地址,端口,账户,密码,数据库名
        $db = new \Workerman\MySQL\Connection('127.0.0.1', '3306', '', '', '');
    };

    // 启动进程对外提供服务
    $tcp_worker-&gt;count = 1;
    //获取客户端ip
    $tcp_worker-&gt;onConnect = function ($connection) {
        global $db;
        echo &quot;client connect ip:&quot; . $connection-&gt;getRemoteIp() . &quot; port:&quot; . $connection-&gt;getRemotePort() . PHP_EOL;
        $connection-&gt;send('connection success');
    };
    $tcp_worker-&gt;onMessage = function($connection, $data){
        global $db;
        var_dump($data);
        echo 'sssssssssssssssssssssssssss'.PHP_EOL;
    };

// 运行worker
Worker::runAll();
  • 暂无评论
年代过于久远,无法发表回答
🔝