webman 不支持单进程监听多协议端口,因底层 workerman 的 worker 实例创建时即绑定协议类型与端口,http、tcp、websocket 协议栈差异大、处理逻辑互斥,混用会导致覆盖或崩溃;正确方式是通过 config/process.php 配置多个独立进程,分别绑定不同协议和端口。

Webman 本身不支持单个进程监听多个不同协议的端口(比如同时跑 HTTP + TCP),必须拆成多个独立进程,每个进程绑定一种协议和端口。
为什么不能在一个进程里 listen 多个协议
Webman 底层基于 Workerman,而 Workerman 的 Worker 实例在创建时就绑定了协议类型(http、tcp、websocket 等)和端口。协议栈差异大:HTTP 要解析请求头、处理 Keep-Alive;TCP 是裸字节流;WebSocket 还要握手升级——这些逻辑无法共存于同一个连接处理器中。
强行混用会导致:
-
Worker::listen('http://0.0.0.0:8787')和Worker::listen('tcp://0.0.0.0:9501')写在同一段启动代码里,只会以最后一个生效,前面的被忽略 - 即使绕过限制注册了多个
Worker,也会因事件循环冲突或onMessage回调签名不兼容(Requestvsstring)而崩溃
正确做法:用多进程配置启动不同协议服务
Webman 的 config/process.php 支持定义多个独立进程,每个可指定不同协议、端口、handler 类。这是官方推荐且稳定的方式。
例如,同时运行:
- HTTP 服务在
8787 - TCP 自定义协议服务在
9501
只需在 config/process.php 中添加:
'http_server' => [
'handler' => \support\Server::class,
'listen' => 'http://0.0.0.0:8787',
'count' => cpu_count(),
],
'tcp_server' => [
'handler' => \process\TcpHandler::class,
'listen' => 'tcp://0.0.0.0:9501',
'count' => 1, // TCP 通常单进程足够
],
其中 \process\TcpHandler 需自行实现,结构类似:
namespace process;
use Workerman\Connection\TcpConnection;
class TcpHandler
{
public function onConnect(TcpConnection $connection) { /* ... */ }
public function onMessage(TcpConnection $connection, string $data) { /* ... */ }
public function onClose(TcpConnection $connection) { /* ... */ }
}
注意 config/server.php 里的端口只影响默认 HTTP 进程
很多人误以为改 config/server.php 中的 port 就能控制所有服务——其实它只用于初始化默认的 http_server 进程。其他协议进程完全由 config/process.php 独立定义,互不影响。
常见踩坑点:
- 忘记在
process.php中为新协议进程设置'count' => 1,导致 Workerman 尝试 fork 多个子进程跑 TCP,但多数自定义协议不需要多 worker(无状态连接池除外) - TCP handler 类没实现
onConnect/onClose,连接异常断开时资源未释放,长期运行后 fd 耗尽 - 防火墙或云服务器安全组只放行了
8787,忘了开9501,本地 telnet 能通,线上连不上
Docker 部署时要暴露所有端口
如果用官方 docker-compose.yml,默认只映射 8787。加 TCP 服务后,必须显式追加端口映射:
ports: - "8787:8787" - "9501:9501"
否则容器内虽监听成功,宿主机无法访问。另外,Docker 默认使用 bridge 网络,TCP 连接不会自动继承 host 网络的 DNS 或路由策略,跨容器调用时建议用 host.docker.internal 或固定 IP。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











