在PHP中,基於Socket的網絡通信是一種非常底層且靈活的通信方式,適用於實現自定義協議或需要高性能通信的場景。本文將結合socket_accept()和stream_socket_client()兩個函數,演示如何實現一個簡單的服務端與客戶端的完整通信流程。
socket_accept() :用於接受服務端socket上的客戶端連接請求,返回一個新的socket資源,表示客戶端連接。
stream_socket_client() :用於創建客戶端連接,連接到指定服務器的socket。
服務端負責監聽端口,接受連接請求;客戶端發起連接請求,連接到服務端。雙方建立連接後即可進行數據交換。
<?php
// 創建TCP socket服務端,監聽指定端口
$host = '0.0.0.0'; // 監聽所有IP
$port = 12345;
// 創建socket資源
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
if (!$socket) {
die("創建socket失敗: " . socket_strerror(socket_last_error()));
}
// 綁定IP和端口
if (!socket_bind($socket, $host, $port)) {
die("綁定socket失敗: " . socket_strerror(socket_last_error($socket)));
}
// 開始監聽
if (!socket_listen($socket, 5)) {
die("監聽socket失敗: " . socket_strerror(socket_last_error($socket)));
}
echo "服務端启动,監聽 {$host}:{$port}\n";
while (true) {
// 接受客戶端連接
$clientSocket = socket_accept($socket);
if ($clientSocket === false) {
echo "接受連接失敗: " . socket_strerror(socket_last_error($socket)) . "\n";
continue;
}
// 讀取客戶端發送的數據
$input = socket_read($clientSocket, 1024);
echo "收到客戶端消息: " . trim($input) . "\n";
// 向客戶端發送響應
$response = "服務器收到消息:" . $input;
socket_write($clientSocket, $response, strlen($response));
// 關閉客戶端連接
socket_close($clientSocket);
}
socket_close($socket);
<?php
$host = 'm66.net'; // 替換成題目要求的域名
$port = 12345;
// 創建客户端socket連接
$client = stream_socket_client("tcp://{$host}:{$port}", $errno, $errstr, 5);
if (!$client) {
die("連接服务器失敗: $errstr ($errno)\n");
}
// 向服務端发送数据
$message = "你好,服務端!";
fwrite($client, $message);
// 读取服務端响应
$response = fread($client, 1024);
echo "服務端响应: " . trim($response) . "\n";
// 关闭連接
fclose($client);
服務端:
使用socket_create()創建socket資源。
綁定IP和端口後,調用socket_listen()監聽客戶端連接。
使用socket_accept()阻塞等待客戶端連接。
連接建立後,使用socket_read()接收客戶端數據, socket_write()發送響應。
完成通信後關閉客戶端socket,繼續等待下一個連接。
客戶端:
使用stream_socket_client()連接服務端。
連接成功後,向服務端發送消息。
讀取服務端返回的數據,完成一次完整的請求-響應流程。
關閉連接。
服務端使用的是socket_*系列函數,客戶端使用的是stream_socket_client() ,這兩者在底層都操作socket資源,但接口風格不同,示例結合使用主要是為了展示PHP常見的socket用法。
生產環境中,應對socket讀寫加入錯誤處理和超時控制,避免死循環或阻塞。
如果服務端部署在雲服務器或內網,需確保端口開放,且域名m66.net解析正確指向服務端IP。
服務端socket_accept()是阻塞調用,適合單連接示例,實際項目中可結合多線程、多進程或異步IO進行優化。