PHP连接TCP Socket服务器:前2次正常后socket_read失败挂起求助
PHP TCP Socket 读取阻塞问题排查建议
以下是针对你遇到的前两次操作正常、后续卡在socket_read的问题,给出的具体排查和解决方向:
检查
PHP_NORMAL_READ的行为:PHP_NORMAL_READ模式会持续阻塞直到读取到换行符(\n)或达到指定长度。如果服务器后续返回的响应没有包含换行符,socket_read会一直等待。可以尝试切换为PHP_BINARY_READ模式,或者确认服务器是否每次响应都正确添加了换行结束符。修复标准输入资源泄漏:你的代码每次循环都重新打开
php://stdin却没有关闭,可能导致资源耗尽。应该把$stdin = fopen('php://stdin', 'r');移到循环外部,循环内直接复用这个资源。添加读取超时机制:给socket设置读取超时,避免无限阻塞。可以通过
socket_set_option配置SO_RCVTIMEO参数:$timeout = ['sec' => 5, 'usec' => 0]; // 5秒超时 socket_set_option($sock, SOL_SOCKET, SO_RCVTIMEO, $timeout);验证请求结束符:
trim(fgets($stdin))会去掉输入的换行符,如果服务器需要特定的请求结束标记(比如换行),可能导致服务器无法识别完整请求,进而不返回响应。可以尝试在发送时补回换行:socket_write($sock, $msg . "\n", strlen($msg) + 1);提前检查连接状态:在每次读取前,用
socket_get_status确认连接是否正常,避免在连接已断开的情况下继续阻塞读取:$status = socket_get_status($sock); if ($status['eof']) { echo "连接已断开\n"; break; }
修改后的示例代码
<?php if (($sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) === false) { echo "socket_create() failed: reason: " . socket_strerror(socket_last_error()) . "\n"; exit; } if (socket_connect($sock, '127.0.0.1', 10000) === false) { echo "socket_connect() failed: reason: " . socket_strerror(socket_last_error()) . "\n"; exit; } // 设置5秒读取超时 $timeout = ['sec' => 5, 'usec' => 0]; socket_set_option($sock, SOL_SOCKET, SO_RCVTIMEO, $timeout); // 仅初始化一次标准输入资源 $stdin = fopen('php://stdin', 'r'); if (!$stdin) { echo "无法打开标准输入\n"; socket_close($sock); exit; } do { echo "请输入消息:"; $msg = trim(fgets($stdin)); // 补加换行符作为请求结束标记(根据服务器要求调整) $sendData = $msg . "\n"; if (socket_write($sock, $sendData, strlen($sendData)) === false) { echo "socket_write() failed: reason: " . socket_strerror(socket_last_error($sock)) . "\n"; break; } $status = socket_get_status($sock); if ($status['eof']) { echo "连接已断开\n"; break; } // 使用PHP_BINARY_READ模式读取,避免等待换行符 $buf = socket_read($sock, 2048, PHP_BINARY_READ); if ($buf === false) { $errorCode = socket_last_error($sock); if ($errorCode === SOCKET_ETIMEDOUT) { echo "读取超时,请检查服务器响应\n"; } else { echo "socket_read() failed: reason: " . socket_strerror($errorCode) . "\n"; } } else { echo "response: $buf\n"; } } while (true); // 关闭资源 fclose($stdin); socket_close($sock);
内容的提问来源于stack exchange,提问作者user19095524
相关产品推荐
相关产品推荐

