日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪(fǎng)問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > php >内容正文

php

php如何编写通信协议,定制通讯协议

發(fā)布時(shí)間:2023/12/1 php 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 php如何编写通信协议,定制通讯协议 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

## 如何定制協(xié)議

實(shí)際上制定自己的協(xié)議是比較簡(jiǎn)單的事情。簡(jiǎn)單的協(xié)議一般包含兩部分:

* 區(qū)分?jǐn)?shù)據(jù)邊界的標(biāo)識(shí)

* 數(shù)據(jù)格式定義

## 一個(gè)例子

### 協(xié)議定義

這里假設(shè)區(qū)分?jǐn)?shù)據(jù)邊界的標(biāo)識(shí)為換行符"\n"(注意請(qǐng)求數(shù)據(jù)本身內(nèi)部不能包含換行符),數(shù)據(jù)格式為Json,例如下面是一個(gè)符合這個(gè)規(guī)則的請(qǐng)求包。

{"type":"message","content":"hello"}

注意上面的請(qǐng)求數(shù)據(jù)末尾有一個(gè)換行字符(在PHP中用**雙引號(hào)**字符串"\n"表示),代表一個(gè)請(qǐng)求的結(jié)束。

### 實(shí)現(xiàn)步驟

在WorkerMan中如果要實(shí)現(xiàn)上面的協(xié)議,假設(shè)協(xié)議的名字叫JsonNL,所在項(xiàng)目為MyApp,則需要以下步驟

1、協(xié)議文件放到項(xiàng)目的Protocols文件夾,例如文件MyApp/Protocols/JsonNL.php

2、實(shí)現(xiàn)JsonNL類(lèi),以```namespace Protocols;```為命名空間,必須實(shí)現(xiàn)三個(gè)靜態(tài)方法分別為 input、encode、decode

注意:workerman會(huì)自動(dòng)調(diào)用這三個(gè)靜態(tài)方法,用來(lái)實(shí)現(xiàn)分包、解包、打包。具體流程參考下面執(zhí)行流程說(shuō)明。

### workerman與協(xié)議類(lèi)交互流程

1、假設(shè)客戶(hù)端發(fā)送一個(gè)數(shù)據(jù)包給服務(wù)端,服務(wù)端收到數(shù)據(jù)(可能是部分?jǐn)?shù)據(jù))后會(huì)立刻調(diào)用協(xié)議的```input```方法,用來(lái)檢測(cè)這包的長(zhǎng)度,```input```方法返回長(zhǎng)度值```$length```給workerman框架。

2、workerman框架得到這個(gè)```$length```值后判斷當(dāng)前數(shù)據(jù)緩沖區(qū)中是否已經(jīng)接收到```$length```長(zhǎng)度的數(shù)據(jù),如果沒(méi)有就會(huì)繼續(xù)等待數(shù)據(jù),直到緩沖區(qū)中的數(shù)據(jù)長(zhǎng)度不小于```$length```。

4、緩沖區(qū)的數(shù)據(jù)長(zhǎng)度足夠后,workerman就會(huì)從緩沖區(qū)截取出```$length```長(zhǎng)度的數(shù)據(jù)(即**分包**),并調(diào)用協(xié)議的```decode```方法**解包**,解包后的數(shù)據(jù)為```$data```。

3、解包后workerman將數(shù)據(jù)```$data```以回調(diào)```onMessage($connection, $data)```的形式傳遞給業(yè)務(wù),業(yè)務(wù)在onMessage里就可以使用```$data```變量得到客戶(hù)端發(fā)來(lái)的完整并且已經(jīng)解包的數(shù)據(jù)了。

4、當(dāng)```onMessage```里業(yè)務(wù)需要通過(guò)調(diào)用```$connection->send($buffer)```方法給客戶(hù)端發(fā)送數(shù)據(jù)時(shí),workerman會(huì)自動(dòng)利用協(xié)議的```encode```方法將```$buffer```**打包**后再發(fā)給客戶(hù)端。

### 具體實(shí)現(xiàn)

**MyApp/Protocols/JsonNL.php的實(shí)現(xiàn)**

```php

namespace Protocols;

class JsonNL

{

/**

* 檢查包的完整性

* 如果能夠得到包長(zhǎng),則返回包的在buffer中的長(zhǎng)度,否則返回0繼續(xù)等待數(shù)據(jù)

* 如果協(xié)議有問(wèn)題,則可以返回false,當(dāng)前客戶(hù)端連接會(huì)因此斷開(kāi)

* @param string $buffer

* @return int

*/

public static function input($buffer)

{

// 獲得換行字符"\n"位置

$pos = strpos($buffer, "\n");

// 沒(méi)有換行符,無(wú)法得知包長(zhǎng),返回0繼續(xù)等待數(shù)據(jù)

if($pos === false)

{

return 0;

}

// 有換行符,返回當(dāng)前包長(zhǎng)(包含換行符)

return $pos+1;

}

/**

* 打包,當(dāng)向客戶(hù)端發(fā)送數(shù)據(jù)的時(shí)候會(huì)自動(dòng)調(diào)用

* @param string $buffer

* @return string

*/

public static function encode($buffer)

{

// json序列化,并加上換行符作為請(qǐng)求結(jié)束的標(biāo)記

return json_encode($buffer)."\n";

}

/**

* 解包,當(dāng)接收到的數(shù)據(jù)字節(jié)數(shù)等于input返回的值(大于0的值)自動(dòng)調(diào)用

* 并傳遞給onMessage回調(diào)函數(shù)的$data參數(shù)

* @param string $buffer

* @return string

*/

public static function decode($buffer)

{

// 去掉換行,還原成數(shù)組

return json_decode(trim($buffer), true);

}

}

```

至此,JsonNL協(xié)議實(shí)現(xiàn)完畢,可以在MyApp項(xiàng)目中使用,使用方法例如下面

文件:MyApp\start.php

```php

use Workerman\Worker;

require_once '/your/path/Workerman/Autoloader.php'

$json_worker = new Worker('JsonNL://0.0.0.0:1234');

$json_worker->onMessage = function($connection, $data) {

// $data就是客戶(hù)端傳來(lái)的數(shù)據(jù),數(shù)據(jù)已經(jīng)經(jīng)過(guò)JsonNL::decode處理過(guò)

echo $data;

// $connection->send的數(shù)據(jù)會(huì)自動(dòng)調(diào)用JsonNL::encode方法打包,然后發(fā)往客戶(hù)端

$connection->send(array('code'=>0, 'msg'=>'ok'));

};

Worker::runAll();

...

```

### 協(xié)議接口說(shuō)明

在WorkerMan中開(kāi)發(fā)的協(xié)議類(lèi)必須實(shí)現(xiàn)三個(gè)靜態(tài)方法,input、encode、decode,協(xié)議接口說(shuō)明見(jiàn)Workerman/Protocols/ProtocolInterface.php,定義如下:

```php

namespace Workerman\Protocols;

use \Workerman\Connection\ConnectionInterface;

/**

* Protocol interface

* @author walkor

*/

interface ProtocolInterface

{

/**

* 用于在接收到的recv_buffer中分包

*

* 如果可以在$recv_buffer中得到請(qǐng)求包的長(zhǎng)度則返回整個(gè)包的長(zhǎng)度

* 否則返回0,表示需要更多的數(shù)據(jù)才能得到當(dāng)前請(qǐng)求包的長(zhǎng)度

* 如果返回false或者負(fù)數(shù),則代表錯(cuò)誤的請(qǐng)求,則連接會(huì)斷開(kāi)

*

* @param ConnectionInterface $connection

* @param string $recv_buffer

* @return int|false

*/

public static function input($recv_buffer, ConnectionInterface $connection);

/**

* 用于請(qǐng)求解包

*

* input返回值大于0,并且WorkerMan收到了足夠的數(shù)據(jù),則自動(dòng)調(diào)用decode

* 然后觸發(fā)onMessage回調(diào),并將decode解碼后的數(shù)據(jù)傳遞給onMessage回調(diào)的第二個(gè)參數(shù)

* 也就是說(shuō)當(dāng)收到完整的客戶(hù)端請(qǐng)求時(shí),會(huì)自動(dòng)調(diào)用decode解碼,無(wú)需業(yè)務(wù)代碼中手動(dòng)調(diào)用

* @param ConnectionInterface $connection

* @param string $recv_buffer

*/

public static function decode($recv_buffer, ConnectionInterface $connection);

/**

* 用于請(qǐng)求打包

*

* 當(dāng)需要向客戶(hù)端發(fā)送數(shù)據(jù)即調(diào)用$connection->send($data);時(shí)

* 會(huì)自動(dòng)把$data用encode打包一次,變成符合協(xié)議的數(shù)據(jù)格式,然后再發(fā)送給客戶(hù)端

* 也就是說(shuō)發(fā)送給客戶(hù)端的數(shù)據(jù)會(huì)自動(dòng)encode打包,無(wú)需業(yè)務(wù)代碼中手動(dòng)調(diào)用

* @param ConnectionInterface $connection

* @param mixed $data

*/

public static function encode($data, ConnectionInterface $connection);

}

```

## 注意:

Workerman中沒(méi)有嚴(yán)格要求協(xié)議類(lèi)必須基于ProtocolInterface實(shí)現(xiàn),實(shí)際上協(xié)議類(lèi)只要類(lèi)包含了input、encode、decode三個(gè)靜態(tài)方法即可。

總結(jié)

以上是生活随笔為你收集整理的php如何编写通信协议,定制通讯协议的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。