ThinkChat🤖让你学习和工作更高效,注册即送10W Token,即刻开启你的AI之旅 广告
# 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`