UDP协议无连接,不存在onConnect, onClose等事件,数据包发出后,对方是否收到也无法得知。UDP数据包有界,因而也不需要Parser::input检测边界。但是Parser::decode/encode也是有意义的:

decode可以把数据包转换成我们便于处理的格式。
encode可以把响应结果转成字节流格式。

实现UDP服务步骤

  1. 从beyodHandler继承,实现自己的Handler, 并重写onUdpMessage方法,如:

app/UdpHandler.php

<?php
namespace app;

use beyoio\UdpMessageEvent;

class UdpHandler extends \beyoio\Handler
{
    //当收到udp数据包时,此方法被调用。
    public function onUdpMessage(UdpMessageEvent $event)
    {
        $event->message; //客户发送的数据包内容,具体格式与对应Parser::decode有关
        $event->local; //服务器地址(ip:port)
        $event->peer; //对方地址(ip:port)
        $event->sender; //!!!当前listenner实例
        
        //处理完毕,向客户端发送数据
        //$flag含义参阅stream_socket_sendto函数
        //$raw发送前是否进行封包处理
        $this->sendto($event, $replyMessage, $flag, $raw);
    }
}
  1. 从beyodParser继承,实现decode/encode方法

Handler收到的消息 $event->message格式,与Parser::decode返回的类型相同。

  1. 修改配置文件:

config/main.php

'components'=>[
    'server'=>[
        'listenners'=>[
            'seny' =>[
                'listen' => 'udp://0.0.0.0:7512',
                'parser' => 'app\UdpParser',
                'handler' => 'app\UdpHandler'
            ]
        ]
    ]
]

使用udp/unix socket实现一个syslog服务器

Linux的syslog用于接受本机或其它节点的日志信息,它可以作为客户端以日志中继器的角色存在,也可以作为日志服务器,接收其它客户端的日志信息。

我们通过Linux系统命令或是syslog函数产生系统日志,本质上是通过unix socket和本机日志服务器通讯,可以用以下命令验证:

[root@sl ~]# netstat -npl | grep syslog
udp 0  0 0.0.0.0:514 0.0.0.0:*  1099/rsyslogd 

[root@sl ~]# strace  logger "hello syslog"

socket(PF_LOCAL, SOCK_DGRAM|SOCK_CLOEXEC, 0) = 1
connect(1, {sa_family=AF_LOCAL, sun_path="/dev/log"}, 110) = 0
sendto(1, "<13>Sep  8 20:55:22 root: hello "..., 38, MSG_NOSIGNAL, NULL, 0) = 38

[root@sl ~]# file /dev/log 
/dev/log: socket

可见,产生系统日志信息,就是向/dev/log套接字发送日志消息。SOCK_DGRAM指明了是用户数据报文协议(无连接,不可靠、固定最大长度)。

即syslog监听了两个套接字:
/dev/log unix domain socket, 基于UDP
0.0.0.0:514 UDP端口

unix:// 提供了在 UNIX 域中对套接字流连接的访问。udg:// 提供了替代的传输器以用户数据报协议(UDP)来访问 UNIX 域套接字。

也就是unix://是基于连接的(类似TCP), udg://基于无连接的udp传输协议。

要实现这样的一个服务器,我们首先要弄清楚其数据包格式。

http://www.ietf.org/rfc/rfc3164.txt

beyod自带了syslog服务器,消息格式定义在beyoioprotocolsyslogMessage中,一个syslog日志由以下字段组成:

facility

日志消息来源设备的标识, 值范围目前为0~23

说明
0kernel messages
1user-level messages
2mail system
3system daemons
4security/authorization messages
5messages generated internally by syslogd
6line printer subsystem
7network news subsystem
8UUCP subsystem
9clock daemon
10security/authorization messages
11FTP daemon
12NTP subsystem
13log audit
14log alert
15clock daemon (note 2)
16local use 0 (local0)
17local use 1 (local1)
18local use 2 (local2)
19local use 3 (local3)
20local use 4 (local4)
21local use 5 (local5)
22local use 6 (local6)
23local use 7 (local7)

severity

日志消息的严重程度

说明
0Emergency: system is unusable
1Alert: action must be taken immediately
2Critical: critical conditions
3Error: error conditions
4Warning: warning conditions
5Notice: normal but significant condition
6Informational: informational messages
7Debug: debug-level messages

time

日志消息产生的时间,使用GMT时间格式

host

日志来源主机名。

content

日志消息内容

典型的格式如:

<13>Oct 22 10:52:12 localhost hello, syslog 

<13> 指明了消息来源设备和严重程度,算法为:
serverity =  13 % 8 = 5
facility = 13-5 = 8

Oct 22 10:52:12 是消息产生的时间

localhost是消息来源主机名

hello, syslog 消息内容

服务器配置:
config/main.php

//...
'components'=>[
    'server'=>[
        //...
        'listenners'=>[
            'syslog-udg'=>[
                'listen' => 'udg://dev/mylog',
                'parser' => 'beyod\protocol\syslog\Parser'
            ],
            'syslog-udp'=>[
                'listen' => 'udp://0.0.0.0:514',
                'parser' => 'beyod\protocol\syslog\Parser'
            ]
        ]
    ]
]

需要自行编写Handler负责消息的最终存储或处理。