参考文章 https://blog.csdn.net/ldy3243942/article/details/40920743

下面都是原文 最后才是自己的

swoole入门教程05-Swoole的自定义协议功能的使用
2014年11月08日 14:40:21

环境说明: 系统:Ubuntu14.04 (安装教程包括CentOS6.5)
PHP版本:PHP-5.5.10
swoole版本:1.7.8-alpha


1.为什么要提供自定义协议

熟悉TCP通信的朋友都会知道,TCP是一个流式协议。客户端向服务器发送的一段数据,可能并不会被服务器一次就完整的收到;客户端向服务器发送的多段数据,可能服务器一次就收到了全部的数据。而实际应用中,我们希望在服务器端能一次接收一段完整的数据,不多也不少。传统的TCP服务器中,往往需要由程序员维护一个缓存区,先将读到的数据放进缓存区中,然后再通过预先设定好的协议内容,来区分一段完整数据的开头、长度和结尾,并将一段完整的数据交给逻辑部分处理。这就是自定义协议的功能。
而在Swoole中,已经在底层实现了一个数据缓存区,并内置好了几个常用的协议类型,直接在底层做好了数据的拆分,保证了在onReceive回调函数中,一定能收到一个(或数个)完整的数据段。数据缓存区的大小可以通过配置选项package_max_length来控制。下面我就将讲解如何使用这些内置协议。

2.EOF标记型协议

第一个比较常用的协议就是EOF标记协议。协议的内容是通过规定一个一定不会出现在正常数据中的字符或者字符串,用这个来标记一段完整数据的结尾。这样,只要发现这个结尾,就可以认定之前的数据已经结束,可以开始接收一个新的数据段了。
在Swoole中,可以通过open_eof_check和package_eof两个配置项来开启。其中,open_eof_check指定开启了EOF检测,package_eof指定了具体的EOF标记。通过这两个选项,Swoole底层就会自动根据EOF标记来缓存和拆分收到的数据包。示例如下:

$this->serv->set(array(
    'package_max_length' => 8192,
    'open_eof_check'=> true,
    'package_eof' => "\r\n"
));

就这样,swoole就已经开启了EOF标记协议的解析。那么让我们来测试一下效果:
服务器这边:

// Server
public function onReceive( swoole_server $serv, $fd, $from_id, $data ) {    echo "Get Message From Client {$fd}:{$data}\n";
}

客户端这边:

$msg_eof = "This is a Msg\r\n";

$i = 0;
while( $i < 100 ) {    $this->client->send( $msg_eof );
    $i ++;
}

然后运行一下,你会发现:哎不对啊,为什么还是一次收到了好多数据啊!
这是因为,在Swoole中,采用的不是遍历识别的方法,而只是简单的检查每一次接收到的数据的末尾是不是定义好的EOF标记。因此,在开启EOF检测后,onReceive回调中还是可能会一次收到多个数据包。
这要怎么办?你会发现,虽然是多个数据包,但是实际上收到的是N个完整的数据片段,那就只需要根据EOF把每个包再拆出来,一个个处理就好啦。
修改后的服务器端代码如下:

public function onReceive( swoole_server $serv, $fd, $from_id, $data ) {    $data_list = explode("\r\n", $data);
    foreach ($data_list as $msg) {        if( !empty($msg) ) {            echo "Get Message From Client {$fd}:{$msg}\n";
        }

    }
}

再次运行,妥了~
点此查看完整实例
另外,如果担心这样运行多段数据会长时间占用Worker,可以采用把数据+fd转发给Task进程的做法。如何转发请读者自己尝试实现。

============================================我是分割线========================================

下面开始把源代码 转换到 fd+task里 并通知客户端

首先server端代码如下  代码格式没做对齐

<?php
class Server
{private $serv;public function __construct() {$this->serv = new swoole_server("0.0.0.0", 9501);$this->serv->set(array('worker_num' => 8,'daemonize' => false,'max_request' => 10000,'dispatch_mode' => 2,'package_max_length' => 8192,'open_eof_check'=> true,'package_eof' => "\r\n",'task_worker_num'=>8,));$this->serv->on('Start', array($this, 'onStart'));$this->serv->on('Connect', array($this, 'onConnect'));$this->serv->on('Receive', array($this, 'onReceive'));$this->serv->on('Close', array($this, 'onClose'));//自己增加的$this->serv->on('Task', array($this, 'onTask'));$this->serv->on('Finish', array($this, 'onFinish'));$this->serv->start();}public function onStart( $serv ) {echo "Start\n";}public function onConnect( $serv, $fd, $from_id ) {echo "Client {$fd} connect\n";}public function onReceive( swoole_server $serv, $fd, $from_id, $data ) {// echo "Get Message From Client {$fd}:{$data}\n";// // send a task to task worker.$param = array('fd' => $fd,'data'=>$data,);//$data_list = explode("\r\n", $data);//先尝试直接转走 教给task 这里不能打开上面的注释 因为一次性还是会有可能进来很多$serv->task( json_encode( $param ) );echo "Continue Handle Worker\n";}public function onClose( $serv, $fd, $from_id ) {echo "Client {$fd} close connection\n";}public function onTask($serv,$task_id,$from_id, $data) {echo "This Task {$task_id} from Worker {$from_id}\n";$fd = json_decode( $data , true )['fd'];$data_arr = json_decode( $data , true )['data'];$data_list = explode("\r\n", $data_arr);// print("收到的Data: {$data}\n"); 这里还是会一次收到好多个foreach ($data_list as $msg) {if( !empty($msg) ) {echo "Get Message From Client {$fd}:{$msg}\n";}}$serv->send( $fd , "Data in Task {$task_id}");//这里给客户端发个消息吧 告诉他现在做完了echo "send is ok?\n";return "Task {$task_id}'s result";//返回结果onfinsh}public function onFinish($serv,$task_id, $data) {echo "Task {$task_id} finish\n";echo "Result: {$data}\n";}}
new Server();

client 客户端

<?php
class Client
{private $client;public function __construct() {$this->client = new swoole_client(SWOOLE_SOCK_TCP, SWOOLE_SOCK_ASYNC);$this->client->on('Connect', array($this, 'onConnect'));$this->client->on('Receive', array($this, 'onReceive'));$this->client->on('Close', array($this, 'onClose'));$this->client->on('Error', array($this, 'onError'));}public function connect() {$fp = $this->client->connect("127.0.0.1", 9501 , 1);if( !$fp ) {echo "Error: {$fp->errMsg}[{$fp->errCode}]\n";return;}}public function onReceive( $cli, $data ) {echo "Get Message From Server: {$data}\n";}public function onConnect( $cli) {$msg_eof = "This is a Msg\r\n";//      $msg_length = pack("N" , strlen($msg_normal) ). $msg_normal;//  $msg_length = pack("N" , strlen($msg_eof) ). $msg_eof;$i = 0;while(1){if( $i < 100 ) { //有可能会分几次发 因为一次可能处理不完//            $this->client->send( $msg_length );$this->client->send( $msg_eof );$i ++;}else{break; //这里一定加个else 不然的话 无法收到返回信息 会被while(1) 始终阻塞在那里}}}public function onClose( $cli) {echo "Client close connection\n";}public function onError() {}public function send($data) {$this->client->send( $data );}public function isConnected() {return $this->client->isConnected();}
}
$cli = new Client();
$cli->connect();

运行结果如下 server端

下面运行客户端

这里看到客户端收到了一个消息 这是说明server端做完任务给的返回信息 返回信息随意写的

再看server端

又重新截了一次图 server 端 截图以这里的为主

client 端 对应上面的 8 和 9

======================我是分割线=============================

上面是自己的一点补充 下面是原本的

server代码如下

<?php
class Server
{private $serv;public function __construct() {$this->serv = new swoole_server("0.0.0.0", 9501);$this->serv->set(array('worker_num' => 8,'daemonize' => false,'max_request' => 10000,'dispatch_mode' => 2,'package_max_length' => 8192,'open_eof_check'=> true,'package_eof' => "\r\n"));$this->serv->on('Start', array($this, 'onStart'));$this->serv->on('Connect', array($this, 'onConnect'));$this->serv->on('Receive', array($this, 'onReceive'));$this->serv->on('Close', array($this, 'onClose'));$this->serv->start();}public function onStart( $serv ) {echo "Start\n";}public function onConnect( $serv, $fd, $from_id ) {echo "Client {$fd} connect\n";}public function onReceive( swoole_server $serv, $fd, $from_id, $data ) {$data_list = explode("\r\n", $data);foreach ($data_list as $msg) {if( !empty($msg) ) {echo "Get Message From Client {$fd}:{$msg}\n";}}}public function onClose( $serv, $fd, $from_id ) {echo "Client {$fd} close connection\n";}
}
new Server();

client 用原来的 稍作修改 不然github上那个无法测试这个 eof模式的代码 不需要pack 删除了那个

这里引出了一个问题 因为 想要回调 Receive 那么必须

//$this->client = new swoole_client(SWOOLE_SOCK_TCP, SWOOLE_SOCK_ASYNC);

// $this->client->on('Receive', array($this, 'onReceive'));

他们一组

否则

$this->client = new swoole_client(SWOOLE_SOCK_TCP);
       //$this->client = new swoole_client(SWOOLE_SOCK_TCP, SWOOLE_SOCK_ASYNC);

// $this->client->on('Receive', array($this, 'onReceive'));

不然会报错

回到正题 client端代码

<?php
class Client
{private $client;public function __construct() {$this->client = new swoole_client(SWOOLE_SOCK_TCP);}public function connect() {global $client;if( !$this->client->connect("0.0.0.0", 9501 , 1) ) {echo "Error: {$fp->errMsg}[{$fp->errCode}]\n";}$msg_normal = "This is a Msg";$msg_eof = "This is a Msg\r\n";//      $msg_length = pack("N" , strlen($msg_normal) ). $msg_normal;$msg_length = pack("N" , strlen($msg_eof) ). $msg_eof;$i = 0;while( $i < 100 ) {//      $this->client->send( $msg_length );$this->client->send( $msg_eof );$i ++;}}
}
$client = new Client();
$client->connect();

这样运行后 server 会有个notice

百度了一下 说这个不是错误 只不过是客户端发送数据后关闭了 那么看下客户端 运行结果

所以才会有上面的警告提示 这个可以忽略

可能这个文章说的有点乱 自己试一下应该会好很多吧 大概就这个样子了

swoole 自定义eof 标记 带返回信息(自己修改)和 不带返回信息的原本demo相关推荐

  1. ###用户信息的修改及用户的认证信息###

    ###用户信息的修改及用户的认证信息### 在实际生活中,我们需要对用户的信息作出改变,在Linux系统中给我们提供了以下方法. 1.修改用户信息可以使用以下命令: 命令 参数 新名称/ID/其他 用 ...

  2. 【pytest官方文档】解读- 如何自定义mark标记,并将测试用例的数据传递给fixture函数

    在之前的分享中,我们知道可以使用yield或者return关键字把fixture函数里的值传递给test函数. 这种方法很实用,比如我在fixture函数里向数据库里插入必要的测试数据,那我就可以把相 ...

  3. 高德地图实现自定义小蓝点 自定义点标记 绘制多边形/圆形区域 根据地图的移动显示或者隐藏自定义点标记的相关实现

    最近项目升级改版,项目中本来应用了苹果自带的定位模块,但升级改版有需要应用到高德地图的模块,在参考别的app地图相关模块实现过程中,自己产生了一些想法.首先说明要实现的功能需求.类似支付宝app内的跑 ...

  4. ios 带scrollView的控制器,双击“状态栏”,返回scrollView的顶部

    ios  带scrollView的控制器,双击"状态栏",返回scrollView的顶部 自动存在的属性,如果没有过分的自定义一般都好使. 转载于:https://www.cnbl ...

  5. html自定义标记,HTML模板(自定义)标记

    我知道使用自定义html标记由于各种原因是不合适的,但我想运行一个特定的情况,可能需要自定义html标记,并希望得到其他方面的信息,或者可能更好实现我的目标的方式.HTML模板(自定义)标记 在我的代 ...

  6. tablueau地图标记圆形_高德地图实现自定义小蓝点 自定义点标记 绘制多边形/圆形区域 根据地图的移动显示或者隐藏自定义点标记的相关实现...

    最近项目中有需要应用到高德地图的模块,在参考别的app地图相关模块实现过程中,自己产生了一些想法.首先说明要实现的功能需求.类似支付宝app内的跑腿功能,在全市的所有商铺,电梯广告等任意地点发布任务, ...

  7. 高德地图自定义点标记大小_高德地图实现自定义小蓝点 自定义点标记 绘制多边形/圆形区域 根据地图的移动显示或者隐藏自定义点标记的相关实现...

    最近项目中有需要应用到高德地图的模块,在参考别的app地图相关模块实现过程中,自己产生了一些想法.首先说明要实现的功能需求.类似支付宝app内的跑腿功能,在全市的所有商铺,电梯广告等任意地点发布任务, ...

  8. 利用DNSLOG获取看不到的信息(给盲注带上眼镜)

    一.前言 本文属i春秋原创奖励计划,未经许可禁止转载! 毕业设计总算搞得差不多了,这个心累啊. 这不,完成了学校的任务,赶紧回来给蛋总交作业. 今天给大家分享一个姿势吧,不是什么新东西,但比较少见-- ...

  9. CodeGen编写自定义表达式标记

    CodeGen编写自定义表达式标记 CodeGen支持开发人员通过编写plug-in modules插件模块来定义自定义表达式标记的能力,以提供与这些标记相关联的逻辑.这种plug-in module ...

最新文章

  1. TeamViewer介绍:远程控制计算机
  2. MySQL 不落地迁移、导入 PostgreSQL - 推荐 rds_dbsync
  3. html3d样式,CSS+HTML3D文字效果
  4. HDU 1506 Largest Rectangle in a Histogram(dp、单调栈)
  5. 于我,过去,现在和未来 —— 西格里夫·萨松
  6. python os rename用法_Python os.rename() 方法
  7. windows进入mysql改user_windows下如何修改mysql数据库密码
  8. 字节跳动新加坡职位 Algorithm Engineer (Platform Governance)
  9. 我的第一本算法书(图解算法)——什么是哈希表
  10. JAVA(-Xms,Xmx,Xmn-XX:newSize,-XX:MaxnewSize,-XX:PermSize,-XX:MaxPermSize)区别
  11. 【Python学习之路】——Day7(面向对象)
  12. 新版傻妞对接QQ完整版(10月24日)
  13. 统计学 常用的数据分析方法大总结,推荐收藏
  14. 基于Web的酒店客房管理系统
  15. 终于把所有的Python库,都整理出来啦
  16. Flink Web UI不能访问
  17. matlab显示tiff为全白_Matlab读写TIFF图像
  18. windows配置代理
  19. Android各版本对应的SDK及JDK版本要求
  20. 读书笔记 摘自:《为什么精英都是时间控》

热门文章

  1. Leetcode 513 javascript
  2. Qt那些事0.0.2
  3. import pycharm setting_Pycharm不能正常使用的常见问题
  4. python多核cpu_Python中的多核CPU共享数据之协程详解
  5. 导入项目到IDEA报javax/xml/bind/DatatypeConverter错误?
  6. [Ext JS]Grid的列过滤
  7. Java事务管理之Spring+Hibernate
  8. Oracle rac 组件reload,亲测Linux 7系列 上安装Oracle RAC 遇到的问题和坑
  9. 数据库oracle修改属性列,Oracle修改表结构
  10. mysql 添加删除权限_MySQL实例讲解:添加账户、授予权限、删除用户