0

0

Workerman怎么进行数据序列化?Workerman数据打包格式?

幻夢星雲

幻夢星雲

发布时间:2025-09-03 10:05:01

|

366人浏览过

|

来源于php中文网

原创

workerman中选择数据序列化方式的关键考量因素包括性能、跨语言兼容性、开发调试便利性及协议扩展性。性能方面需权衡序列化开销与数据大小,json适合跨语言通信,php serialize在同构环境中更高效,自定义二进制协议性能最优但开发成本高。通过实现协议类的len、decode、encode方法可解决粘包半包问题,常用策略有长度前缀、分隔符和固定长度法,其中长度前缀结合协议类注册是推荐做法。

workerman怎么进行数据序列化?workerman数据打包格式?

Workerman本身并没有强制规定你必须使用哪种数据序列化或打包格式。它提供的是一个底层网络通信框架,你可以完全自由地选择最适合你应用场景的数据编码方式。通常,我们会在

onMessage
回调中对接收到的原始数据进行反序列化,在发送数据时(
send
方法)进行序列化和打包。常见的选择包括PHP原生的
serialize
/
unserialize
、JSON、以及自定义的二进制协议。

在Workerman中,数据序列化和打包主要通过你定义的消息处理逻辑来实现。当客户端发送数据到Workerman服务端时,你会在

onMessage
回调函数中接收到一个原始的字符串数据。你需要在这个函数内部,根据你预设的协议格式,对这个字符串进行解析。反之,当你需要向客户端发送数据时,你需要先将你的PHP数据结构(数组、对象等)序列化成一个字符串,然后通过
$connection->send()
方法发送出去。

最直接也是最常用的方式就是使用JSON。它的优点在于跨语言兼容性好,可读性强,调试起来也方便。

// 假设这是你的Workerman服务启动文件
use Workerman\Worker;
use Workerman\Connection\TcpConnection;

require_once __DIR__ . '/vendor/autoload.php';

$worker = new Worker('tcp://0.0.0.0:2345');

$worker->onConnect = function(TcpConnection $connection) {
    echo "New connection from " . $connection->remoteAddress . "\n";
};

$worker->onMessage = function(TcpConnection $connection, $data) {
    // 接收到数据,尝试JSON解码
    $decodedData = json_decode($data, true); // true表示解码为关联数组

    if (json_last_error() === JSON_ERROR_NONE) {
        echo "Received JSON data: " . print_r($decodedData, true);

        // 假设我们要回应一个成功消息
        $response = ['status' => 'success', 'message' => 'Data received!', 'data' => $decodedData];
        $connection->send(json_encode($response));
    } else {
        echo "Received non-JSON data or invalid JSON: " . $data . "\n";
        $connection->send(json_encode(['status' => 'error', 'message' => 'Invalid JSON format.']));
    }
};

$worker->onClose = function(TcpConnection $connection) {
    echo "Connection closed\n";
};

Worker::runAll();

除了JSON,如果你所有的客户端都是PHP,那么

serialize
/
unserialize
也是一个不错的选择,它能更完整地保留PHP的数据类型信息。但话说回来,如果你的场景对性能有极致要求,或者需要与非PHP客户端进行高效通信,那么自定义二进制协议可能才是最终答案。

Workerman中选择数据序列化方式的关键考量因素是什么?

在我看来,选择Workerman中的数据序列化方式,绝不是拍脑袋就能决定的,它涉及到几个核心的权衡。首先是性能,这包括序列化和反序列化的CPU开销,以及序列化后数据的大小(直接影响网络带宽占用)。像PHP原生的

serialize
通常比JSON在PHP内部处理更快,因为它不需要额外的解析步骤,但序列化后的字符串可能比JSON或某些二进制协议更大。JSON虽然解析有开销,但其文本特性在跨语言场景下是巨大的优势,而且在很多场景下其数据大小也相当可观。自定义二进制协议往往能在数据大小和解析速度上做到极致,但开发成本也最高。

其次是跨语言兼容性。如果你的Workerman服务需要与Java、Python、JavaScript等不同语言的客户端进行通信,那么JSON无疑是首选,因为它是一种事实上的通用数据交换格式。而PHP的

serialize
则几乎只能在PHP环境中使用。自定义二进制协议虽然可以跨语言,但你需要为每种语言都实现一套相同的编解码逻辑,这无疑增加了复杂性。

再来就是开发与调试的便利性。JSON的可读性非常高,你在调试时直接看日志就能大致理解数据结构。PHP的

serialize
虽然可读性差一些,但在PHP内部调试也还算方便。自定义二进制协议嘛,那可就得硬着头皮对着字节流分析了,这无疑会增加开发和维护的难度。

最后,协议的演进和扩展性也得考虑。一个设计良好的JSON结构,或者一套有版本控制的二进制协议,在未来业务需求变化时,能更容易地添加字段或修改结构,而不会导致兼容性问题。这都是在项目初期就得深思熟虑的。

如何在Workerman中实现自定义数据协议以优化性能?

实现自定义数据协议是Workerman进阶使用的一个重要环节,尤其当你面对高并发、低延迟的场景时。Workerman提供了一个非常优雅的机制来处理这个问题,那就是协议类(Protocol Class)。你只需要创建一个遵循特定接口的PHP类,然后将其注册到Workerman的

Worker
实例上。

A1.art
A1.art

一个创新的AI艺术应用平台,旨在简化和普及艺术创作

下载

一个协议类通常需要实现几个静态方法:

  1. len($buffer)
    : 这个方法用于判断当前接收到的
    $buffer
    中是否包含一个完整的包。如果包含,它应该返回这个包的长度;如果不包含,或者数据不足以判断包长,则返回
    0
    。这是解决粘包和半包问题的核心。
  2. decode($buffer)
    : 当
    len
    方法返回一个大于0的长度时,Workerman会根据这个长度从
    $buffer
    中截取出完整的包,然后将这个包传递给
    decode
    方法。
    decode
    方法负责将这个原始的包数据反序列化成PHP数据,并返回。
  3. encode($data)
    : 当你需要通过
    $connection->send()
    发送数据时,Workerman会调用这个方法,将你的PHP数据(
    $data
    )序列化成符合你自定义协议格式的二进制字符串,然后发送出去。

举个例子,一个简单的“长度+数据”协议:

// Protocols/MyProtocol.php
namespace Protocols;

class MyProtocol
{
    // 假设我们用4个字节来存储包的长度(无符号长整型)
    const PACKAGE_LENGTH_BYTE = 4;

    /**
     * 判断当前缓冲区中是否包含一个完整的包。
     * 如果是,返回包的长度(包括头部);否则返回0。
     * @param string $buffer
     * @return int
     */
    public static function len($buffer)
    {
        // 如果连包头都不够,肯定不是一个完整的包
        if (strlen($buffer) < self::PACKAGE_LENGTH_BYTE) {
            return 0;
        }
        // 从缓冲区头部解析出包的长度
        // 'N' 表示无符号长整型(32位),网络字节序
        $length = unpack('N', substr($buffer, 0, self::PACKAGE_LENGTH_BYTE))[1];
        // 如果缓冲区中的数据长度小于包头声明的长度+包头自身长度,说明数据不完整
        if (strlen($buffer) < $length + self::PACKAGE_LENGTH_BYTE) {
            return 0;
        }
        // 返回完整包的长度
        return $length + self::PACKAGE_LENGTH_BYTE;
    }

    /**
     * 将原始的包数据解码成PHP数据
     * @param string $buffer 已经是一个完整的包(包含头部)
     * @return mixed
     */
    public static function decode($buffer)
    {
        // 截取掉头部,获取实际的数据部分
        $data = substr($buffer, self::PACKAGE_LENGTH_BYTE);
        // 这里可以根据你的实际需求进行反序列化,例如JSON
        return json_decode($data, true);
    }

    /**
     * 将PHP数据编码成符合协议格式的二进制字符串
     * @param mixed $data
     * @return string
     */
    public static function encode($data)
    {
        // 将PHP数据序列化成字符串,例如JSON
        $body = json_encode($data);
        // 计算数据体的长度
        $length = strlen($body);
        // 将长度打包成4字节的网络字节序
        $head = pack('N', $length);
        // 拼接头部和数据体
        return $head . $body;
    }
}

然后在你的Worker中这样使用:

// ...
use Protocols\MyProtocol;

$worker = new Worker('tcp://0.0.0.0:2345');
// 注册自定义协议
$worker->protocol = MyProtocol::class; 
// ...

这样,Workerman就会自动调用

MyProtocol
len
decode
encode
方法来处理数据的接收和发送,大大简化了你在
onMessage
中手动处理协议的复杂性,并且能有效地解决粘包问题。

Workerman处理粘包和半包问题的策略有哪些?

处理粘包(Sticky Packets)和半包(Half Packets)是所有TCP网络编程绕不开的坎。TCP是一个流式协议,它只保证数据的顺序性和完整性,不保证消息的边界。也就是说,你发送了两个包,接收端可能一次性收到两个包连在一起,也可能只收到第一个包的一部分。Workerman在设计时就考虑到了这一点,其核心策略就是协议类的

len
方法

当Workerman的

TcpConnection
接收到数据时,它会将数据追加到一个内部的接收缓冲区(
InputBuffer
)中。然后,它会不断地调用你注册的协议类中的
len
静态方法,并传入当前
InputBuffer
中的所有数据。

  1. len
    方法的关键作用

    • 如果
      len
      方法返回
      0
      ,这表示当前缓冲区中的数据不足以构成一个完整的包,或者数据格式不符合协议(比如包头不完整)。Workerman会暂停处理,等待更多数据到来。
    • 如果
      len
      方法返回一个大于
      0
      的整数(表示一个完整包的长度),Workerman就会根据这个长度,从
      InputBuffer
      中截取出一个完整的包,然后将这个包传递给协议类的
      decode
      方法进行解码,并从
      InputBuffer
      中移除这个已处理的包。
    • 这个过程会循环进行,直到
      len
      方法再次返回
      0
      ,或者
      InputBuffer
      为空。
  2. 常见的协议设计模式来解决粘包/半包

    • 长度前缀法:这是最常见也最可靠的方法。在每个消息的开头,都加上一个固定长度的字段来表示这个消息体有多长。例如,用4个字节存储消息体的长度。接收方先读取这4个字节,得到消息体的预期长度,然后根据这个长度去读取剩余的消息体。我们前面自定义协议的例子就是这种。
    • 分隔符法:在消息的末尾添加一个特殊的、不会出现在消息体中的分隔符(例如
      \r\n
      \n
      )。接收方不断读取数据直到遇到这个分隔符,就认为一个消息结束了。这种方法相对简单,但需要确保分隔符的唯一性,并且在二进制数据中容易出现问题。HTTP协议就是使用
      \r\n\r\n
      作为头部和body的分隔。
    • 固定长度法:如果所有消息的长度都是固定的,那么接收方每次只需要读取固定字节数即可。这种方法最简单,但灵活性最差,不适用于消息长度可变的应用。

Workerman的

len
方法正是为这些策略服务的。它提供了一个统一的接口,让开发者可以根据自己的协议设计,精确地判断消息边界。通过这种方式,Workerman将底层TCP流的复杂性抽象化,让开发者可以专注于业务逻辑,而不用过多地担心底层的粘包和半包问题。只要你的
len
方法实现得足够健壮和准确,你的Workerman应用在处理数据时就会非常稳定。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
json数据格式
json数据格式

JSON是一种轻量级的数据交换格式。本专题为大家带来json数据格式相关文章,帮助大家解决问题。

455

2023.08.07

json是什么
json是什么

JSON是一种轻量级的数据交换格式,具有简洁、易读、跨平台和语言的特点,JSON数据是通过键值对的方式进行组织,其中键是字符串,值可以是字符串、数值、布尔值、数组、对象或者null,在Web开发、数据交换和配置文件等方面得到广泛应用。本专题为大家提供json相关的文章、下载、课程内容,供大家免费下载体验。

546

2023.08.23

jquery怎么操作json
jquery怎么操作json

操作的方法有:1、“$.parseJSON(jsonString)”2、“$.getJSON(url, data, success)”;3、“$.each(obj, callback)”;4、“$.ajax()”。更多jquery怎么操作json的详细内容,可以访问本专题下面的文章。

334

2023.10.13

go语言处理json数据方法
go语言处理json数据方法

本专题整合了go语言中处理json数据方法,阅读专题下面的文章了解更多详细内容。

82

2025.09.10

数据类型有哪几种
数据类型有哪几种

数据类型有整型、浮点型、字符型、字符串型、布尔型、数组、结构体和枚举等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

337

2023.10.31

php数据类型
php数据类型

本专题整合了php数据类型相关内容,阅读专题下面的文章了解更多详细内容。

224

2025.10.31

c语言 数据类型
c语言 数据类型

本专题整合了c语言数据类型相关内容,阅读专题下面的文章了解更多详细内容。

138

2026.02.12

js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

760

2023.08.03

C# ASP.NET Core微服务架构与API网关实践
C# ASP.NET Core微服务架构与API网关实践

本专题围绕 C# 在现代后端架构中的微服务实践展开,系统讲解基于 ASP.NET Core 构建可扩展服务体系的核心方法。内容涵盖服务拆分策略、RESTful API 设计、服务间通信、API 网关统一入口管理以及服务治理机制。通过真实项目案例,帮助开发者掌握构建高可用微服务系统的关键技术,提高系统的可扩展性与维护效率。

3

2026.03.11

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Django 教程
Django 教程

共28课时 | 4.9万人学习

Excel 教程
Excel 教程

共162课时 | 21万人学习

R 教程
R 教程

共45课时 | 7.8万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号