Research on issues of worker storage client connection and cross-process communication

Research on issues of worker storage client connection and cross-process communication

1. First of all, this wiki is based on the changes to the server code based on the structure of the company's project "[[Indoor Navigation Solution]]".

2. Secondly, I was born in ue4 and c++ and have never understood php. Before I learned about workman, my knowledge of PHP was only to use PHP to connect to the database, and then return the data to C++ for use through get. I don’t understand PHP syntax, code specifications, etc. So if there is anything wrong, please correct me.

1: When the worker is a single process, the problem of sharing array variables

Requirements : When we process client connections, we need to divide client links into two categories: WeChat and Web. At the same time, they correspond one to one, that is, one WeChat terminal needs to correspond to one web terminal.
Idea : Our idea is to create two arrays ($WX=array(); $Web=array()). Store all WeChat connections in $WX, and store all Web connections in Web.
Problem encountered : These two arrays are not stored all the time. When the connection arrives, it is clearly stored in the array, but when the message arrives, both arrays are empty.

Solution: ① Define these two arrays into the worker class. ②: Add "global $ws_worker;" to the first sentence of each function in your own running class to make our $ws_worker global. (Using C++ syntax, it is simply difficult to understand this way of writing!)

//在库文件worker.php里面添加、声明两个数组
//定义两个数组用于存储所有的WX连接,所有的Web连接
    public $WX=array();
    public $Web=array();
//在我们自己写的run.php里面
//每个函数里面申明我们的全局worker
$ws_worker->onMessage = function($connection, $data)
{
   global $ws_worker;
   ......       
}
      After processing in this way, we can save these links very well, so that when a wx client message arrives, we can find the corresponding Web to forward the message. But it is still limited to $ws_worker->count = 1; when starting a process.

2: When there are multiple worker processes, mutual communication between processes

Requirements : When we use workers as servers, when the number of connections is relatively small, we can use $ws_worker->count = 1; it can be completely handled. But if you encounter a project with a relatively large number of connections, then $ws_worker->count = 4; is still necessary.
Idea : Use the worker-based component Channel to communicate between threads. Channel is two php files Client.php and Server.php.
The solution is available after downloading : ①: Register the event in the "onWorkerStart" function when the worker process starts (I understand it as registration). ②When communication between threads is required, we call "\Channel\Client::publish('Findandclose', $event_data);" for the registered corresponding event.   
// 每个worker进程启动时(这个函数是进程间通讯,事件注册用)
$ws_worker->onWorkerStart = function($ws_worker)
{
    //需要跨线程做的事都写在这里
    // Channel客户端连接到Channel服务端
    Channel\Client::connect('127.0.0.1', 2206);
    // 注册"Findandforward"事件,用于消息转发时当前进程找不到对应连接时调用
    Channel\Client::on('Findandforward', function($event_data)use($ws_worker){
      if($event_data->type == 'Message')
      {
        if($event_data->from == 'WX')
        {
               foreach ($ws_worker->Web as $everyweb) 
               {
                 if($event_data->openid == $everyweb['openid'])
                 {
                   $everyweb['connect']->send($event_data->data);
                   break;
                 }
		       }
        }
      }
    });
    // 注册"Findandclose"事件,用于连接断开时当前进程找不到对应连接
      Channel\Client::on('Findandclose', function($event_data)use($ws_worker){
      if($event_data['Who_closed']== 'WX_closed')
      {
          foreach( $ws_worker->Web as $key => $value ) {
            if($value['openid'] ==$event_data['openid'])
            {
              $ws_worker->Web[$key]['connect']->close();
              array_splice($ws_worker->Web,$key,1);//重置数组
              var_dump($ws_worker->Web);
              savelog("在其它进程找到了需要关闭的Web连接"."  ".$event_data['openid']);
              break;
            }
          }
      }
      if($event_data['Who_closed']== 'Web_closed')
      {
          foreach( $ws_worker->WX as $key => $value ) {
            if($value['openid'] ==$event_data['openid'])
            {
              $ws_worker->WX[$key]['connect']->close();
              array_splice($ws_worker->WX,$key,1);//重置数组
              var_dump($ws_worker->WX);
              savelog("在其它进程找到了需要关闭的WX连接"."  ".$event_data['openid']);
              break;
            }
          }
      }  
    });
};
//调用我们的跨线程事件
      if($jsondata->from == 'WX')
      {          
          savelog("WX is sen Message the WX id is"."   ".$jsondata->openid);
           //循环$Web匹配本次消息的openid对应有就将小程序的消息转发给web
            $isfind_theweb=false;//定义一个Bool变量,判断在当前线程是否找到对应的连接
            foreach ($ws_worker->Web as $everyweb) {
  			if($jsondata->openid == $everyweb['openid'])
            {
              $isfind_theweb=true;//当前线程找到了对应连接
                $everyweb['connect']->send($jsondata->data);
                break;
            }
		}
        if(!$isfind_theweb)//如果在这个进程没有找到对应的web,我们发送全局事件
        {
          savelog("当前进程未找到匹配连接");
          $event_data = $jsondata;
          // 向所有worker进程发布Findandforward事件
          \Channel\Client::publish('Findandforward', $event_data);//Findandforward是我们要调用的事件名,$event_data是我们要传递的参数
        }   
      }

 Summarize

      Once workerman is used, it can serve many of our projects. Later, the server side will basically use websocket communication, which is still a very useful thing. Of course this is only a small part. This is my first time coming into contact with php. If you have better solutions to the above problems, please leave me a message. Regarding other aspects, I hope you can record and share more.

Guess you like

Origin blog.csdn.net/qq_22824481/article/details/80452125
Recommended