WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。
WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。
在 WebSocket API 中,浏览器和服务器只需要完成一次握手的动作,浏览器和服务器之间就形成了一条快速通道创建持久性的连接,两者之间就直接可以数据互相传送。(长连接,循环连接的不算)
现在,很多网站为了实现推送技术,所用的技术都是 Ajax 轮询。轮询是在特定的的时间间隔(如每1秒),由浏览器对服务器发出HTTP请求,然后由服务器返回最新的数据给客户端的浏览器。
这种传统的模式带来很明显的缺点,即浏览器需要不断的向服务器发出请求,然而HTTP请求可能包含较长的头部,其中真正有效的数据可能只是很小的一部分,显然这样会浪费很多的带宽等资源。
php应用实现webSocket更多使用workerman或swoole框架.
简单实现webSocket(demo)
serverSocket.php文件
?1 <?php ?2 ??3 class SocketService ?4 { ?5 ????private $address; ?6 ????private $port; ?7 ????private $_sockets; ?8 ????public function __construct($address = ‘‘, $port=‘‘) ?9 ????{ 10 ????????????if(!empty($address)){ 11 ????????????????$this->address = $address; 12 ????????????} 13 ????????????if(!empty($port)) { 14 ????????????????$this->port = $port; 15 ????????????} 16 ????} 17 ??18 ????public function service(){ 19 ????????//获取tcp协议号码。 20 ????????$tcp = getprotobyname("tcp"); 21 ????????$sock = socket_create(AF_INET, SOCK_STREAM, $tcp); 22 ????????socket_set_option($sock, SOL_SOCKET, SO_REUSEADDR, 1); 23 ????????if($sock < 0) 24 ????????{ 25 ????????????throw new Exception("failed to create socket: ".socket_strerror($sock)."\n"); 26 ????????} 27 ????????socket_bind($sock, $this->address, $this->port); 28 ????????socket_listen($sock, $this->port); 29 ????????echo "listen on $this->address $this->port ... \n"; 30 ????????$this->_sockets = $sock; 31 ????} 32 ??33 ????public function run(){ 34 ????????$this->service(); 35 ????????$clients[] = $this->_sockets; 36 ????????while (true){ 37 ????????????$changes = $clients; 38 ????????????$write = NULL; 39 ????????????$except = NULL; 40 ????????????socket_select($changes, ?$write, ?$except, NULL); 41 ????????????foreach ($changes as $key => $_sock){ 42 ????????????????if($this->_sockets == $_sock){ //判断是不是新接入的socket 43 ????????????????????if(($newClient = socket_accept($_sock)) ?=== false){ 44 ????????????????????????die(‘failed to accept socket: ‘.socket_strerror($_sock)."\n"); 45 ????????????????????} 46 ????????????????????$line = trim(socket_read($newClient, 1024)); 47 ????????????????????$this->handshaking($newClient, $line); 48 ????????????????????//获取client ip 49 ????????????????????socket_getpeername ($newClient, $ip); 50 ????????????????????$clients[$ip] = $newClient; 51 ????????????????????echo ?"Client ip:{$ip} ??\n"; 52 ????????????????????echo "Client msg:{$line} \n"; 53 ????????????????} else { 54 ????????????????????socket_recv($_sock, $buffer, ?2048, 0); 55 ????????????????????$msg = $this->message($buffer); 56 ????????????????????//在这里业务代码 57 ????????????????????echo "{$key} clinet msg:",$msg,"\n"; 58 ????????????????????fwrite(STDOUT, ‘Please input a argument:‘); 59 ????????????????????$response = trim(fgets(STDIN)); 60 ????????????????????$this->send($_sock, $response); 61 ????????????????????echo "{$key} response to Client:".$response,"\n"; 62 ????????????????} 63 ????????????} 64 ????????} 65 ????} 66 ??67 ????/** 68 ?????* 握手处理 69 ?????* @param $newClient socket 70 ?????* @return int ?接收到的信息 71 ?????*/ 72 ????public function handshaking($newClient, $line){ 73 ??74 ????????$headers = array(); 75 ????????$lines = preg_split("/\r\n/", $line); 76 ????????foreach($lines as $line) 77 ????????{ 78 ????????????$line = chop($line); 79 ????????????if(preg_match(‘/\A(\S+): (.*)\z/‘, $line, $matches)) 80 ????????????{ 81 ????????????????$headers[$matches[1]] = $matches[2]; 82 ????????????} 83 ????????} 84 ????????$secKey = $headers[‘Sec-WebSocket-Key‘]; 85 ????????$secAccept = base64_encode(pack(‘H*‘, sha1($secKey . ‘258EAFA5-E914-47DA-95CA-C5AB0DC85B11‘))); 86 ????????$upgrade ?= "HTTP/1.1 101 Web Socket Protocol Handshake\r\n" . 87 ????????????"Upgrade: websocket\r\n" . 88 ????????????"Connection: Upgrade\r\n" . 89 ????????????"WebSocket-Origin: $this->address\r\n" . 90 ????????????"WebSocket-Location: ws://$this->address:$this->port/websocket/websocket\r\n". 91 ????????????"Sec-WebSocket-Accept:$secAccept\r\n\r\n"; 92 ????????return socket_write($newClient, $upgrade, strlen($upgrade)); 93 ????} 94 ??95 ????/** 96 ?????* 解析接收数据 97 ?????* @param $buffer 98 ?????* @return null|string 99 ?????*/100 ????public function message($buffer){101 ????????$len = $masks = $data = $decoded = null;102 ????????$len = ord($buffer[1]) & 127;103 ????????if ($len === 126) ?{104 ????????????$masks = substr($buffer, 4, 4);105 ????????????$data = substr($buffer, 8);106 ????????} else if ($len === 127) ?{107 ????????????$masks = substr($buffer, 10, 4);108 ????????????$data = substr($buffer, 14);109 ????????} else ?{110 ????????????$masks = substr($buffer, 2, 4);111 ????????????$data = substr($buffer, 6);112 ????????}113 ????????for ($index = 0; $index < strlen($data); $index++) {114 ????????????$decoded .= $data[$index] ^ $masks[$index % 4];115 ????????}116 ????????return $decoded;117 ????}118 ?119 ????/**120 ?????* 发送数据121 ?????* @param $newClinet 新接入的socket122 ?????* @param $msg ??要发送的数据123 ?????* @return int|string124 ?????*/125 ????public function send($newClinet, $msg){126 ????????$msg = $this->frame($msg);127 ????????socket_write($newClinet, $msg, strlen($msg));128 ????}129 ?130 ????public function frame($s) {131 ????????$a = str_split($s, 125);132 ????????if (count($a) == 1) {133 ????????????return "\x81" . chr(strlen($a[0])) . $a[0];134 ????????}135 ????????$ns = "";136 ????????foreach ($a as $o) {137 ????????????$ns .= "\x81" . chr(strlen($o)) . $o;138 ????????}139 ????????return $ns;140 ????}141 ?142 ????/**143 ?????* 关闭socket144 ?????*/145 ????public function close(){146 ????????return socket_close($this->_sockets);147 ????}148 }149 ?150 $sock = new SocketService(‘127.0.0.1‘,‘9000‘);151 $sock->run();
web.html 文件
1 <!doctype html> 2 <html lang="en"> 3 ?<head> 4 ??<meta charset="UTF-8"> 5 ??<meta name="viewport" content="width=device-width,initial-scale=1, maximum-scale=1, user-scalable=no"> 6 ??<title>websocket</title> 7 ?</head> 8 ?<body> 9 ?<input id="text" value="">10 ?<input type="submit" value="send" onclick="start()">11 ?<input type="submit" value="close" onclick="close()">12 <div id="msg"></div>13 ?<script>14 ????/**15 ??????*0:未连接16 ??????*1:连接成功,可通讯17 ??????*2:正在关闭18 ??????*3:连接已关闭或无法打开19 ??????*/20 ????//创建一个webSocket 实例21 ????var webSocket ?= new ?WebSocket("ws://127.0.0.1:9000");22 ?23 ?24 ????webSocket.onerror = function (event){25 ????????onError(event);26 ????};27 ?28 ????// 打开websocket29 ????webSocket.onopen = function (event){30 ????????onOpen(event);31 ????};32 ?33 ????//监听消息34 ????webSocket.onmessage = function (event){35 ????????onMessage(event);36 ????};37 ?38 ?39 ????webSocket.onclose = function (event){40 ????????onClose(event);41 ????}42 ?43 ????//关闭监听websocket44 ????function onError(event){45 ????????document.getElementById("msg").innerHTML = "<p>close</p>";46 ????????console.log("error"+event.data);47 ????};48 ?49 ????function onOpen(event){50 ????????console.log("open:"+sockState());51 ????????document.getElementById("msg").innerHTML = "<p>Connect to Service</p>";52 ????};53 ????54 ????function onMessage(event){55 ????????console.log("onMessage");56 ????????document.getElementById("msg").innerHTML += "<p>response:"+event.data+"</p>"57 ????};58 ?59 ????function onClose(event){60 ????????document.getElementById("msg").innerHTML = "<p>close</p>";61 ????????console.log("close:"+sockState());62 ????????webSocket.close();63 ????}64 ?65 ????function sockState(){66 ????????var status = [‘未连接‘,‘连接成功,可通讯‘,‘正在关闭‘,‘连接已关闭或无法打开‘];67 ????????????return status[webSocket.readyState];68 ????}69 ?70 ????function start(event){71 ????????console.log(webSocket);72 ????????var msg = document.getElementById(‘text‘).value;73 ????????document.getElementById(‘text‘).value = ‘‘;74 ????????console.log("send:"+sockState());75 ????????console.log("msg="+msg);76 ????????webSocket.send("msg="+msg);77 ????????document.getElementById("msg").innerHTML += "<p>request"+msg+"</p>"78 ????};79 ?80 ????function close(event){81 ????????webSocket.close();82 ????}83 ?</script>84 ?</body>85 </html>
运行结果:
准备工作开启扩展: php需要打开websocket的配置,在php安装目录下的php.ini extension=php_sockets.dll
先执行脚本 例如: php -q serverSocket.php
后执行页面 例如: http://web.html
php 简单实现webSocket(demo)
原文地址:https://www.cnblogs.com/cxx8181602/p/10142140.html