如何在PHP中实现长连接通信?

1. 什么是长连接通信

在 HTTP 请求中,客户端和服务器之间的通信通常是短暂的,也就是说一旦服务器返回了相应的结果,连接就会被关闭。这种方式在某些场景下并不适用,比如在线聊天,游戏等需要持续通信的场景。长连接就是一种可以保持持续通信的方式。长连接也叫做 HTTP 长轮询 或者 Comet 技术。

2. PHP 中的长连接实现

2.1 使用 socket 实现

PHP 中可以使用 socket 函数库来实现长连接。使用 socket 函数库可以建立一个服务器端和一个客户端之间的独立连接,当有数据传入或者传出时,连接将会被激活。

// 建立服务器端

$server = 'localhost';

$port = 9999;

$max_clients = 10;

if(!($sock = socket_create(AF_INET, SOCK_STREAM, 0))){

$errorcode = socket_last_error();

$errormsg = socket_strerror($errorcode);

die("Couldn't create socket: [$errorcode] $errormsg \n");

}

echo "Socket created";

if(!socket_bind($sock, $server , $port)){

$errorcode = socket_last_error();

$errormsg = socket_strerror($errorcode);

die("Could not bind socket : [$errorcode] $errormsg \n");

}

echo "Socket bind successful";

if(!socket_listen($sock , $max_clients)){

$errorcode = socket_last_error();

$errormsg = socket_strerror($errorcode);

die("Could not listen on socket : [$errorcode] $errormsg \n");

}

echo "Socket listen successful";

while (true) {

$client = socket_accept($sock);

// 在这里进行数据的交互操作

socket_close($client);

}

socket_close($sock);

上面的代码创建了一个服务器并且监听了端口号为 9999 的连接,等待客户端的连接请求。一旦有连接建立成功,服务器将会创建一个新的 socket 连接和客户端进行通信。当通信结束后,服务器将会关闭这个连接。

2.2 使用 Websocket 实现

WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。WebSocket 不同于 HTTP,其通信双方可以在任何时候主动发送或接收数据,并且没有 HTTP 请求头的限制。而且 WebSocket 还有传输层加密和压缩等功能。

PHP中可用使用开源库 Ratchet 来实现 WebSocket。Ratchet 能够提供底层的通讯支持,同时还可以和 PHP 应用程序进行集成。

use Ratchet\MessageComponentInterface;

use Ratchet\ConnectionInterface;

require dirname(__DIR__) . '/vendor/autoload.php';

class Chat implements MessageComponentInterface {

protected $clients;

public function __construct() {

$this->clients = new \SplObjectStorage;

}

public function onOpen(ConnectionInterface $conn) {

$this->clients->attach($conn);

echo "New connection! ({$conn->resourceId})\n";

}

public function onMessage(ConnectionInterface $from, $msg) {

foreach ($this->clients as $client) {

if ($client !== $from) {

$client->send($msg);

}

}

}

public function onClose(ConnectionInterface $conn) {

$this->clients->detach($conn);

echo "Connection {$conn->resourceId} has disconnected\n";

}

public function onError(ConnectionInterface $conn, \Exception $e) {

echo "An error has occurred: {$e->getMessage()}\n";

$conn->close();

}

}

$server = IoServer::factory(

new HttpServer(

new WsServer(

new Chat()

)

),

8080

);

$server->run();

上面的代码实现了一个简单的聊天室应用。它可以让使用者在不同的客户端中进行聊天,所有的消息都将在客户端之间实时进行交互。

2.3 使用 Swoole 实现

Swoole 是一个为 PHP 提供的高性能网络框架,可以轻易地实现高并发、异步任务,以及长连接等需求。

$server = new Swoole\WebSocket\Server("0.0.0.0", 9501);

$server->on("open", function (Swoole\WebSocket\Server $server, $request) {

echo "server: handshake success with fd{$request->fd}\n";

});

$server->on("message", function (Swoole\WebSocket\Server $server, $frame) {

echo "receive from {$frame->fd}: {$frame->data}, opcode: {$frame->opcode}, fin: {$frame->finish}\n";

$server->push($frame->fd, "this is server");

});

$server->on("close", function (Swoole\WebSocket\Server $server, $fd) {

echo "client {$fd} closed\n";

});

$server->start();

上面的代码实现了一个简单的 WebSocket 服务,客户端只需要建立一个与服务端的长连接,就可以向服务端发送任意的消息,并接收到服务端的响应。

3. 小结

在本文中,我们介绍了长连接通信的概念,以及如何在 PHP 中使用 socket、WebSocket 以及 Swoole 等库来实现长连接。

后端开发标签