一、什么是PHP Socket长连接
Socket是一个抽象层,它允许程序在网络环境中发送和接收数据。使用Socket时,程序将创建一个Socket对象,并用它来代表一个网络连接,可以发送数据和接收数据。
在PHP中,通过socket扩展可以很方便地使用Socket API,实现TCP/UDP协议的通信。其中,PHP Socket长连接指建立Socket连接后,长时间保持连接状态,能够发送多个请求和接收多个数据包,以及服务器在一段时间没有数据包传输时自动关闭连接。
二、PHP Socket长连接的优点
1、降低网络连接时延:长连接可以避免频繁地建立和断开网络连接,减少网络连接的时延。
2、减轻服务器资源压力:在每个连接间产生的握手协议、安全协议、重复发送的HTTP头必须消耗额外的带宽和享元模式,通过长连接可以减少网络开销,减轻服务器压力。
3、隐藏网络延迟:使用长连接可以减少网络开销,缓存请求在服务端的答复,避免一次没有完全填充的请求等待下一次完整的请求。从而有效地将网络延迟隐藏在网络背景中,提高用户体验。
三、PHP Socket长连接的应用
1、聊天室
我们可以使用PHP Socket长连接来实现聊天室功能。当用户在网页上输入聊天内容后,客户端将该内容以Socket长连接方式发送到后台,并放入消息队列中,服务端读取消息队列并再次发送给所有的聊天室用户。
//PHP长连接服务端代码示例
set_time_limit(0);
$sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_bind($sock, "0.0.0.0", 9999);
socket_listen($sock);
$clients = array($sock);
while (true) {
$read = $clients;
$write = null;
$err = null;
if (socket_select($read, $write, $err, 5) < 1) {
continue;
}
if (in_array($sock, $read)) {
$clients[] = $newsock = socket_accept($sock);
$header = PHP_EOL.'Welcome to chat-demo'.PHP_EOL.'Enter your name: ';
@socket_write($newsock, $header, strlen($header));
unset($read[ array_search( $sock, $read ) ]);
}
foreach ($read as $read_sock) {
$data = @socket_read($read_sock, 2048, PHP_NORMAL_READ);
if ($data === false) {
socket_close($read_sock);
$key_to_remove = array_search($read_sock, $clients, true);
unset($clients[$key_to_remove]);
break;
}
$data = trim($data);
if (!empty($data)) {
foreach ($clients as $send_sock) {
if ($send_sock == $sock || $send_sock == $read_sock){
continue;
}
@socket_write($send_sock, $data, strlen($data));
}
}
}
}
2、即时通讯
使用PHP Socket长连接可以实现即时通讯功能。比如,客户端可以将用户输入的文本消息以及相关的用户信息,通过Socket长连接方式提交到服务器端,服务器端收到后可以通过Websocket将消息推送给所有需要的在线用户。
//PHP长连接服务端代码示例
set_time_limit(0);
error_reporting(E_ALL & ~E_NOTICE);
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_bind($socket, '0.0.0.0', 9999);
socket_listen($socket);
$clients = array();
while (true) {
$read = $clients;
$read[] = $socket;
socket_select($read, $write, $except, null);
foreach ($read as $connect_socket) {
if ($connect_socket == $socket) {
$new_socket = socket_accept($connect_socket);
if ($new_socket) {
$clients[] = $new_socket;
}
} else {
$bytes = @socket_recv($connect_socket, $buffer, 1024, MSG_DONTWAIT);
if ($bytes) {
if (preg_match('/(.*): (.*)/', $buffer, $matches) == 1) {
$name = $matches[1];
$message = $matches[2];
$response = $name . ':' . $message . "\n";
} else {
$response = "robot: " . $buffer;
}
foreach ($clients as $client) {
@socket_write($client, $response, strlen($response));
}
}
if ($bytes === false) {
$key_to_remove = array_search($connect_socket, $clients, true);
unset($clients[$key_to_remove]);
socket_shutdown($connect_socket, 2);
socket_close($connect_socket);
}
}
}
}
3、定时器
PHP中没有自带的“计时器”功能,但使用Socket长连接可以轻松实现定时器功能。当需要创建一个任务,在指定的时间间隔内运行该任务时,可以在客户端启动Socket服务端程序,并在连接建立后开启一个周期性的定时器。这样,在一定时间后,服务端程序会主动调用客户端指定的函数。
//PHP长连接客户端代码示例
set_time_limit(0);
$host = 'localhost';
$port = 2345;
$conn = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
if (socket_connect($conn, $host, $port) === false) {
die("ERROR: " . socket_strerror(socket_last_error()) . "\n");
}
$next_call_time = time();
while (true) {
$time_left = $next_call_time - time();
if ($time_left > 0) {
usleep(1000000 * $time_left);
}
$next_call_time += 5;
socket_write($conn, 'time to do something ...');
}
四、总结
PHP Socket长连接可以有效地缓解网络延迟、减少服务器资源压力,具有很多实际应用场景。上述示例演示了使用PHP Socket长连接实现聊天室、即时通讯、定时器等功能的方法。如需使用PHP Socket长连接应用到您的项目中,可以参考以上示例代码,根据实际情况进行调整和扩展。