目录
- 什么是 Socket?
- 为什么要在 PHP 中使用 Socket?
- PHP 中的 Socket 函数(传统方式)
- 一个简单的 TCP 服务器/客户端示例
- 一个简单的 UDP 服务器/客户端示例
- 现代 PHP 的替代方案:Swoole, ReactPHP
- Socket 的应用场景
- 总结与最佳实践
什么是 Socket?
你可以把 Socket(套接字) 想象成一个通信的“插座”或“端点”。

-
类比:想象一下电话系统,你的应用程序就像一部电话机,IP 地址是电话号码,端口号是分机号,Socket 就是电话机上的听筒和话筒的组合,它建立了连接,让你能够通过电话线(网络)与其他电话机(另一台计算机上的应用程序)进行双向通话。
-
技术定义:Socket 是操作系统提供给应用程序编程的接口(API),它允许应用程序发送或接收数据,就像打开一个文件进行读写一样,它隐藏了底层的复杂网络协议(如 TCP/IP)。
-
关键概念:
- IP 地址:网络中设备的唯一地址,如
0.0.1(本机) 或8.8.8(Google DNS)。 - 端口号:应用程序在设备上的唯一标识,一个 IP 地址可以同时运行多个网络服务,每个服务使用一个不同的端口号,HTTP 默认使用 80 端口,HTTPS 默认使用 443 端口。
- 协议:数据传输的规则,主要有两种:
- TCP (Transmission Control Protocol):面向连接、可靠的协议,数据传输前需要先建立连接(三次握手),保证数据无差错、不丢失、不重复且按序到达,就像打电话,必须先接通才能说话。
- UDP (User Datagram Protocol):无连接、不可靠的协议,不保证数据包的顺序或是否到达,但开销小、速度快,就像寄平信,你寄出去了,但信件是否收到、是否按顺序收到,都无法保证。
- IP 地址:网络中设备的唯一地址,如
为什么要在 PHP 中使用 Socket?
PHP 主要以其 Web 开发能力而闻名(通过 Apache/Nginx + PHP-FPM),为什么还需要直接使用 Socket 呢?

- 实现自定义协议:当 HTTP/HTTPS 无法满足你的需求时,你需要一个持续连接、低延迟的通信,而不是 HTTP 的“请求-响应”模式。
- 构建实时应用:如在线聊天室、实时游戏、股票行情推送等,HTTP 是无状态的,服务器无法主动向客户端推送信息,而 Socket 可以保持长连接,实现服务器到客户端的主动消息推送。
- 与现有服务通信:很多网络服务(如 SMTP 邮件服务、FTP 文件传输服务、Redis、Memcached、游戏服务器等)都使用自己的 TCP/UDP 协议,你可以用 PHP Socket 客户端去模拟这些协议,与这些服务直接交互。
- 开发高性能网络服务:虽然 PHP-FPM 处理 HTTP 请求很高效,但如果你想开发一个独立的服务(比如一个 TCP 端口监听服务),Socket 是基础。
- 学习和理解网络编程:这是深入理解计算机网络和操作系统原理的最佳途径。
PHP 中的 Socket 函数(传统方式)
PHP 提供了一套强大的 Socket 函数,它们直接映射到了底层的 C 语言 Socket API。
基本流程(TCP 服务器为例):
socket_create(): 创建一个 Socket 资源。socket_bind(): 将 Socket 绑定到一个 IP 地址和端口上。socket_listen(): 开始监听来自客户端的连接请求。socket_accept(): 阻塞等待,接受一个客户端连接,并返回一个新的 Socket 资源用于与该客户端通信。socket_read(): 从已连接的 Socket 中读取数据。socket_write(): 向已连接的 Socket 中写入数据。socket_close(): 关闭 Socket。
关键函数列表:
| 函数名 | 作用 |
|---|---|
socket_create() |
创建一个 Socket |
socket_bind() |
绑定 IP 和端口 |
socket_listen() |
开始监听连接 |
socket_accept() |
接受一个连接 |
socket_connect() |
客户端连接到服务器 |
socket_read() |
从 Socket 读取数据 |
socket_write() / socket_send() |
向 Socket 写入数据 |
socket_close() |
关闭 Socket |
socket_last_error() / socket_strerror() |
获取和解释 Socket 错误 |
一个简单的 TCP 服务器/客户端示例
这个例子将创建一个回显服务器:客户端发送什么消息,服务器就原样返回什么消息。

TCP 服务器 (server.php)
<?php
// 设置一个超时时间,防止脚本无限期运行
set_time_limit(0);
// IP 和端口
$host = '127.0.0.1';
$port = 9999;
// 1. 创建一个 TCP Socket (AF_INET 是 IPv4, SOCK_STREAM 是 TCP)
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
// 检查是否创建成功
if ($socket === false) {
echo "socket_create() 失败: 原因: " . socket_strerror(socket_last_error()) . "\n";
exit();
}
// 2. 绑定 IP 和端口到 Socket
if (socket_bind($socket, $host, $port) === false) {
echo "socket_bind() 失败: 原因: " . socket_strerror(socket_last_error($socket)) . "\n";
exit();
}
// 3. 开始监听连接
if (socket_listen($socket, 5) === false) {
echo "socket_listen() 失败: 原因: " . socket_strerror(socket_last_error($socket)) . "\n";
exit();
}
echo "服务器启动,监听在 $host:$port\n";
// 4. 进入一个无限循环,等待客户端连接
while (true) {
// 接受一个客户端连接
$clientSocket = socket_accept($socket);
if ($clientSocket === false) {
echo "socket_accept() 失败: 原因: " . socket_strerror(socket_last_error($socket)) . "\n";
continue; // 继续等待下一个连接
}
// 获取客户端信息
$clientInfo = socket_getpeername($clientSocket, $clientIp, $clientPort);
echo "新的客户端连接: $clientIp:$clientPort\n";
// 与客户端通信
while (true) {
// 从客户端读取数据
$input = socket_read($clientSocket, 1024);
if ($input === false) {
echo "socket_read() 失败\n";
break;
}
// 如果客户端关闭了连接 (返回空字符串)
if ($input === "") {
echo "客户端 $clientIp:$clientPort 断开连接\n";
break;
}
// 去除末尾的换行符
$input = trim($input);
echo "收到来自 $clientIp:$clientPort 的消息: '$input'\n";
// 将消息转换为大写并发送回客户端
$output = strtoupper($input) . "\n";
socket_write($clientSocket, $output, strlen($output));
}
// 5. 关闭与当前客户端的连接
socket_close($clientSocket);
}
// 6. 关闭服务器 Socket (通常上面的 while(true) 不会退出)
socket_close($socket);
?>
TCP 客户端 (client.php)
<?php
$host = '127.0.0.1';
$port = 9999;
// 1. 创建一个客户端 Socket
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
if ($socket === false) {
echo "socket_create() 失败: 原因: " . socket_strerror(socket_last_error()) . "\n";
exit();
}
// 2. 连接到服务器
if (socket_connect($socket, $host, $port) === false) {
echo "socket_connect() 失败: 原因: " . socket_strerror(socket_last_error($socket)) . "\n";
exit();
}
echo "已连接到服务器 $host:$port\n";
// 要发送的消息列表
$messages = [
"hello world",
"this is a test",
"quit"
];
foreach ($messages as $msg) {
// 发送消息到服务器
if (socket_write($socket, $msg . "\ 