在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进行优化。