一、簡介
對於網頁中快速的發送接收多條訊息,WebSocket非常適合來解決這種需求。此次使用WebSocket來搭建一個聊天網頁應用。主要涉及的用戶端的實現,服務端使用是一個php來實現的WebSocket服務端,在本篇中暫不做詳細介紹。
主要的JavaScript代碼有這些
- new WebSocket 建立一個websocket對象
- socket.onopen 建立串連後觸發
- socket.onerror 錯誤時觸發
- socket.onmessage 接受到資料時觸發
- socket.onclose 串連關閉時觸發
- socket.send() 發送資料
二、成果
最終實現的是向伺服器發訊息,伺服器返回相同訊息,效果如所示。線上展示版點擊圖片下發連結
線上版本在這裡
三、代碼
JavaScript
var socket;var submit = document.getElementById('submit');//首先輸入聊天者名字,提交後可開始聊天var button = document.getElementById('send');//發送按鈕button.addEventListener('click', sendMsg);submit.addEventListener('click', startChat);functionstartChat(){ document.getElementById('modal').style.visibility = "collapse"; document.getElementById('modalBody').style.visibility = "collapse"; connect();//串連伺服器}//發送訊息functionsendMsg(){var txetArea = document.getElementById('sendText'); var content = txetArea.value; var client = document.getElementById('name').value; showMsg(content,0); txetArea.value = ""; msg = { name: client, message: content } socket.send(JSON.stringify(msg)); //發送資料}//顯示訊息functionshowMsg(content,type){var mainDiv = document.getElementById('main'); var div = document.createElement('div'); mainDiv.appendChild(div); var lineDiv = mainDiv.lastChild; lineDiv.className = 'line'; lineDiv.innerHTML = (function(){if (type == 0){ return""; } else { return""; } })(); var contentDiv = lineDiv.lastChild; contentDiv.innerHTML = content; mainDiv.scrollTop = mainDiv.scrollHeight - mainDiv.clientHeight;}//建立串連functionconnect(){var http_request; if (window.XMLHttpRequest){ http_request = new XMLHttpRequest(); if (http_request.overrideMimeType){ http_request.overrideMimeType('text/xml'); } } elseif (window.ActiveXObject) { try { http_request = new ActiveXObject("Msxml2.XMLHTTP"); } catch (e){ try { http_request = new ActiveXObject("Microsoft.XMLHTTP"); } catch (e){} } } http_request.open('GET', "http://localhost/websocket/server.php", true); http_request.send(); socket = new WebSocket("ws://localhost:9000/websocket/server.php"); socket.onopen = open; //綁定成功開啟後觸發的函數 socket.onmessage = recMessage; //綁定接受到資料後的處理函數 socket.onerror = error; //綁定處理錯誤的函數 socket.onclose = close; //綁定串連關閉後的處理函數}//串連成功functionopen(){var i = document.getElementsByTagName('i'); i[0].innerHTML = '串連成功!'; button.disabled = '';}//出錯functionerror(){var i = document.getElementsByTagName('i'); i[0].style.color = "#FF0000"; i[0].innerHTML = '串連失敗'; button.disabled = 'disabled';}//接受到資料functionrecMessage(e){var data = JSON.parse(e.data); showMsg(data.message, 1);}//串連關閉functionclose(){ button.disabled = 'disabled'; if (confirm('串連已關閉,是否需要再次串連?')){ connect(); }}
php服務端代碼,已封裝成類
namespaceMyLab;classWebSocket{private$host; private$port; function__construct($port, $host) {$this->host = $host; $this->port = $port; } //啟動服務functionStartServer(){$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);//建立socket socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, 1); socket_bind($socket, 0, $this->port); socket_listen($socket);//開啟監聽$sockets = array($socket); $write = NULL; $except = NULL; while (true) { $clients = $sockets; $num = socket_select($clients, $write, $except, 0); if ($num === false){ echo"socket_select failed!"; break; } if (in_array($socket, $clients)) { $socket_new = socket_accept($socket); //接受串連$sockets[] = $socket_new; //儲存串連$header = socket_read($socket_new, 1024); $status = $this->handshaking($header, $socket_new, $this->host, $this->port); $response = $this->code(json_encode(array('message'=>'歡迎來到Chat with yourself'))); $status = $this->sendMessage($response, $socket_new);//首次串連上之後回應$found_socket = array_search($socket, $clients); unset($clients[$found_socket]); } foreach ($clientsas$client) //遍曆串連,處理接受到的訊息 { while (socket_recv($client, $buf, 1024, 0) >= 1) { $received_text = $this->decode($buf); $decode_text = json_decode($received_text); $user_name = $decode_text->name; $user_message = $decode_text->message; $response_text = $this->code(json_encode(array('type' => 'usermsg', 'name' => $user_name, 'message' => $user_message))); $this->sendMessage($response_text, $client); break2; } } } } //握手驗證functionhandshaking($receved_header,$client_conn, $host, $port) {$headers = array(); $lines = preg_split("/\r\n/", $receved_header); foreach($linesas$line) { $line = chop($line); if(preg_match('/\A(\S+): (.*)\z/', $line, $matches)) { $headers[$matches[1]] = $matches[2]; } } $secKey = $headers['Sec-WebSocket-Key']; $secAccept = base64_encode(pack('H*', sha1($secKey . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'))); $upgrade = "HTTP/1.1 101 Web Socket Protocol Handshake\r\n" . "Upgrade: websocket\r\n" . "Connection: Upgrade\r\n" . "WebSocket-Origin: $host\r\n" . "WebSocket-Location: ws://$host:$port/demo/shout.php\r\n". "Sec-WebSocket-Accept:$secAccept\r\n\r\n"; socket_write($client_conn,$upgrade,strlen($upgrade)); return$upgrade; } //解碼functiondecode($str) {$length = ord($str[1]) & 127; if ($length == 126) { $masks = substr($str, 4, 4); $data = substr($str, 8); } elseif ($length == 127) { $masks = substr($str, 10, 4); $data = substr($str, 14); } else { $masks = substr($str, 2, 4); $data = substr($str, 6); } $str = ''; for ($i = 0; $i < strlen($data); ++$i) { $str .= $data[$i] ^ $masks[$i % 4]; } return$str; } //發送訊息functionsendMessage($msg, $cilent) {try{ return socket_write($cilent, $msg, strlen($msg)); } catch (\Exception$e){ return$e; } } //編碼functioncode($str) {$b1 = 0x80 | (0x1 & 0x0f); $length = strlen($str); if ($length <= 125) $header = pack('CC', $b1, $length); elseif ($length >125 && $length < 65536) $header = pack('CCn', $b1, 126, $length); elseif ($length >= 65536) $header = pack('CCNN', $b1, 127, $length); else { returnfalse; } return$header.$str; }}
').addClass('pre-numbering').hide(); $(this).addClass('has-numbering').parent().append($numbering); for (i = 1; i <= lines; i++) { $numbering.append($('
').text(i)); }; $numbering.fadeIn(1700); }); });
以上就介紹了WebSocket使用筆記,包括了方面的內容,希望對PHP教程有興趣的朋友有所協助。