先从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);}
socket/workman/swoole学习交流群:604438441
php学习交流群:163656536
先运行 server.php
![ab3d0878ab0130ae49cefec12f06a295.png](https://i-blog.csdnimg.cn/blog_migrate/20702db5cb47551dd5dfec96a389d145.jpeg)
在运行 client.php
![3e7d5c70b0430bf2577699afa1fbde57.png](https://i-blog.csdnimg.cn/blog_migrate/6ff54cbee53b22f9ba4d175094affbe1.jpeg)
实现了socket的通信,但是这里有个问题,当我们在开一个终端运行 client.php时,这时 无法进行 socket通信,因为 上一个client.php在阻塞,没办法进行应答。这里就需要一个新的知识点,来解决。
![71fceb3d9a58ab85879dd9b75e30b844.png](https://i-blog.csdnimg.cn/blog_migrate/d5eab8f2bd2d91c8f5ab14df1987ee94.jpeg)
IO阻塞模型只能是同一个时刻只能由一个客户端进行访问。不能好几个客户端同时访问服务端。
解决:
1 多进程
2 IO多路复用机制
select(apache) epoll (nginx) 模型
socket_select() 函数 就是使用了 select 模型 实现io多路复用
![449dba378ee80649deb12760e4c1ceec.png](https://i-blog.csdnimg.cn/blog_migrate/cd90d9d8ea44b080b504f1f739bd56b1.jpeg)
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
![61afa2fbbc3d391b582f10cbc220075f.png](https://i-blog.csdnimg.cn/blog_migrate/50445a86b0e3b7e539bf92ed72305ef9.jpeg)
![be97f638d41c90f909a18d24e0830902.png](https://i-blog.csdnimg.cn/blog_migrate/a9247d3baca4fa9cf4d9ac99346eb885.jpeg)
两个终端链接 可以进行通信 不受影响
实现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"; $response .= "Content-Type: text/html; charset=utf-8"; $response .="Content-Length: $len"; $response .=$str; @socket_write($sock,$response,strlen($response)); } }}
浏览器访问
![d2c20be0ac3e510055198a2532ec9f87.png](https://i-blog.csdnimg.cn/blog_migrate/8ed38393ea7e58d4c1d5e114d0a9a5b0.jpeg)
已经可以正常的能够访问了,不依赖于 nginx apache 就可以直接访问,比较简陋 但是大体功能实现了。仅供学习参考。