amp\socket\server 不是“开箱即用”的 tcp 服务器,因其仅封装底层 socket、不处理连接生命周期、协议解析或请求分发,accept 后需手动 read/write,否则连接卡住;udp 模式下 api 完全不同,须用 datagram::receive() 而非 read();资源必须显式 close() 防 fd 泄露;且依赖正确运行的 event loop。

为什么 Amp\Socket\Server 不是“开箱即用”的 TCP 服务器
Amp\Socket\Server 是底层 socket 封装,它不自动处理连接生命周期、协议解析或并发请求分发。直接 new Amp\Socket\Server 后只 listen,但 accept 后的 $socket 是裸 stream,没做任何读写封装,不手动调用 read() / write() 就卡住——这不是 bug,是设计意图:它只管“谁连上来了”,不管“怎么跟对方说话”。
- 常见错误现象:
Connection reset by peer或客户端收不到响应,本质是服务端 accept 后没 read 数据、也没 write 回复 - 典型使用场景:需要自定义二进制协议、透传代理、低延迟设备通信等,而非 HTTP/JSON API
- 参数差异:
new Amp\Socket\Server('0.0.0.0:8000')中地址支持udp://前缀(如udp://0.0.0.0:8000),但 UDP 模式下accept()返回的是Datagram对象,不是Socket,API 完全不同
UDP 模式下必须用 Datagram::receive() 而非 Socket::read()
很多人照搬 TCP 示例,在 UDP 场景下调用 $socket->read(),结果抛出 TypeError: Cannot read from datagram socket。Amp 把 TCP 和 UDP 的抽象层彻底分开:UDP 不是“连接”,没有流式读取概念,每次收发都是独立报文。
- 正确做法:对
Datagram实例调用receive()获取array{string $data, string $remoteAddress},再用send($data, $remoteAddress)回复 - 性能影响:UDP 无连接握手开销,但需自行处理丢包、乱序;
receive()默认阻塞,但在 Amp 协程中实际是非阻塞的,无需额外 await - 容易踩的坑:用
bindTo()绑定本地地址时,UDP 必须显式指定0.0.0.0(不能省略),否则可能监听失败且无明确错误提示
协程内处理连接时别漏掉 try/catch 和资源清理
每个 accept() 返回的 Socket 或 Datagram 都是独立资源,协程退出时不显式 close(),连接会一直 hang 在 ESTABLISHED 状态,最终耗尽文件描述符。
- 必须包裹在
try/finally中:finally { $socket->close(); } - 常见错误现象:服务跑几小时后新连接拒绝,
lsof -i :8000 | wc -l显示数百个 CLOSE_WAIT 或 ESTABLISHED,说明 socket 没释放 - 注意
read()可能返回null(对端关闭)或空字符串(TCP 空包),此时应主动break并 close,而不是继续循环 - UDP 无连接状态,
close()不是必须的,但Datagram实例仍建议在协程结束前调用close()防止 fd 泄露
启动服务前确认 event loop 已运行且未被阻塞
Amp 所有异步操作依赖全局 event loop,如果在 Amp\Loop::run() 外调用 Server::start(),或者 loop 内部执行了同步阻塞代码(如 sleep()、file_get_contents()),整个服务就卡死——看起来像“没启动”,其实是 loop 停摆了。
- 正确启动模式:
Amp\Loop::run(fn() => $server->start(...)),不要在 loop 外 new Server 后再塞进去 - 兼容性影响:PHP 8.1+ 下若用
pcntl_fork()启动多 worker,Amp loop 不支持 fork 后复用,必须每个子进程单独 run loop - 调试技巧:加一句
echo "loop running\n";在Loop::run()回调开头,确认是否真的进了 loop;用strace -p $(pgrep php)看是否卡在epoll_wait
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











