打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
基于Swoole的分布式socket消息服务器架构

消息服务器使用socket,为避免服务器过载,单台只允许500个socket连接,当一台不够的时候,扩充消息服务器是必然,问题来了,如何让链接在不同消息服务器上的用户可以实现消息发送呢?

要实现消息互通就必须要让这些消息服务器本身能互通,想了两个方式,一种是消息服务器之间交叉链接,另一种是增加一个特殊的消息服务器,这个消息服务器不对外开放,只负责消息转发和推送。

下列测试不考虑防火墙等。仅测试可行性和效率。

测试环境

  • 消息服务器
    192.168.0.201 9501 192.168.0.202 9501
  • 转发服务器
    192.168.0.203 9501
  • 公共缓存
    Redis 192.168.0.231 6379
  • 软件环境
    centos 6.5 mini swoole php

流程图

  • 整个流程图如下:

  • 流程图说明:
    client1可向client2或者其他client发送消息,并接收其他client发送的消息.

    Redis中保存client连接的信息,给每个用户分配唯一的key,包括链接的哪台服务器,转发服务器定时检测消息服务器,如消息服务器挂掉,由转发服务器清理掉Redis已经挂掉的所有链接。

  • 完整的流程:

    1.Client1Client2发送一条消息

    2.Socket1接收到消息,根据key从Redis取出Client2的连接信息,连接在本机,直接推送给Client2,流程结束。

    3.如果连接不在本机,把消息推送到转发服务器,由转发服务器把该消息推送给连接所在消息服务器,消息服务器接收消息,推送给Client2

    4.消息发送结束。

编码实现

  • Socket
    在socket1上创建一个server.php,内容如下:

      <?php //服务端    $serv = new swoole_server("0.0.0.0", 9501);  //redis  $redis = new \Redis();          $redis->connect("192.168.0.231", 6379);    //client  $proxy = new swoole_client(SWOOLE_TCP | SWOOLE_KEEP);  $proxy->connect("192.168.0.203", 9501);    $serv->on('start', function($serv) {      echo "Service:Start...";  });  $serv->on('connect', function ($serv, $fd) {    });  $serv->on('receive', function ($serv, $fd, $from_id, $data) {      global $redis;        $data = (array) json_decode($data);      $cmd = $data['cmd'];     switch ($cmd) {          case "login"://登陆              //保存连接信息              $save = array(                  'fd' => $fd,                  'socket_ip' => "192.168.0.201"              );              $redis->set($data['name'], serialize($save));              break;          case "chat":              $recv = unserialize($redis->get($data['recv']));              if ($recv['socket_ip'] != "192.168.0.201") {                  //需要转发                  $data['cmd'] = 'forward';                  $data['recv_ip'] = $recv['socket_ip'];                  $serv->task(json_encode($data));              } else {                  //直接发送                  $serv->send($recv['fd'], "{$data['send']}给您发了消息:{$data['content']}");              }          break;          case "forward"://接收转发消息              $recv = unserialize($redis->get($data['recv']));              $serv->send($recv['fd'], "{$data['send']}给您发了消息:{$data['content']}");          break;      }      //$serv->send($fd, 'Swoole: ' . $data);  });  $serv->on('task', function ($serv, $task_id, $from_id, $data) {      global $proxy;      $proxy->send($data);  });  $serv->on('finish', function ($serv, $task_id, $data) {  });  $serv->on('close', function ($serv, $fd) {      echo "Client: Close.\n";  });  $serv->set(array('task_worker_num' => 4));  $serv->start();

    在socket2上只需把ip变更一下即可。192.168.0.201变更为192.168.0.202.

  • Proxy
    在转发服务器上建立脚本proxy.php,内容如下:

     $serv = new swoole_server("0.0.0.0", 9501); //服务端 $serv->on('start', function($serv) {     echo "Service:Start..."; }); $serv->on('connect', function ($serv, $fd) { }); $serv->on('receive', function ($serv, $fd, $from_id, $data) {     global $redis;     $serv->task($data); }); $serv->on('task', function ($serv, $task_id, $from_id, $data) {     $forward = (array) json_decode($data);     $client = new swoole_client(SWOOLE_SOCK_TCP, SWOOLE_SOCK_SYNC);     $client->connect($forward['recv_ip'], 9501);     unset($forward['recv_ip']);     $client->send(json_encode($forward));     $client->close(); }); $serv->on('finish', function ($serv, $task_id, $data) { }); $serv->on('close', function ($serv, $fd) {     echo "Client: Close.\n"; });  $serv->set(array('task_worker_num' => 4)); $serv->start();

测试

注意开启顺序

1.开启转发服务器php proxy.php

2.分别开启socket服务器php server.php

可以在转发服务器上看到两个消息服务器已经连接
3.开始测试,分别打开两个telnet,连接两个消息服务器,发送消息测试:
登陆

发送消息测试

消息成功接收。

基于强大的swoole扩展,让php高效的实现这些成为可能,目前消息服务器到转发服务器是长连接,转发服务器到消息服务器是短连接,存在性能瓶颈,也浪费了连接资源。下一步改造成长连接,消息服务器的client使用异步。

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
【Swoole系列4.1】Swoole协程系统
Swoole 2.0 正式版发布,协程特性支持 PHP 7
php搭建swooleTCP服务器
哇靠,这些数据疯狂变化,该怎么爬取?
如何使用PHP构建一个高性能的弹幕后端服务
PHP实现WebSocket实例详解
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服