| 特性 | fsockopen 系 | socket_create 系 (擴展) |
| 函數族 | fsockopen, fputs, fgets, fclose | socket_create, socket_connect, socket_write, socket_read, socket_close |
| 穩定性 | 核心內置,成熟穩定 | 實驗性擴展,行為可能變更 |
| 多次通訊 | 長連接下二次通訊易卡死 | 長連接多次收發穩定 |
| 適用場景 | 單次請求響應、簡單協議 | 長連接、雙向通訊、複雜協議 |
實戰現象:雙請求場景
作者測試發現:
- 單次請求:兩種方式均正常
- 雙次請求(同一連接發送兩次、接收兩次):
- `fsockopen`:首次極快,第二次卡住數分鐘
- `socket_create` 系:兩次均毫秒級完成
推測 `fsockopen` 在長連接下緩衝區處理或 EOF 判斷存在缺陷。
封裝類:基於 socket 擴展的可復用客戶端
<?php
/**
* Socket 客戶端封裝類
* 支持 TCP 長連接、多次收發、調試輸出
*/
class SocketClient {
private $socket;
private $host;
private $port;
public $sendFlag = '>>>';
public $recvFlag = '<<<';
public $response = '';
public $debug = true;
public function __construct($hostname, $port) {
$this->host = $hostname;
$this->port = $port;
$address = gethostbyname($hostname);
$this->socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
$result = socket_connect($this->socket, $address, $port);
if ($this->debug) {
if ($result < 0) {
echo '連接失敗: ' . socket_strerror($result) . '<br>';
} else {
echo '連接成功<br>';
}
}
}
public function send($msg) {
socket_write($this->socket, $msg, strlen($msg));
$result = socket_read($this->socket, 1024);
$this->response = $result;
if ($this->debug) {
printf('<font color=#CCCCCC>%s %s</font><br>', $this->sendFlag, htmlspecialchars($msg));
printf('<font color=blue>%s %s</font><br>', $this->recvFlag, htmlspecialchars($result));
}
return $result;
}
public function close() {
socket_close($this->socket);
}
public function __destruct() {
if (is_resource($this->socket)) {
socket_close($this->socket);
}
}
}
// 使用示例
$client = new SocketClient('127.0.0.1', 9999);
$client->send('CMD1:HELLO');
$client->send('CMD2:WORLD');
$client->close();
?>
關鍵最佳實踐
- 錯誤處理:每個 socket 函數調用後檢查返回值,使用 `socket_last_error()` / `socket_strerror()` 診斷
- 超時控制:`socket_set_option($socket, SOL_SOCKET, SO_RCVTIMEO, ['sec'=>5, 'usec'=>0])`
- 完整讀取:`socket_read` 可能返回部分數據,需循環讀取直到協議定義的邊界(換行、長度前綴、特定標記)
- 非阻塞模式:高併發場景配合 `socket_select()` 實現 I/O 多路復用
- SSL/TLS:使用 `stream_socket_client()` + `stream_socket_enable_crypto()` 或 OpenSSL 擴展
總結
對於需要長連接、多次交互的 TCP 客戶端,**優先選擇 `socket_create` 系擴展**。`fsockopen` 適合簡單的一次性 HTTP/WHOIS 等短連接場景。生產環境請完善錯誤處理、超時、協議解析與資源清理機制。
- 上一篇文章: PHP 5 PDO 抽象層與 Oracle 數據庫實戰指南
- 下一篇文章: FPDF 純 PHP 生成 PDF 文件:從入門到中文支持實戰
Copyright ©
程式碼之家 All Rights Reserved