使用Workerman实现UNIX套接字服务端客户端连接异常求助
问题分析
- 客户端核心错误:误用
Workerman\Worker创建服务端实例,而非发起客户端连接 - 路径错误:客户端socket路径与服务端不匹配,且错误将资源名追加到socket路径中(服务端socket是
/var/www/html/sw/tmp.sock,客户端却指向/var/www/html/sw/app/Http/Controllers/tmp.sock/admin)
正确解决方案
方案1:使用Workerman异步TCP连接(HTTP协议,适合CLI环境)
Workerman提供AsyncTcpConnection用于客户端连接,由于服务端是HTTP接口,需构造标准HTTP请求报文。
public function index(Request $request) { $time_start = microtime(true); $results = []; try { $search = $request->input('search'); // 与服务端一致的Unix socket路径 $socketPath = 'unix://' . base_path('tmp.sock'); foreach ($search as $resource) { // 创建异步TCP连接,指定服务端socket $connection = new \Workerman\Connection\AsyncTcpConnection($socketPath); // 构造HTTP GET请求,对应服务端的/{name}路由 $connection->send("GET /{$resource} HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n"); // 处理服务端返回结果 $connection->onMessage = function ($conn, $data) use (&$results, $resource) { // 拆分HTTP响应头与响应体 list($header, $body) = explode("\r\n\r\n", $data, 2); $results[$resource] = json_decode($body, true) ?: $body; $conn->close(); }; // 发起连接 $connection->connect(); } // 启动Workerman事件循环,等待所有请求处理完成(仅适合CLI环境) \Workerman\Worker::runAll(); } catch (\Exception $e) { return response($e->getMessage(), 500); } $time_end = microtime(true); $execution_time = ($time_end - $time_start); return view('search', compact('results', 'execution_time')); }
注意:该方案依赖Workerman事件循环,会阻塞进程,不适合Web请求环境,仅用于CLI脚本场景。
方案2:使用Guzzle同步HTTP客户端(适合Web环境)
服务端基于HTTP协议,Guzzle支持直接连接Unix套接字,是Web环境下的最优选择。
- 先安装Guzzle:
composer require guzzlehttp/guzzle
- 客户端代码:
use GuzzleHttp\Client; public function index(Request $request) { $time_start = microtime(true); $results = []; try { $search = $request->input('search'); // 服务端Unix socket的绝对路径 $socketPath = base_path('tmp.sock'); $client = new Client([ 'base_uri' => 'http://localhost', 'curl' => [ // 指定Unix套接字路径 CURLOPT_UNIX_SOCKET_PATH => $socketPath, ], ]); foreach ($search as $resource) { // 发起GET请求,对应服务端的/{name}路由 $response = $client->get("/{$resource}"); $results[$resource] = json_decode($response->getBody(), true) ?: $response->getBody()->getContents(); } } catch (\Exception $e) { return response($e->getMessage(), 500); } $time_end = microtime(true); $execution_time = ($time_end - $time_start); return view('search', compact('results', 'execution_time')); }
关键注意事项
- 路径一致性:客户端必须使用与服务端完全相同的socket路径,推荐用
base_path('tmp.sock')获取项目根目录下的socket文件,避免相对路径错误。 - 协议匹配:服务端是HTTP协议,客户端必须发送符合HTTP规范的请求,不能直接传输原始数据。
- 环境适配:Web请求环境优先选择Guzzle同步方案,避免阻塞Web进程;CLI脚本可使用Workerman异步方案。
内容的提问来源于stack exchange,提问作者Jake
相关产品推荐
相关产品推荐

