UDP数据包是有界的，不存在数据包边界确定的问题，但TCP数据包是无界的，如果使用的自定义格式数据包，就需要自定义协议，一般来说，自定义协议主要有两个工作：

#### Parser

完成数据包的解析

#### Handler

网络事件处理

以一个简单的echo server为例子说明整个过程：

1. 客户端连接后，即可发送文本内容，文本内容以CRLF结尾，服务器收到数据包后，向所有用户广播当前用户输入的内容。
2. 客户端发送字符串quit表示断开连接，服务器将通知事件发送给其它客户端。
3. 单个数据包如果超过64KB, 给客户端发送错误信息。

这部分代码已经包含在源码包中：

vendor/beyoio/beyoio/protocol/text/Parser.php中的内容：

    <?php
    namespace beyod\protocol\text;

    use beyod\Connection;

    class Parser extends \beyod\Parser
    {
        //数据包结尾定界符
        public $delimiter = "\r\n";

        public $max_packet_size = 65536; //设置数据包最大长度

        /**
         * @param string $buffer
         * @param Connection $connection 当前连接,对udp协议此值为null
         * @return int
         */
        public function input($buffer, $connection){

            //调用父类方法，检测数据包是否过大
            $len = parent::input($buffer, $connection);

            //如果数据中没有CRLF, 返回0，说明完整数据未收到，继续等待下一次数据段到达。
            $pos = strpos($buffer, $this->delimiter);
            if ($pos === false) {
                return 0;
            }

            //包含CRLF， 说明已经收到完整数据包，返回整个数据包的长度。
            return $pos + 2;
        }

        /**
        * 一旦收到数据包后，可以解码处理，因为对我们来说，是不必要关心的，所以清理后返回给handler
        */
        public function decode($buffer, $connection){
            return trim($buffer);
        }

        //向客户端发送文本时，自动追加边界符。
        public function encode($buffer, $connection){
            return $buffer.$this->delimiter;
        }
    }

vendor/beyoio/beyoio/protocol/text/Handler.php

    <?php

    namespace beyod\protocol\text;

    use Yii;
    use yii\base\Event;
    use beyod\IOEvent;
    use beyod\MessageEvent;
    use beyod\CloseEvent;
    use beyod\ErrorEvent;

    class Handler extends \beyoio\Handler
    {
        public $tag = null;

        public function init()
        {
            $this->tag = "Beyod Text Echo Server 1.0.1"
                ."\r\nServer:\t".Yii::$app->server->server_token
                ."\r\nServer Start At:\t".date('Y-m-d H:i:s')
                ."\r\nGPID:\t".Yii::$app->server->getGPID()
                . "\r\n";
        }

        /**
         * @param  IOEvent $event
         * {@inheritDoc}
         * @see \beyod\Handler::onConnect()
         */
        public function onConnect(IOEvent $event)
        {
            //连接后向当前客户端发送提示信息
            $resp = $this->tag."your connection id ".$event->sender."\r\nPlease input message, quit to disconnect:\r\n";
            $event->sender->send($resp);

            //向其它连接正常的客户端发送上线通知
            foreach($event->sender->listenner->connections as $id => $conn){
                if($id == $event->sender->id || $conn->isClosed() ) continue;
                $conn->send($conn." connected");
            }
        }

        /**
         * 当收到数据包时的处理
         * @param  MessageEvent $event
         */
        public function onMessage(MessageEvent $event)
        {
            //如果收到quit，向其它客户端发送上线通知
            if($event->message == 'quit'){
                foreach($event->sender->listenner->connections as $id => $conn){
                    if($id == $event->sender->id || $conn->isClosed() ) continue;
                    $conn->send($conn.' quit !');
                }

                //向当前客户端发送消息并断开连接
                return $event->sender->close('bye bye !');
            }

            //向其它客户端发送消息内容，实现消息群聊
            foreach($event->sender->listenner->connections as $id => $conn){
                if($id == $event->sender->id || $conn->isClosed() ) continue;
                $conn->send($conn.": ".$event->message);
            }

            //当前客户端的提示
            $event->sender->send("you said: ".$event->message);
        }

        //当连接断开时，向其它客户端发送下线通知
        public function onClose(CloseEvent $event){
            foreach($event->sender->listenner->connections as $id => $conn){
                if($id == $event->sender->id || $conn->isClosed() ) continue;
                $conn->send($conn." disconnected");
            }
        }

        //当数据包解析错误时，向客户端发送错误消息（并未断开连接）
        public function onBadPacket(ErrorEvent $event)
        {
            $event->sender->send($event->errstr);
        }
    }

config/main.php中的配置此服务功能：

    'components' =>[
        'server' => [
            //...
            'listeners' => [
                'text' => [
                        'class' => 'beyod\Listener',
                        'listen' => 'tcp://0.0.0.0:7723',
                        'parser' =>  'beyod\protocol\text\Parser',
                        'handler' => 'beyod\protocol\text\Handler'
                    ],
                //其它服务协议
            ]
        ]
    ]

同时打开多个telnet，连接至7723端口即可测试。