1. はじめに
Web ページ上で複数のメッセージを迅速に送受信するには、WebSocket がこのニーズを解決するのに非常に適しています。今回はWebSocketを利用してチャットWebアプリケーションを構築します。主にクライアントの実装に関係しますが、サーバーは PHP で実装された WebSocket サーバーを使用します。この記事では詳しく説明しません。
メインの JavaScript コードは次のとおりです
2. 結果
最終的に達成されるのは、サーバーにメッセージを送信することであり、サーバーは同じメッセージを返します効果は下図の通りです。画像をクリックするとオンライン表示バージョンへのリンクが送信されます
オンラインバージョンはこちらです
3. コード
JavaScript
<code><span>var</span> socket; <span>var</span> submit = document.getElementById(<span>'submit'</span>);<span>//首先输入聊天者名字,提交后可开始聊天</span><span>var</span> button = document.getElementById(<span>'send'</span>);<span>//发送按钮</span> button.addEventListener(<span>'click'</span>, sendMsg); submit.addEventListener(<span>'click'</span>, startChat); <span><span>function</span><span>startChat</span><span>()</span>{</span> document.getElementById(<span>'modal'</span>).style.visibility = <span>"collapse"</span>; document.getElementById(<span>'modalBody'</span>).style.visibility = <span>"collapse"</span>; connect();<span>//连接服务器</span> } <span>//发送消息</span><span><span>function</span><span>sendMsg</span><span>()</span>{</span><span>var</span> txetArea = document.getElementById(<span>'sendText'</span>); <span>var</span> content = txetArea.value; <span>var</span> client = document.getElementById(<span>'name'</span>).value; showMsg(content,<span>0</span>); txetArea.value = <span>""</span>; msg = { name: client, message: content } socket.send(<span>JSON</span>.stringify(msg)); <span>//发送数据</span> } <span>//显示消息</span><span><span>function</span><span>showMsg</span><span>(content,type)</span>{</span><span>var</span> mainDiv = document.getElementById(<span>'main'</span>); <span>var</span> div = document.createElement(<span>'div'</span>); mainDiv.appendChild(div); <span>var</span> lineDiv = mainDiv.lastChild; lineDiv.className = <span>'line'</span>; lineDiv.innerHTML = (<span><span>function</span><span>()</span>{</span><span>if</span> (type == <span>0</span>){ <span>return</span><span>"<div class='\"selfContent\"'></div>"</span>; } <span>else</span> { <span>return</span><span>"<div class='\"content\"'></div>"</span>; } })(); <span>var</span> contentDiv = lineDiv.lastChild; contentDiv.innerHTML = content; mainDiv.scrollTop = mainDiv.scrollHeight - mainDiv.clientHeight; } <span>//建立连接</span><span><span>function</span><span>connect</span><span>()</span>{</span><span>var</span> http_request; <span>if</span> (window.XMLHttpRequest){ http_request = <span>new</span> XMLHttpRequest(); <span>if</span> (http_request.overrideMimeType){ http_request.overrideMimeType(<span>'text/xml'</span>); } } <span>else</span><span>if</span> (window.ActiveXObject) { <span>try</span> { http_request = <span>new</span> ActiveXObject(<span>"Msxml2.XMLHTTP"</span>); } <span>catch</span> (e){ <span>try</span> { http_request = <span>new</span> ActiveXObject(<span>"Microsoft.XMLHTTP"</span>); } <span>catch</span> (e){} } } http_request.open(<span>'GET'</span>, <span>"http://localhost/websocket/server.php"</span>, <span>true</span>); http_request.send(); socket = <span>new</span> WebSocket(<span>"ws://localhost:9000/websocket/server.php"</span>); socket.onopen = open; <span>//绑定成功打开后触发的函数</span> socket.onmessage = recMessage; <span>//绑定接受到数据后的处理函数</span> socket.onerror = error; <span>//绑定处理错误的函数</span> socket.onclose = close; <span>//绑定连接关闭后的处理函数</span> } <span>//连接成功</span><span><span>function</span><span>open</span><span>()</span>{</span><span>var</span> i = document.getElementsByTagName(<span>'i'</span>); i[<span>0</span>].innerHTML = <span>'连接成功!'</span>; button.disabled = <span>''</span>; } <span>//出错</span><span><span>function</span><span>error</span><span>()</span>{</span><span>var</span> i = document.getElementsByTagName(<span>'i'</span>); i[<span>0</span>].style.color = <span>"#FF0000"</span>; i[<span>0</span>].innerHTML = <span>'连接失败'</span>; button.disabled = <span>'disabled'</span>; } <span>//接受到数据</span><span><span>function</span><span>recMessage</span><span>(e)</span>{</span><span>var</span> data = <span>JSON</span>.parse(e.data); showMsg(data.message, <span>1</span>); } <span>//连接关闭</span><span><span>function</span><span>close</span><span>()</span>{</span> button.disabled = <span>'disabled'</span>; <span>if</span> (confirm(<span>'连接已关闭,是否需要再次连接?'</span>)){ connect(); } }</code>
phpサーバーコードは、クラス
<code><span><span><?php </span><span>namespace</span><span>MyLab</span>; <span><span>class</span><span>WebSocket</span>{</span><span>private</span><span>$host</span>; <span>private</span><span>$port</span>; <span><span>function</span><span>__construct</span><span>(<span>$port</span>, <span>$host</span>)</span> {</span><span>$this</span>->host = <span>$host</span>; <span>$this</span>->port = <span>$port</span>; } <span>//启动服务</span><span><span>function</span><span>StartServer</span><span>()</span>{</span><span>$socket</span> = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);<span>//创建socket</span> socket_set_option(<span>$socket</span>, SOL_SOCKET, SO_REUSEADDR, <span>1</span>); socket_bind(<span>$socket</span>, <span>0</span>, <span>$this</span>->port); socket_listen(<span>$socket</span>);<span>//开启监听</span><span>$sockets</span> = <span>array</span>(<span>$socket</span>); <span>$write</span> = <span>NULL</span>; <span>$except</span> = <span>NULL</span>; <span>while</span> (<span>true</span>) { <span>$clients</span> = <span>$sockets</span>; <span>$num</span> = socket_select(<span>$clients</span>, <span>$write</span>, <span>$except</span>, <span>0</span>); <span>if</span> (<span>$num</span> === <span>false</span>){ <span>echo</span><span>"socket_select failed!"</span>; <span>break</span>; } <span>if</span> (in_array(<span>$socket</span>, <span>$clients</span>)) { <span>$socket_new</span> = socket_accept(<span>$socket</span>); <span>//接受连接</span><span>$sockets</span>[] = <span>$socket_new</span>; <span>//保存连接</span><span>$header</span> = socket_read(<span>$socket_new</span>, <span>1024</span>); <span>$status</span> = <span>$this</span>->handshaking(<span>$header</span>, <span>$socket_new</span>, <span>$this</span>->host, <span>$this</span>->port); <span>$response</span> = <span>$this</span>->code(json_encode(<span>array</span>(<span>'message'</span>=><span>'欢迎来到Chat with yourself'</span>))); <span>$status</span> = <span>$this</span>->sendMessage(<span>$response</span>, <span>$socket_new</span>);<span>//首次连接上之后回应</span><span>$found_socket</span> = array_search(<span>$socket</span>, <span>$clients</span>); <span>unset</span>(<span>$clients</span>[<span>$found_socket</span>]); } <span>foreach</span> (<span>$clients</span><span>as</span><span>$client</span>) <span>//遍历连接,处理接受到的消息</span> { <span>while</span> (socket_recv(<span>$client</span>, <span>$buf</span>, <span>1024</span>, <span>0</span>) >= <span>1</span>) { <span>$received_text</span> = <span>$this</span>->decode(<span>$buf</span>); <span>$decode_text</span> = json_decode(<span>$received_text</span>); <span>$user_name</span> = <span>$decode_text</span>->name; <span>$user_message</span> = <span>$decode_text</span>->message; <span>$response_text</span> = <span>$this</span>->code(json_encode(<span>array</span>(<span>'type'</span> => <span>'usermsg'</span>, <span>'name'</span> => <span>$user_name</span>, <span>'message'</span> => <span>$user_message</span>))); <span>$this</span>->sendMessage(<span>$response_text</span>, <span>$client</span>); <span>break</span><span>2</span>; } } } } <span>//握手验证</span><span><span>function</span><span>handshaking</span><span>(<span>$receved_header</span>,<span>$client_conn</span>, <span>$host</span>, <span>$port</span>)</span> {</span><span>$headers</span> = <span>array</span>(); <span>$lines</span> = preg_split(<span>"/\r\n/"</span>, <span>$receved_header</span>); <span>foreach</span>(<span>$lines</span><span>as</span><span>$line</span>) { <span>$line</span> = chop(<span>$line</span>); <span>if</span>(preg_match(<span>'/\A(\S+): (.*)\z/'</span>, <span>$line</span>, <span>$matches</span>)) { <span>$headers</span>[<span>$matches</span>[<span>1</span>]] = <span>$matches</span>[<span>2</span>]; } } <span>$secKey</span> = <span>$headers</span>[<span>'Sec-WebSocket-Key'</span>]; <span>$secAccept</span> = base64_encode(pack(<span>'H*'</span>, sha1(<span>$secKey</span> . <span>'258EAFA5-E914-47DA-95CA-C5AB0DC85B11'</span>))); <span>$upgrade</span> = <span>"HTTP/1.1 101 Web Socket Protocol Handshake\r\n"</span> . <span>"Upgrade: websocket\r\n"</span> . <span>"Connection: Upgrade\r\n"</span> . <span>"WebSocket-Origin: $host\r\n"</span> . <span>"WebSocket-Location: ws://$host:$port/demo/shout.php\r\n"</span>. <span>"Sec-WebSocket-Accept:$secAccept\r\n\r\n"</span>; socket_write(<span>$client_conn</span>,<span>$upgrade</span>,strlen(<span>$upgrade</span>)); <span>return</span><span>$upgrade</span>; } <span>//解码</span><span><span>function</span><span>decode</span><span>(<span>$str</span>)</span> {</span><span>$length</span> = ord(<span>$str</span>[<span>1</span>]) & <span>127</span>; <span>if</span> (<span>$length</span> == <span>126</span>) { <span>$masks</span> = substr(<span>$str</span>, <span>4</span>, <span>4</span>); <span>$data</span> = substr(<span>$str</span>, <span>8</span>); } <span>elseif</span> (<span>$length</span> == <span>127</span>) { <span>$masks</span> = substr(<span>$str</span>, <span>10</span>, <span>4</span>); <span>$data</span> = substr(<span>$str</span>, <span>14</span>); } <span>else</span> { <span>$masks</span> = substr(<span>$str</span>, <span>2</span>, <span>4</span>); <span>$data</span> = substr(<span>$str</span>, <span>6</span>); } <span>$str</span> = <span>''</span>; <span>for</span> (<span>$i</span> = <span>0</span>; <span>$i</span> $data</span>); ++<span>$i</span>) { <span>$str</span> .= <span>$data</span>[<span>$i</span>] ^ <span>$masks</span>[<span>$i</span> % <span>4</span>]; } <span>return</span><span>$str</span>; } <span>//发送消息</span><span><span>function</span><span>sendMessage</span><span>(<span>$msg</span>, <span>$cilent</span>)</span> {</span><span>try</span>{ <span>return</span> socket_write(<span>$cilent</span>, <span>$msg</span>, strlen(<span>$msg</span>)); } <span>catch</span> (\<span>Exception</span><span>$e</span>){ <span>return</span><span>$e</span>; } } <span>//编码</span><span><span>function</span><span>code</span><span>(<span>$str</span>)</span> {</span><span>$b1</span> = <span>0x80</span> | (<span>0x1</span> & <span>0x0f</span>); <span>$length</span> = strlen(<span>$str</span>); <span>if</span> (<span>$length</span> 125</span>) <span>$header</span> = pack(<span>'CC'</span>, <span>$b1</span>, <span>$length</span>); <span>elseif</span> (<span>$length</span> ><span>125</span> && <span>$length</span> 65536) <span>$header</span> = pack(<span>'CCn'</span>, <span>$b1</span>, <span>126</span>, <span>$length</span>); <span>elseif</span> (<span>$length</span> >= <span>65536</span>) <span>$header</span> = pack(<span>'CCNN'</span>, <span>$b1</span>, <span>127</span>, <span>$length</span>); <span>else</span> { <span>return</span><span>false</span>; } <span>return</span><span>$header</span>.<span>$str</span>; } }</code>
以上、WebSocket の使用上の注意点を関連内容も含めて紹介しましたが、PHP チュートリアルに興味のある友人の参考になれば幸いです。