2016-07-07 71 views
1

我正在写一种PHP代理。PHP线程做多件事

此代理将与服务器建立几个连接,并且如果没有其他命令必须发送,则通过每隔一段时间发送一个“ping”数据包来保持连接打开。

客户端应该能够连接到代理并让它将消息转发到服务器上。在这种情况下,代理将选择其中一个当前不忙的连接(如果连接了多个客户端并且其中一个请求需要一段时间)并使用该非繁忙连接。

关于它如何工作的想法:使用RabbitMQ作为队列。客户端向RabbitMQ发送消息并等待响应。在服务器端,每个连接都是它自己的线程,每个线程都会不断地等待来自RabbitMQ的工作,并且第一个从RabbitMQ获取消息的线程将满足请求。但在这种情况下,由于连接线程一直在忙于等待工作,如果没有工作,我将如何发送keepalive包?

如果这是一个糟糕的主意,这将如何正确完成?

回答

0

从结构上讲,线程是解决这个问题的好方法,所以你肯定会以正确的方式思考这个问题。不幸的是,PHP不支持线程!所以,您必须使用进程,而不是通过pcntl_fork()Here's an example(不是我的代码),创建一个新的进程来处理每个连接而不是一个线程。

/** 
* Connection handler 
*/ 
function onConnect($client) { 
    $pid = pcntl_fork(); 

    if ($pid == -1) { 
     die('could not fork'); 
    } else if ($pid) { 
     // parent process 
     return; 
    } 

    $read = ''; 
    printf("[%s] Connected at port %d\n", $client->getAddress(), $client->getPort()); 

    while(true) { 
     $read = $client->read(); 
     if($read != '') { 
      $client->send('[' . date(DATE_RFC822) . '] ' . $read ); 
     } 
     else { 
      break; 
     } 

     if(preg_replace('/[^a-z]/', '', $read) == 'exit') { 
      break; 
     } 
     if($read === null) { 
      printf("[%s] Disconnected\n", $client->getAddress()); 
      return false; 
     } 
     else { 
      printf("[%s] recieved: %s", $client->getAddress(), $read); 
     } 
    } 
    $client->close(); 
    printf("[%s] Disconnected\n", $client->getAddress()); 

} 
require "sock/SocketServer.php"; 
$server = new \Sock\SocketServer(); 
$server->init(); 
$server->setConnectionHandler('onConnect'); 
$server->listen(); 

你说你还需要一个线程来发送keepalives。我会说最简单的解决方案是pnctl_fork()一个额外的过程,并用它来发送keepalive,而其他进程很忙。

至于keepalive消息,您可以在分叉连接处理程序进程中执行此操作。然后,在连接处理程序进程下的另一个分叉进程中执行实际的工作。

+0

请注意,这是一个非常宽泛的问题,所以很难用更具体的答案。 – Will

+0

好吧 - 我也读过pcntl_fork()。但是,只要我的客户端连接到代理服务器,该线程只会持续多久?例如,我的客户端连接 - >一个新的进程开始处理客户端 - >客户端断开连接 - >进程结束。 – derp

+0

当客户端断开连接时,进程不会自动死掉。如果客户端在工作完成之前断开连接,那么工作进程池应该完全独立,客户端只需与后台工作进程使用的队列进行交互。 – Will