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

先从socket通信简单的demo说起

 

$socket = socket_create(AF_INET,SOCK_STREAM,SOL_TCP);
 
server.php
 
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 就可以直接访问,比较简陋 但是大体功能实现了。仅供学习参考。

 

关于这个文章对应的视频课程:https://ke.qq.com/course/373963?tuin=30289dc0

socket/workman/swoole技术交流群:604438441

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

qq_33716731

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值