Rumah  >  Artikel  >  rangka kerja php  >  Kongsi protokol tersuai Workerman untuk menyelesaikan masalah melekit dan membongkar

Kongsi protokol tersuai Workerman untuk menyelesaikan masalah melekit dan membongkar

青灯夜游
青灯夜游ke hadapan
2022-12-12 20:09:511721semak imbas

pekerjaBagaimanakah protokol tersuai menyelesaikan masalah melekit dan membongkar? Artikel berikut akan memperkenalkan kepada anda cara protokol tersuai Workerman menyelesaikan masalah paket melekit dan membongkar saya harap ia akan membantu semua orang.

Kongsi protokol tersuai Workerman untuk menyelesaikan masalah melekit dan membongkar

Kata Pengantar:

Memandangkan saya baru-baru ini menggunakan workererman untuk melaksanakan bahagian pelayan permainan dalam talian Unity3D, walaupun ia juga boleh berkomunikasi secara langsung melalui protokol TCP, tetapi beberapa masalah kecil ditemui semasa ujian sebenar. [Cadangan berkaitan: "Tutorial pekerja"]

Contohnya, adakah paket data pada kedua-dua belah dalam bentuk rentetan Juga, kerana ia adalah rentetan, ia perlu dipotong, dan kadangkala apabila pelanggan Ralat akan berlaku apabila klien atau pelayan menerimanya. Selepas mencetak log, didapati bahawa paket yang diterima oleh kedua-dua hujung adalah dalam format yang tidak dipersetujui terlebih dahulu. Ini adalah fenomena melekit dan membongkar TCP. Penyelesaian untuk ini sangat mudah, dan terdapat banyak di Internet, tetapi di sini saya ingin menggunakan protokol yang saya laksanakan untuk menyelesaikannya, jadi saya akan meninggalkannya untuk kemudian.

Jawapan kepada soalan:

Saya juga telah melihat beberapa konvensyen mengenai format paket data komunikasi permainan dalam talian di Internet. Jika anda tidak menggunakan bahasa yang ditaip lemah untuk melakukan skrip sebelah pelayan, yang lain sering menggunakan tatasusunan bait. Tetapi apabila PHP menerima tatasusunan bait, ia sebenarnya adalah rentetan, tetapi premisnya ialah tatasusunan bait itu tidak mempunyai beberapa penukaran tertentu. Ambil C# sebagai contoh Apabila menyelesaikan masalah seperti paket melekit, panjang bait (BitConverter.GetBytes (len)) akan ditambah sebelum tatasusunan bait. Tetapi apabila ini dihantar ke pelayan PHP untuk penerimaan, 4 bait pertama rentetan tidak boleh dipaparkan, dan walaupun selepas banyak kaedah penukaran, ia tidak boleh diambil semula. Kemudian, saya juga terfikir untuk menggunakan kaedah data Protobuf Walaupun PHP boleh menukar data, saya menyerah kerana saya tidak biasa dengan klien C#.

Masalah lain ialah sebenarnya, kebanyakan penyegerakan bingkai yang digunakan oleh pelayan permainan dalam talian lain menggunakan protokol UDP, yang turut dikongsi oleh TCP dan UDP. Tetapi jika ia hanya permainan dalam talian berbilang pemain yang kecil, adalah mungkin untuk menggunakan PHP sebagai pelayan dan komunikasi protokol TCP. Seterusnya, mari kembali kepada protokol tersuai pekerja dan isu melekit serta membongkar.

Protokol tersuai:

Workerman telah merangkum beberapa fungsi soket PHP (mengenai fungsi soket, jika anda sanggup bersusah payah, PHP juga boleh menulis fungsi pemindahan fail Alat), berdasarkan TCP, ia juga dilengkapi dengan beberapa protokol lapisan aplikasi, seperti Http, Websocket, Frame, dll. Ia juga menyimpan persimpangan untuk pengguna mentakrifkan protokol mereka sendiri. Mereka hanya perlu melaksanakan antara muka ProtocolInterface Berikut adalah pengenalan ringkas kepada beberapa kaedah yang perlu dilaksanakan untuk antara muka berikut.

1. Kaedah input

Dalam kaedah ini, paket data boleh dibongkar, diperiksa untuk panjang paket, ditapis, dan lain-lain sebelum diterima oleh pelayan. Mengembalikan 0 bermakna meletakkan paket data ke dalam penimbal hujung penerima dan terus menunggu Mengembalikan panjang yang ditentukan bermakna mengambil panjang dalam penimbal. Jika terdapat pengecualian, anda juga boleh mengembalikan palsu untuk menutup terus sambungan klien.

2. kaedah pengekodan

Kaedah ini adalah pemprosesan format paket data oleh pelayan sebelum menghantar paket data kepada klien, iaitu pengkapsulan paket. Bahagian depan dan belakang dipersetujui.

3. Kaedah penyahkod

Kaedah ini juga membongkar, iaitu mengambil panjang yang ditentukan dari penimbal ke tempat ia perlu diproses sebelum onMessage diterima, seperti Pelarasan logik dan sebagainya.

Fenomena pembongkaran paket melekit:

Oleh kerana TCP adalah berdasarkan aliran, dan kerana ia adalah lapisan pengangkutan, aplikasi dalam lapisan atas menggunakan soket (difahamkan sebagai antara muka) komunikasi, dia tidak tahu di mana permulaan dan penghujung paket data yang diluluskan. Hanya gam atau nyahhimpun hantaran mengikut set algoritma kesesakan TCP. Jadi secara literal, paket melekat adalah beberapa paket data yang dihantar bersama-sama Pada asalnya terdapat dua paket, tetapi pelanggan hanya menerima satu paket. Membongkar adalah untuk memisahkan paket data kepada beberapa paket Ia sepatutnya menerima satu paket data, tetapi hanya satu yang diterima. Oleh itu, jika ini tidak diselesaikan, seperti yang dinyatakan sebelum ini dan rentetan dihantar mengikut perjanjian, ralat mungkin dilaporkan semasa membongkar.

Penyelesaian untuk membongkar paket melekit:

1. Tambahkan pengepala pada panjang paket

<?php
/**
 * This file is part of game.
 *
 * Licensed under The MIT License
 * For full copyright and license information, please see the MIT-LICENSE.txt
 * Redistributions of files must retain the above copyright notice.
 *
 * @author    beiqiaosu
 * @link      http://www.zerofc.cn
 */
namespace Workerman\Protocols;

use Workerman\Connection\TcpConnection;

/**
 * Frame Protocol.
 */
class Game
{
    /**
     * Check the integrity of the package.
     *
     * @param string        $buffer
     * @param TcpConnection $connection
     * @return int
     */
    public static function input($buffer, TcpConnection $connection)
    {
        // 数据包前4个字节
        $bodyLen = intval(substr($buffer, 0 , 4));
        $totalLen = strlen($buffer);

        if ($totalLen < 4) {
            return 0;
        }

        if ($bodyLen <= 0) {
            return 0;
        }

        if ($bodyLen > strlen(substr($buffer, 4))) {
            return 0;
        }

        return $bodyLen + 4;
    }

    /**
     * Decode.
     *
     * @param string $buffer
     * @return string
     */
    public static function decode($buffer)
    {
        return substr($buffer, 4);
    }

    /**
     * Encode.
     *
     * @param string $buffer
     * @return string
     */
    public static function encode($buffer)
    {
        // 对数据包长度向左补零
        $bodyLen = strlen($buffer);
        $headerStr = str_pad($bodyLen, 4, 0, STR_PAD_LEFT);

        return $headerStr . $buffer;
    }
}

2. Pembahagian aksara khusus

<?php

namespace Workerman\Protocols;

use Workerman\Connection\ConnectionInterface;

/**
 * Text Protocol.
 */
class Tank
{
    /**
     * Check the integrity of the package.
     *
     * @param string        $buffer
     * @param ConnectionInterface $connection
     * @return int
     */
    public static function input($buffer, ConnectionInterface $connection)
    {
        
        if (isset($connection->maxPackageSize) && \strlen($buffer) >= $connection->maxPackageSize) {
            $connection->close();
            return 0;
        }
        
        $pos = \strpos($buffer, "#");
        
        if ($pos === false) {
            return 0;
        }
        
        // 返回当前包长
        return $pos + 1;
    }

    /**
     * Encode.
     *
     * @param string $buffer
     * @return string
     */
    public static function encode($buffer)
    {
        return $buffer . "#";
    }

    /**
     * Decode.
     *
     * @param string $buffer
     * @return string
     */
    public static function decode($buffer)
    {
        return \rtrim($buffer, "#");
    }
}

Ujian pembongkaran paket melekit:

Di sini kami hanya menunjukkan penyelesaian kepada pembahagian rentetan tertentu, kerana halaman utama di atas Masih terdapat masalah dengan 4 bait ditambah panjang paket. Iaitu, kali pertama paket dihantar tanpa panjang paket, simulasi melekat atau membongkar akan kekal dalam penimbal Anda boleh merujuk kepada kod di atas untuk demonstrasi berikut.

1. Pembukaan perkhidmatan dan sambungan pelanggan

2. 服务业务端代码

        数据包格式说明一下,字符串以逗号分割,数据包以 #分割,逗号分割第一组是业务方法,如 Login 表示登陆传递,Pos 表示坐标传递,后面带的就是对应方法需要的参数了。

<?php

use Workerman\Worker;

require_once __DIR__ . &#39;/vendor/autoload.php&#39;;

// #### create socket and listen 1234 port ####
$worker = new Worker(&#39;tank://0.0.0.0:1234&#39;);

// 4 processes
//$worker->count = 4;

$worker->onWorkerStart = function ($connection) {
    echo "游戏协议服务启动……";
};

// Emitted when new connection come
$worker->onConnect = function ($connection) {
    echo "New Connection\n";
    $connection->send("address: " . $connection->getRemoteIp() . " " . $connection->getRemotePort());
};

// Emitted when data received
$worker->onMessage = function ($connection, $data) use ($worker, $stream) {

    echo "接收的数据:" . $data . "\n";

    // 简单实现接口分发
    $arr = explode(",", $data);

    if (!is_array($arr) || !count($arr)) {
        $connection->close("数据格式错误", true);
    }

    $func = strtoupper($arr[0]);
    $client = $connection->getRemoteAddress();

    switch($func) {
        case "LOGIN":
            $sendData = "Login1";
            break;
        case "POS":
            $positionX = $arr[1] ?? 0;
            $positionY = $arr[2] ?? 0;
            $positionZ = $arr[3] ?? 0;

            $sendData = "POS,$client,$positionX,$positionY,$positionZ";
            break;
    }

    $connection->send($sendData);
};

// Emitted when connection is closed
$worker->onClose = function ($connection) {
    echo "Connection closed\n";
};


// 接收缓冲区溢出回调
$worker->onBufferFull = function ($connection) {
    echo "清理缓冲区吧";
};

Worker::runAll();

?>

3. 粘包测试

    只需要在客户端模拟两个数据包连在一起,但是要以 #分隔,看看服务端接收的时候是一几个包进行处理的。

4. 拆包测试

        拆包模拟只需要将一个数据包分成两次发送,看看服务端接收的时候能不能显示或者说能不能按约定好的格式正确显示。

更多编程相关知识,请访问:编程教学!!

Atas ialah kandungan terperinci Kongsi protokol tersuai Workerman untuk menyelesaikan masalah melekit dan membongkar. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Artikel ini dikembalikan pada:csdn.net. Jika ada pelanggaran, sila hubungi admin@php.cn Padam