TCP 服務
TCP 基礎 Demo
EasySwoole
創(chuàng)建 TCP
服務器,有兩種以下方式:
1.將 TCP 服務作為 EasySwoole 的主服務。
首先修改配置文件中 MAIN_SERVER.SERVER_TYPE
配置項為 EASYSWOOLE_SERVER
。
然后在 EasySwooleEvent
的 mainServerCreate 事件中注冊回調,注冊參考示例如下:
<?php
namespace EasySwoole\EasySwoole;
use EasySwoole\EasySwoole\AbstractInterface\Event;
use EasySwoole\EasySwoole\Swoole\EventRegister;
use Swoole\Server as SwooleServer;
class EasySwooleEvent implements Event
{
// ...
public static function mainServerCreate(EventRegister $register)
{
$register->add($register::onConnect, function (SwooleServer $server, int $fd, int $reactorId) {
echo "fd{$fd} connected\n";
});
$register->add($register::onReceive, function (SwooleServer $server, int $fd, int $reactorId, string $data) {
echo "fd:{$fd} receive_data:{$data}\n";
});
$register->add($register::onClose, function (SwooleServer $server, int $fd, int $reactorId) {
echo "fd {$fd} closed\n";
});
}
}
2.將 TCP 服務作為 EasySwoole 的子服務。顧名思義:另外開一個端口進行
tcp
監(jiān)聽。
在 EasySwooleEvent
中的 mainServerCreate 事件中進行子服務監(jiān)聽,參考代碼如下:
<?php
namespace EasySwoole\EasySwoole;
use EasySwoole\EasySwoole\AbstractInterface\Event;
use EasySwoole\EasySwoole\Swoole\EventRegister;
use Swoole\Server as SwooleServer;
class EasySwooleEvent implements Event
{
// ...
public static function mainServerCreate(EventRegister $register)
{
// ....
$server = ServerManager::getInstance()->getSwooleServer();
$subPort = $server->addlistener('0.0.0.0', 9502, SWOOLE_TCP);
$subPort->set([
// swoole 相關配置
'open_length_check' => false,
]);
$subPort->on($register::onConnect, function (SwooleServer $server, int $fd, int $reactorId) {
echo "fd {$fd} connected\n";
});
$subPort->on($register::onReceive, function (SwooleServer $server, int $fd, int $reactorId, string $data) {
echo "fd:{$fd} received_data:{$data}\n";
});
$subPort->on($register::onClose, function (SwooleServer $server, int $fd, int $reactorId) {
echo "fd {$fd} closed\n";
});
}
}
如何處理粘包
1.解決思路
-
方法1:通過標識
EOF
,例如http
協(xié)議,通過\r\n\r\n
的方式去表示該數(shù)據(jù)已經完結,我們可以自定義一個協(xié)議。例如當接收到 "結尾666" 字符串時,代表該字符串已經結束,如果沒有獲取到,則存入緩沖區(qū),等待結尾字符串,或者如果獲取到多條,則通過該字符串剪切出其他數(shù)據(jù)。 -
方法2:定義消息頭,通過特定長度的消息頭進行獲取。例如我們定義一個協(xié)議,前面 10 位字符串都代表著之后數(shù)據(jù)主體的長度,那么我們傳輸數(shù)據(jù)時,只需要
000000000512346
(前10位為協(xié)議頭,表示了這條數(shù)據(jù)的大小,后面的為數(shù)據(jù)),每次我們讀取只先讀取10位,獲取到消息長度,再讀取消息長度那么多的數(shù)據(jù),這樣就可以保證數(shù)據(jù)的完整性了。(但是為了不被混淆,協(xié)議頭也得像EOF
一樣標識) -
方法3:通過
pack
二進制處理,相當于于方法2,將數(shù)據(jù)通過二進制封裝拼接進消息中,通過驗證二進制數(shù)據(jù)去讀取信息,swoole
采用的就是這種方式。
可查看 swoole 官方文檔: https://wiki.swoole.com/zh-cn/#/learn?id=tcp數(shù)據(jù)包邊界問題