Maison  >  Article  >  développement back-end  >  WebSocket使用笔记

WebSocket使用笔记

WBOY
WBOYoriginal
2016-07-29 09:05:51896parcourir

一、简介

对于网页中快速的发送接收多条消息,WebSocket非常适合来解决这种需求。此次使用WebSocket来搭建一个聊天网页应用。主要涉及的客户端的实现,服务端使用是一个php来实现的WebSocket服务端,在本篇中暂不做详细介绍。
主要的JavaScript代码有这些

  • new WebSocket 创建一个websocket对象
  • socket.onopen 建立连接后触发
  • socket.onerror 错误时触发
  • socket.onmessage 接受到数据时触发
  • socket.onclose 连接关闭时触发
  • socket.send() 发送数据

二、成果

最终实现的是向服务器发消息,服务器返回相同消息,效果如下图所示。在线展示版点击图片下发链接

WebSocket使用笔记

在线版本在这里

三、代码

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>
').addClass('pre-numbering').hide(); $(this).addClass('has-numbering').parent().append($numbering); for (i = 1; i ').text(i)); }; $numbering.fadeIn(1700); }); });

以上就介绍了WebSocket使用笔记,包括了方面的内容,希望对PHP教程有兴趣的朋友有所帮助。

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Article précédent:细说php作者高洛峰免费收徒Article suivant:xampp配置虚拟主机