使用php(不是swoole)实现tcp/httpserver。PHP内置的流系列函数和套接字扩展提供了对网络编程的支持。socket扩展需要在编译时通过配置--enable-sockets来开启,strem系列函数完全是php核心的内置函数。php社区的workman框架底层是基于stream函数实现的。下面代码演示了php如何通过stream系列函数实现一个简单的tcp/http服务器1:单进程阻塞模式socket=@stream_socket_server($address,$errNo,$errMessage);if(!is_resource($this->socket)){thrownewInvalidArgumentException("参数异常:".$errMessage);}}publicfunctionisHttp(bool$bool):self{$this->isHttp=$bool;返回$这个;}/***启动服务器*/publicfunctionrun(){while(true){$conn=@stream_socket_accept($this->socket);if($conn){if($this->isHttp){//http服务器$data="HelloWorld";$response="HTTP/1.1200OK\r\n";$response.="内容类型:text/html;charset=UTF-8\r\n";$response.="服务器:MyServer1\r\n";$response.="内容长度:".斯特伦($数据)。"\r\n\r\n";$响应.=$数据;fwrite($conn,$response);fclose($conn);}else{//tcpserverwhile($message=fread($conn,1024)){//主退出if(trim($message)=='quit'){echo"close\n";fclose($conn);休息;}echo'我收到了:'。$消息;fwrite($conn,"确定\n");}}}}}}$server=newServer("0.0.0.0:2345");//启动tcpServer$server->run();//启动http服务器//$server->isHttp(true)->run();http服务浏览器访问http://127.0.0.1:2345/看输出结果你好worldtcp服务器通过telnet进行测试。由于连接和读取都被阻塞,因此一次只能处理一个请求。只有处理完当前请求后才能处理下一个请求,不具备并发能力。2:多进程改造socket=@stream_socket_server($address,$errNo,$errMessage);if(!is_resource($this->socket)){thrownewInvalidArgumentException("参数异常:".$errMessage);}}publicfunctionisHttp(bool$bool):self{$this->isHttp=$bool;返回$这个;}/***启动服务器*/publicfunctionrun(){while(true){$conn=@stream_socket_accept($this->socket);if($conn){if($this->isHttp){if(pcntl_fork()==0){//http服务器$data="HelloWorld";$response="HTTP/1.1200OK\r\n";$response.="内容类型:text/html;charset=UTF-8\r\n";$response.="服务器:MyServer1\r\n";$response.="内容长度:".斯特伦($数据)。"\r\n\r\n";$响应.=$数据;fwrite($conn,$response);fclose($conn);出口;}}else{//tcp服务器if(pcntl_fork()==0){while($message=fread($conn,1024)){echo'我收到了:'.$消息;fwrite($conn,"确定\n");}出口;}}}}}}$server=newServer("0.0.0.0:2345");//启动tcp服务器$server->run();//启动http服务器//$server->isHttp(true)->run();这时,由于原来的阻塞读函数是通过子进程处理的,主进程可以接受新的请求,提高并发性,因为创建进程/线程会带来很多新的问题,比如增加系统开销等,所以这个方法在生产环境中基本不会用到。3:IO多路复用(select模式)socket=@stream_socket_server($address,$errNo,$errMessage);if(!is_resource($this->socket)){thrownewInvalidArgumentException("参数异常:".$errMessage);}//stream_set_blocking设置非阻塞iostream_set_blocking($this->socket,false);//添加当前侦听器套接字$this->socketList[(int)$this->socket]=$this->socket;}publicfunctionisHttp(bool$bool):self{$this->isHttp=$bool;返回$这个;}/***启动服务器*/publicfunctionrun(){while(true){$read=$this->socketList;$write=$除了t=[];//阻塞监听设置null阻塞监听$count=@stream_select($read,$write,$except,null);if($count){foreach($readas$k=>$v){if($v==$this->socket){//连接成功//接受连接@$conn=stream_socket_accept($this->套接字,空,$remote_address);回声“连接fd:”。$k。PHP_EOL;$this->socketList[(int)$conn]=$conn;}else{//接收if($this->isHttp){$this->receiveHttp($v);}else{$this->receiveTcp($v);}}}}}}受保护函数receiveHttp($stream){$buffer=fread($stream,1024);if(empty($buffer)&&(feof($stream)||!is_resource($stream))){fclose($stream);取消设置($this->socketList[(int)$stream]);echo"退出成功".PHP_EOL;返回;}//http服务器$data="HelloWorld";$response="HTTP/1.1200OK\r\n";$response.="内容类型:text/html;charset=UTF-8\r\n";$response.="服务器:MyServer1\r\n";$response.="内容长度:".斯特伦($数据)。"\r\n\r\n";$响应.=$数据;fwrite($stream,$response);}/***处理tcp请求*/privatefunctionreceiveTcp($stream){$buffer=fread($stream,1024);如果(feof($stream)||!is_resource($stream)){unset($this->socketList[(int)$stream]);fclose($stream);echo"退出成功".PHP_EOL;返回;}回声'onReceive'。$缓冲区。“->”。$流。PHP_EOL;$message='我收到了:'。$缓冲区;fwrite($stream,"{$message}");}}$server=newServer("0.0.0.0:2345");//启动tcp服务器//$server->run();//启动http服务器$server->isHttp(true)->run();通过IO多路复用Multiplexing是目前解决高并发(C10k)问题的主要思路。通过stream_select函数调用操作系统提供的select方法,将接收到的文件描述符传递给操作系统底层,操作系统遍历返回需要处理的文件描述符,这样就不需要一直阻塞在应用层面,提高并发能力。4:IO多路开销(pollepoll)由于select方式存在各种问题,如性能不佳,数量受限等。处理小规模并发没有问题,但是大规模并发就捉襟见肘了。这时候就需要poll和epoll(推荐)方法来实现多路复用。具体需要在php中安装event或者libevent扩展。详细代码请参考workman源码,此处不再赘述。示例代码https://github.com/tim1116/ph...参考:https://www.php.net/manual/zh...(php支持的SocketTransports)https://www.php.net/手册/zh...https://www.php.net/manual/zh...
