PHP socket 编程: select同步非阻塞多路复用模式

听了凌总培训的socket之后,认识到socket编程虽然平时应用的不多(特别是PHP的socket编程,基本上没什么应用),但确实是非常重要的一块知识,我等泥腿子程序员务必要好好学习,千万不可舍本逐末、急功近利,捡了芝麻丢西瓜$_$。。。

因为在socket编程方面没什么基础,所以只是简单的看了一下PHP的socket,加深对socket的认识。PHP socket是基于BSD的socket接口实现的,所以如果想更深入的学习可以直接研究一下UNIX编程,这里不再赘述。

php作为一个效率一般的单线程语言,用来做socket服务器确实有点勉强,不过php还是提供了各种相关函数,使其可以完整地实现socket编程的各项功能。

// Create a new socket                   
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);                                     
$server['host'] = '127.0.0.1';           
$server['port'] = '2013';            
socket_bind($socket,$server['host'],$server['port']);
socket_listen($socket);
...

首先需要生成一个服务器端socket,并绑定到某主机、端口。注意,一定要将该socket设为非阻塞的。否则socket在accept等待新连接时程序将会被阻塞.

socket_set_nonblock($socket);

一个socket服务端必然需要同时为多个客户端提供服务,单线程的php 的socket模块提供了select的多路复用模型来解决这一问题。

//复制一份客户端列表,socket_select函数的引用参数 
$read = $this->clients;                
while ( @socket_select($read, $write = NULL, $except = NULL,2) < $this->maxClient ) {            
//从连接池中选取一个socket资源   
$newc = $this->selectClient( $read,$socket );   
if ( $newc === false )     
     break ;                                                  
 ...

当程序发现有一个新的客户端socket连接服务端时,就将该socket加入select的连接池,等待服务端提供服务,需要注意,加入的客户端socket也需要设为非阻塞,否则客户端在等待服务端读取其缓冲区中的数据时也会将线程阻塞。

当客户端发出退出信号时,服务端将该客户端socket从连接池中去除,socket连接断开。

完成编程后,可用telnet作为客户端对该服务端进行测试。

php socket

  • 另外,依靠PHP 的 libevent 扩展(需配置安装),也可以实现 epoll/kqueue 的异步非阻塞I/O模型,性能上会表现的更加优秀。
Show Comments