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.phpsocket/workman/swoole學習交流群:604438441
php學習交流群:163656536
在運行 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 就可以直接訪問,比較簡陋 但是大體功能實現了。僅供學習參考。
,更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!