Maison > Article > développement back-end > Étude de cas de la combinaison du framework ThinkPHP5.1 et du framework Workerman's GatewayWorker
GatewayWorker est un framework de connexion longue TCP déployable distribué développé sur la base de Workerman. Il est spécialement utilisé pour développer rapidement des applications de connexion longue TCP, telles que les serveurs push d'applications, les serveurs de messagerie instantanée, les serveurs de jeux, l'Internet des objets et les maisons intelligentes. Attendez
Adresse du document : http://www.workerman.net/gatewaydoc/
1. Testez la DÉMO officielle (version Windows)
1. Téléchargez la démo (Obtenez-la dans les commentaires ci-dessous )
2. Décompressez-la n'importe où, la voici :
D:\phpStudy\PHPTutorial\WWW\GatewayWorker
3. Entrez dans le répertoire GatewayWorker
4. Double-cliquez sur start_for_win.bat pour démarrer. (Si une erreur se produit, veuillez vous référer à la définition de la variable d'environnement php ici), l'effet est le suivant
5. Exécutez telnet 127.0.0.1 8282 dans la fenêtre de ligne de commande , entrez n'importe quel caractère pour discuter (pas pour les tests locaux, veuillez remplacer 127.0.0.1 par l'adresse IP réelle).
PS : Ce qui précède indique que le test de connexion TCP est réussi
2 Modifier le websocket de test
1. Besoin de modifier start_gateway.php spécifie le protocole websocket, comme ceci$gateway = new Gateway(websocket://0.0.0.0:7272);2. Redémarrez start_for_win.bat3. Résumé : Il vous suffit de modifier le protocole et le port d'un fichier (start_gateway.php), et aucune autre modification n'est nécessaire. 3. Intégration avec le framework ThinkPHP5.1
(1) Le serveur envoie activement des messages au client
Principe : 1. Le projet de framework TP5.1 et le déploiement indépendant de GatewayWorker n'interfèrent pas l'un avec l'autre
2. Toute la logique métier est demandée depuis la page du site Web (websocket connecté) vers TP5. via post/get.1 Terminé dans le contrôleur du framework
3 GatewayWorker n'accepte pas les données du client, c'est-à-dire que GatewayWorker ne traite aucune logique métier et GatewayWorker n'est utilisé que comme un seul. façon canal push
4 Uniquement lorsque le framework TP5.1 doit pousser activement les données vers le navigateur, l'API de la passerelle (GatewayClient) est appelée dans le framework TP5.1 pour terminer le push
Étapes spécifiques de mise en œuvre
1. La page du site Web établit une connexion websocket avec le GatewayWorker2. Lorsque le GatewayWorker constate qu'une page initie une connexion, il envoie le client_id de la connexion correspondante à la page du site
Contenu php de l'événementws = new WebSocket("ws://127.0.0.1:7272");
contenu index.html
public static function onConnect($client_id) { $resData = [ 'type' => 'init', 'client_id' => $client_id, 'msg' => 'connect is success' // 初始化房间信息 ]; Gateway::sendToClient($client_id, json_encode($resData)); }
3. La page du site Web déclenche une requête ajax après avoir reçu le client_id (index/chat_room/ bind) envoie le client_id au backend TP5.0, méthode de liaison
4. Après le backend reçoit le client_id, utilisez GatewayClient pour appeler Gateway::bindUid($client_id, $uid) pour comparer le client_id avec la liaison uid actuelle (ID utilisateur ou identifiant unique du client). S'il existe une fonction d'envoi de groupe ou de groupe, vous pouvez également utiliser Gateway::joinGroup($client_id, $group_id) pour ajouter le client_id au groupe correspondantGatewayWorker的websocket连接 GatewayWorker的websocket连接
Valeur renvoyée après une connexion réussie
/* * 用户登录后初始化以及绑定client_id */ public function bind() { // 设置GatewayWorker服务的Register服务ip和端口,请根据实际情况改成实际值 Gateway::$registerAddress = '127.0.0.1:1238'; $uid = $this->userId; $group_id = $this->groupId; $client_id = request()->param('client_id'); // client_id与uid绑定 Gateway::bindUid($client_id, $uid); // 加入某个群组(可调用多次加入多个群组) Gateway::joinGroup($client_id, $group_id); }
PS : La valeur de retour ci-dessus correspond aux données json renvoyées après la connexion réussie du service GatewayWorker
5 Toutes les requêtes initiées par la page sont directement publiées/accédées au. Framework mvc pour un traitement unifié, y compris l'envoi de messages
Envoyer des messages via sendMessage (le serveur envoie activement des messages au client)6. certain uid ou un certain groupe pendant le traitement commercial, appelez directement l'interface GatewayClient Gateway::sendToUid Gateway::sendToGroup et attendez l'envoi
Accédez à l'opération sendMessage via le navigateur, testez les résultats
// mvc后端发消息 利用GatewayClient发送 Events.php public function sendMessage() { // stream_socket_client(): unable to connect to tcp://127.0.0.1:1236 $uid = $this->userId; $group = $this->groupId; $message = json_encode([ 'type'=>'say', 'msg'=>'Hello ThinkPHP5' ]); // 设置GatewayWorker服务的Register服务ip和端口,请根据实际情况改成实际值 Gateway::$registerAddress = '127.0.0.1:1238'; // 向任意uid的网站页面发送数据 Gateway::sendToUid($uid, $message); // 向任意群组的网站页面发送数据,如果开启,则会向页面发送两条一样的消息 //Gateway::sendToGroup($group, $message); }
PS : les messages TP5.0 ci-dessus sont envoyés via GatewayClientGateway et n'ont aucune relation directe avec le service GatewayWorker
Ce qui précède est le serveur qui envoie activement des messages au client
Notez la distinction : 1 , Le serveur envoie activement des messages au client 2. Le client envoie des messages au client(2) Le client envoie des messages au client
Pour modifier l'envoi et la réception de messages client à client, modifiez le fichier Events.php de GatewayWorker ci-dessous (les développeurs doivent uniquement prêter attention à ce fichier)Page du salon de discussion index.html
public static function onConnect($client_id) { $resData = [ 'type' => 'init', 'client_id' => $client_id, 'msg' => 'connect is success' // 初始化房间信息 ]; Gateway::sendToClient($client_id, json_encode($resData)); } /** * 当客户端发来消息时触发 * @param int $client_id 连接id * @param mixed $message 具体消息 */ public static function onMessage($client_id, $message) { // 服务端console输出 //echo "msg : $message \r\n"; // 解析数据 $resData = json_decode($message, true); $type = $resData['type']; $roomId = $resData['roomId']; $userId = $resData['userId']; // 未登录,则传递一个随机 $userName = $resData['userName']; // 未登录,则传递一个随机 $content = isset($resData['content']) ? $resData['content'] : 'default content'; //将时间全部置为服务器时间 $serverTime = date('Y-m-d H:i:s', time()); switch ($type) { case 'join': // 用户进入直播间 //将客户端加入到某一直播间 Gateway::joinGroup($client_id, $roomId); $resData = [ 'type' => 'join', 'roomId' => $roomId, 'userName' => $userName, 'msg' => "enters the Room", // 发送给客户端的消息,而不是聊天发送的内容 'joinTime' => $serverTime // 加入时间 ]; // 广播给直播间内所有人,谁?什么时候?加入了那个房间? Gateway::sendToGroup($roomId, json_encode($resData)); break; case 'say': // 用户发表评论 $resData = [ 'type' => 'say', 'roomId' => $roomId, 'userName' => $userName, 'content' => $content, 'commentTime' => $serverTime // 发表评论时间 ]; // 广播给直播间内所有人 Gateway::sendToGroup($roomId, json_encode($resData)); break; case 'pong': break; // 接收心跳 default: //Gateway::sendToAll($client_id,$json_encode($resData)); break; } }
Redémarrez le serviceRésultats des tests
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>GatewayWorker的websocket连接</title> </head> <body> <h1>GatewayWorker的websocket连接</h1> <div> websocket send content:<input type="text" style="height: 50px; width: 100%;" name="data" id="data"> <p></p> <button id="submit" onclick="sub()">send info</button> <p></p> <div id="output"></div> </div> <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script> <script src="https://cdn.bootcss.com/reconnecting-websocket/1.0.0/reconnecting-websocket.min.js"></script> <script language="javascript" type="text/javascript"> var wsUri = "ws://notes.env:7272/"; var outputContent; var roomId = 'L06777'; var userId = 4840043; var userName = 'Tinywan' + Math.random(); // 把当新链接的客户端加入到当前直播间,消息类型:{"type":"join","roomId":"1002","userId":"88","userName":"userName"} var joinContent = { "type": "join", "roomId": roomId, "userId": userId, "userName": userName }; // 初始化页面操作 function init() { outputContent = document.getElementById("output"); initWebSocket(); } function initWebSocket() { websocket = new ReconnectingWebSocket(wsUri); websocket.onopen = function (evt) { onOpen(evt) }; websocket.onclose = function (evt) { onClose(evt) }; websocket.onmessage = function (evt) { onMessage(evt) }; websocket.onerror = function (evt) { onError(evt) }; } function onOpen(evt) { console.log("CONNECTED"); } // 接收数据 function onMessage(evt) { var data = eval("(" + evt.data + ")"); var type = data.type || ''; switch (type) { case 'init': // 把当新链接的客户端加入到当前直播间 console.log('-------init--------' + data); websocket.send(JSON.stringify(joinContent)); writeToScreen('<span style="color: blue;">RESPONSE: ' + evt.data + '</span>'); break; case 'join': console.log('-------join--------' + data); writeToScreen( '<span style="color: blue;"> ' + ' 新用户: ' + '</span>' + '<span style="color: red;"> ' + data.userName + '</span>' + '<span style="color: green;"> ' + data.joinTime + '</span>' + '<span style="color: black;"> ' + data.msg + '</span>' ); break; case 'say': console.log('say======' + data); writeToScreen( '<span style="color: blue;"> ' + ' Chat: ' + '</span>' + '<span style="color: red;"> ' + data.userName + '</span>' + '<span style="color: #D2691E;"> ' + data.commentTime + '</span>' + '<span style="color: black;"> ' + data.content + '</span>' ); break; default : console.log(data); break; } } function onError(evt) { console.log('<span style="color: red;">ERROR:</span> ' + evt.data); } function onClose(evt) { console.log("DISCONNECTED"); } function writeToScreen(message) { var pre = document.createElement("p"); pre.style.wordWrap = "break-word"; pre.innerHTML = message; outputContent.appendChild(pre); } function sub() { var text = document.getElementById('data').value; // {"type":"say",,"msg":"Welcome 111111111111Live Room"} var sayContent = { "type": "say", "roomId": roomId, "userId": userId, "userName": userName, "content": text }; websocket.send(JSON.stringify(sayContent)); } window.addEventListener("load", init, false); </script> </body> </html>Extension : Oui Stockez les messages dans Redis et comptez le PV de la salle de diffusion en direct via Redis
$redis = new \Redis; $redis->connect('127.0.0.1',6379); $key = "PV:ROOM:".$roomId; $field = "ROOM_TOTAL_PV"; // 进入房间的人数增长,自增 ,增加PV统计 $redis->hIncrBy($key,$field,1);
相关推荐:《PHP教程》
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!