dispatch_func
最后更新于:2022-04-02 06:21:51
# dispatch\_func
[TOC]
设置`dispatch`函数,`swoole`底层了内置了`5`种`dispatch_mode`,如果仍然无法满足需求。可以使用编写`C++`函数或`PHP`函数,实现`dispatch`逻辑。使用方法:
~~~
$serv->set(array(
'dispatch_func' => 'my_dispatch_function',
));
~~~
* 设置`dispatch_func`后底层会自动忽略`dispatch_mode`配置
* `dispatch_func`对应的函数不存在,底层将抛出致命错误
* 如果需要`dispatch`一个超过`8K`的包,`dispatch_func`只能获取到`0-8180`字节的内容
> `dispatch_func`在`1.9.7`或更高版本可用
> `dispatch_func`在`1.9.18`或更高版本可以设置为`PHP`函数
> `dispatch_func`仅在`SWOOLE_PROCESS`模式下有效,`UDP/TCP/UnixSocket`均有效
## 编写PHP函数
由于`ZendVM`无法支持多线程环境,即使设置了多个`Reactor`线程,同一时间只能执行一个`dispatch_func`。因此底层在执行此`PHP`函数时会进行加锁操作,可能会存在锁的争抢问题。请勿在`dispatch_func`中执行任何阻塞操作,否则会导致`Reactor`线程组停止工作。
~~~
$serv->set(array(
'dispatch_func' => function ($serv, $fd, $type, $data) {
var_dump($fd, $type, $data);
return intval($data[0]);
},
));
~~~
* `$fd`为客户端连接的唯一标识符,可使用`Server::getClientInfo`获取连接信息
* `$type`数据的类型,`0`表示来自客户端的数据发送,`4`表示客户端连接关闭,`5`表示客户端连接建立
* `$data`数据内容,需要注意:如果启用了`Http`、`EOF`、`Length`等协议处理参数后,底层会进行包的拼接。但在`dispatch_func`函数中只能传入数据包的前`8K`内容,不能得到完整的包内容。
* 必须返回一个`[0-serv->worker_num)`的数字,表示数据包投递的目标工作进程ID
* 小于`0`或大于等于`serv->worker_num`为异常目标ID,`dispatch`的数据将会被丢弃
## 编写C++函数
在其他PHP扩展中,使用`swoole_add_function`注册长度函数到`Swoole`引擎中。
> C++函数调用时底层不会加锁,需要调用方自行保证线程安全性
~~~
int dispatch_function(swServer *serv, swConnection *conn, swEventData *data);
int dispatch_function(swServer *serv, swConnection *conn, swEventData *data)
{
printf("cpp, type=%d, size=%d\n", data->info.type, data->info.len);
return data->info.len % serv->worker_num;
}
int register_dispatch_function(swModule *module)
{
swoole_add_function("my_dispatch_function", (void *) dispatch_function);
}
~~~
* `dispatch`函数必须返回投递的目标worker进程id
* 返回的`worker_id`不得超过`serv->worker_num`,否则底层会抛出段错误
* 返回负数(`return -1`)表示丢弃此数据包
* `data`可以读取到事件的类型和长度
* `conn`是连接的信息,如果是`UDP`数据包,`conn`为`NULL`
';