php网络编程之io多路复用以及实现http服务器功能(二)

2022-10-11 22:10:44 119 0
魁首哥

先从 socket 通信简单的demo开始

server.php

$socket = socket_create(AF_INET,SOCK_STREAM,SOL_TCP);
socket_set_option($socket,SOL_SOCKET,SO_REUSEADDR,true);
socket_bind($socket,0,8888);
socket_listen($socket);
while(true){
 $conSock = socket_accept($socket);
 socket_getpeername($conSock,$ip,$port);
 echo 'ip:'.$ip.'...port:'.$port.'...connetted'.PHP_EOL;
 while(true){
 $recMsg = socket_read($conSock,1024);
 socket_write($conSock,strtoupper($recMsg), strlen ($recMsg));
 echo $recMsg ;
 }
}

client.php

$socket = socket_create(AF_INET,SOCK_STREAM,SOL_TCP);
socket_connect($socket,'192.168.113.136',8888);
while(true){
 fwrite( STDOUT ,'请输入内容:');
 $in =  fgets (STDIN);
 socket_write($socket,$in,strlen($in));
 echo socket_read($socket,1024);
}
 

先运行 server.php

在运行 client.php

实现了socket的通信,但是这里有个问题,当我们在开一个终端运行 client.php时,这时 无法进行 socket通信,因为 上一个client.php在阻塞,没办法进行应答。这里就需要一个新的知识点,来解决。

IO阻塞模型只能是同一个时刻只能由一个客户端进行访问。不能好几个客户端同时访问服务端。

解决:

1 多进程

2 IO 多路复用 机制

select(apache) epoll (nginx) 模型

socket_select() 函数 就是使用了 select 模型 实现io多路复用

socket_select 这个函数解决

//实现io多路复用 返回活跃的连接
socket_select ( array &$read , array &$write , array &$except , int $tv_sec [, int $tv_usec = 0 ] )
注意 :前三个参数都是引用传值。
$read 服务端监听的套接字资源,当它有变化(就是有新消息到或者有客户端连接/断开)时,socket_select函数才会返回,继续往下执行。
$write是监听是否有客户端写数据,传入NULL是不关心是否有写变化。
$except是$ sockets 里面要被排除的元素,传入NULL是”监听”全部。
第四个参数为null为阻塞, 为0位非阻塞, 为 >0 为等待时间
返回 活跃的链接数 当有连接 或数据操作时就会返回
 

改造一下sever.php的代码

//server.php 把上面的server.php 改造之后
$socket = socket_create(AF_INET,SOCK_STREAM,SOL_TCP);
socket_set_option($socket,SOL_SOCKET,SO_REUSEADDR,true);
socket_bind($socket,0,8888);
socket_listen($socket);
$sockets[] = $socket;
$write = null;
$except = null;
while(true){
 $tmp_sockets = $sockets;
 socket_select($tmp_sockets,$write,$except,null);
 foreach($tmp_sockets as $sock){
 if($sock==$socket){
 $conSock = socket_accept($socket);
 socket_getpeername($conSock,$ip,$port);
 echo 'ip:'.$ip.'...port:'.$port.'...connetted'.PHP_EOL;
 $sockets[] = $conSock;
 }else{
 $recMsg = socket_read($sock,1024);
 socket_write($sock,strtoupper($recMsg),strlen($recMsg));
 echo $recMsg ;
 }
 }
}
 

client.php代码不变 然后 在分别执行 server.php 以及 client.php

两个终端链接 可以进行通信 不受影响

实现web服务器功能

$socket = socket_create(AF_INET,SOCK_STREAM,SOL_TCP);
socket_set_option($socket,SOL_SOCKET,SO_REUSEADDR,true);
socket_bind($socket,0,80);
socket_listen($socket);
$sockets[] = $socket;
$write = null;
$except = null;
while(true){
 $tmp_sockets = $sockets;
 socket_select($tmp_sockets,$write,$except,null);
 foreach($tmp_sockets as $sock){
 if($sock==$socket){
 $conSock = socket_accept($socket);
 socket_getpeername($conSock,$ip,$port);
 $sockets[] = $conSock;
 }else{
 $str = 'hello this is socket';
 $len = strlen($str);
 $response = "HTTP/1.1 200 OK\r\n";
 $response .= "Content-Type: text/html; charset=utf-8\r\n";
 $response .="Content-Length: $len\r\n\r\n";
 $response .=$str;
 @socket_write($sock,$response,strlen($response));
 }
 }
}
 

浏览器访问

已经可以正常的能够访问了,不依赖于 nginx apache 就可以直接访问,比较简陋 但是大体功能实现了。仅供学习参考。

收藏
分享
海报
0 条评论
119
上一篇:php实现的MVC模式框架-「布尔」 下一篇:PHPFPM优化

本站已关闭游客评论,请登录或者注册后再评论吧~

忘记密码?

图形验证码