PHP 协程实现

多进程/线程

最早的服务器端程序都是通过多进程、多线程来解决并发IO的问题。进程模型出现的最早,从Unix 系统诞生就开始有了进程的概念。最早的服务器端程序一般都是 Accept 一个客户端连接就创建一个进程,然后子进程进入循环同步阻塞地与客户端连接进行交互,收发处理数据。

多线程模式出现要晚一些,线程与进程相比更轻量,而且线程之间共享内存堆栈,所以不同的线程之间交互非常容易实现。比如实现一个聊天室,客户端连接之间可以交互,聊天室中的玩家可以任意的其他人发消息。用多线程模式实现非常简单,线程中可以直接向某一个客户端连接发送数据。而多进程模式就要用到管道、消息队列、共享内存等等统称进程间通信(IPC)复杂的技术才能实现。

最简单的多进程服务端模型

$serv = stream_socket_server(

"tcp://0.0.0.0:8000"

, $errno, $errstr)

or

die

(

"Create server failed"

);

while

(

1

) {

$conn = stream_socket_accept($serv);

if

(pcntl_fork() ==

0

) {

$request = fread($conn);

// do something

// $response = "hello world";

fwrite($response);

fclose($conn);

exit

(

0

);

}

}

多进程/线程模型的流程是:

创建一个

 

socket,绑定服务器端口(bind),监听端口(listen),在 PHP 中用

 

stream_socket_server

 

一个函数就能完成上面 3 个步骤,当然也可以使用更底层的sockets

 

扩展分别实现。

进入

 

while

 

循环,阻塞在

 

accept

 

操作上,等待客户端连接进入。此时程序会进入睡眠状态,直到有新的客户端发起

 

connect

 

到服务器,操作系统会唤醒此进程。accept

 

函数返回客户端连接的

 

socket

 

主进程在多进程模型下通过

 

fork(php: pcntl_fork)创建子进程,多线程模型下使用

 

pthread_create(php: new Thread)创建子线程。

下文如无特殊声明将使用进程同时表示进程/线程。

子进程创建成功后进入

 

while

 

循环,阻塞在

 

recv(php:fread)调用上,等待客户端向服务器发送数据。收到数据后服务器程序进行处理然后使用

 

send(php: fwrite)向客户端发送响应。长连接的服务会持续与客户端交互,而短连接服务一般收到响应就会

 

close。

当客户端连接关闭时,子进程退出并销毁所有资源,主进程会回收掉此子进程。



为了更好地阅读体验,请点击“阅读原文”继续阅读!