本站测试实例访问地址: http://code.liuxinxiu.com/php/Interface/html/WebSocket.html

XML/HTML代码
  1. <!DOCTYPE html>  
  2. <html>  
  3.     <head>  
  4.         <title>chatdemo</title>  
  5.         <meta charset="utf-8">  
  6.         <meta name="viewport" content="width=device-width,initial-scale=1, maximum-scale=1, user-scalable=no">  
  7.         <link href="http://code.liuxinxiu.com/lib/bootstrap/3.3.2/bootstrap.min.css" rel="stylesheet">  
  8.         <style type="text/css">  
  9.         <!--  
  10.         html, body {  
  11.           min-height: 100%; }  
  12.   
  13.         body {  
  14.           margin: 0;  
  15.           padding: 0;  
  16.           width: 100%;  
  17.           font-family: "Microsoft Yahei",sans-serif, Arial; }  
  18.   
  19.         .container {  
  20.           text-align: center; }  
  21.   
  22.         .title {  
  23.           font-size: 16px;  
  24.           color: rgba(0, 0, 0, 0.3);  
  25.           position: fixed;  
  26.           z-index:1000;  
  27.           line-height: 30px;  
  28.           height: 30px;  
  29.           left: 0px;  
  30.           right: 0px;  
  31.           background-color: white; }  
  32.   
  33.         .content {  
  34.           background-color: #f1f1f1;  
  35.           border-top-left-radius: 6px;  
  36.           border-top-right-radius: 6px;  
  37.           margin-top: 30px; }  
  38.           .content .show-area {  
  39.             text-align: left;  
  40.             padding-top: 8px;  
  41.             padding-bottom: 168px; }  
  42.             .content .show-area .message {  
  43.               width: 70%;  
  44.               padding: 5px;  
  45.               word-wrap: break-word;  
  46.               word-break: normal; }  
  47.           .content .write-area {  
  48.             position: fixed;  
  49.             bottom: 0px;  
  50.             right: 0px;  
  51.             left: 0px;  
  52.             background-color: #f1f1f1;  
  53.             z-index: 10;  
  54.             width: 100%;  
  55.             height: 160px;  
  56.             border-top: 1px solid #d8d8d8; }  
  57.             .content .write-area .send {  
  58.               position: relative;  
  59.               top: -28px;  
  60.               height: 28px;  
  61.               border-top-left-radius: 55px;  
  62.               border-top-right-radius: 55px; }  
  63.             .content .write-area #name{  
  64.               position: relative;  
  65.               top: -20px;  
  66.               line-height: 28px;  
  67.               font-size: 13px; }  
  68.         -->  
  69.         </style>  
  70.     </head>  
  71.     <body>  
  72.         <div class="container">  
  73.             <div class="title">简易聊天demo</div>  
  74.             <div class="content">  
  75.                 <div class="show-area"></div>  
  76.                 <div class="write-area">  
  77.                     <div><button class="btn btn-default send" >发送</button></div>  
  78.                     <div><input name="name" id="name" type="text" placeholder="input your name"></div>  
  79.                     <div>  
  80.                         <textarea name="message" id="message" cols="38" rows="4" placeholder="input your message..."></textarea>  
  81.                     </div>                      
  82.                 </div>  
  83.             </div>  
  84.         </div>  
  85.   
  86.         <script src="http://code.liuxinxiu.com/lib/jquery/1.9.1/jquery.min.js"></script>  
  87.         <script src="http://code.liuxinxiu.com/lib/bootstrap/3.3.2/bootstrap.min.js"></script>  
  88.         <script>  
  89.         $(function(){  
  90.         var wsurl='ws://code.liuxinxiu.com:9090/php/webSocket/server.php';  
  91.             var websocket;  
  92.             var i = 0;  
  93.             /******** 判断是否有webSocket对象 *******/  
  94.             if(window.WebSocket){  
  95.                 websocket=new WebSocket(wsurl);  
  96.   
  97.                 /******** 连接建立||发起webSocket连接 ********/  
  98.                 websocket.onopen = function(evevt){  
  99.                     console.log("Connected to WebSocket server.");  
  100.                     /******** 监听ready状态码 ********/  
  101.                     console.log('websocket.readyState:'+websocket.readyState);  
  102.                     /*********************************************************  
  103.                       值为0值表示该连接尚未建立  
  104.                       值为1表示连接建立和沟通是可能的  
  105.                       值为2表示连接是通过将结束握手  
  106.                       值为3表示连接已关闭或无法打开  
  107.                     *********************************************************/  
  108.                     /******** 判断状态码为1则连接成功即可正常通信********/  
  109.                     if(websocket.readyState==1){  
  110.                         $('.show-area').append('<p class="bg-info message"><i class="glyphicon glyphicon-info-sign"></i>Connected to WebSocket server!</p>');  
  111.                     }  
  112.                 }  
  113.                 //收到消息  
  114.                 websocket.onmessage = function(event) {  
  115.                     var msg = JSON.parse(event.data); //解析收到的json消息数据  
  116.                     console.log("\n--->>message:\n"+event.data);  
  117.   
  118.                     var type = msg.type; // 消息类型  
  119.                     var umsg = msg.message; //消息文本  
  120.                     var uname = msg.name; //发送人  
  121.                     i++;  
  122.                     if(type == 'usermsg'){  
  123.                         $('.show-area').append('<p class="bg-success message"><i class="glyphicon glyphicon-user"></i><a name="'+i+'"></a><span class="label label-primary">'+uname+' say: </span>'+umsg+'</p>');  
  124.                     }  
  125.                     if(type == 'system'){  
  126.                         $('.show-area').append('<p class="bg-warning message"><a name="'+i+'"></a><i class="glyphicon glyphicon-info-sign"></i>'+umsg+'</p>');  
  127.                     }  
  128.                       
  129.                     $('#message').val('');  
  130.                     window.location.hash = '#'+i;  
  131.                 }  
  132.   
  133.                 //发生错误  
  134.                 websocket.onerror = function(event){  
  135.                     i++;  
  136.                     console.log("Connected to WebSocket server error");  
  137.                     $('.show-area').append('<p class="bg-danger message"><a name="'+i+'"></a><i class="glyphicon glyphicon-info-sign"></i>Connect to WebSocket server error.</p>');  
  138.                     window.location.hash = '#'+i;  
  139.                 }  
  140.   
  141.                 //连接关闭  
  142.                 websocket.onclose = function(event){  
  143.                     i++;  
  144.                     console.log('websocket Connection Closed. ');  
  145.                     $('.show-area').append('<p class="bg-warning message"><a name="'+i+'"></a><i class="glyphicon glyphicon-info-sign"></i>websocket Connection Closed.</p>');  
  146.                     window.location.hash = '#'+i;  
  147.                 }  
  148.   
  149.                 function send(){  
  150.                     var name = $('#name').val();  
  151.                     var message = $('#message').val();  
  152.                     if(!name){  
  153.                         alert('请输入用户名!');  
  154.                         return false;  
  155.                     }  
  156.                     if(!message){  
  157.                         alert('发送消息不能为空!');  
  158.                         return false;  
  159.                     }  
  160.                     var msg = {  
  161.                         message: message,  
  162.                         name: name  
  163.                     };  
  164.                     try{    
  165.                         websocket.send(JSON.stringify(msg));  
  166.                     } catch(ex) {    
  167.                         console.log(ex);  
  168.                     }    
  169.                 }  
  170.   
  171.                 //按下enter键发送消息  
  172.                 $(window).keydown(function(event){  
  173.                     if(event.keyCode == 13){  
  174.                         console.log('user enter');  
  175.                         send();  
  176.                     }  
  177.                 });  
  178.   
  179.                 //点发送按钮发送消息  
  180.                 $('.send').bind('click',function(){  
  181.                     send();  
  182.                 });  
  183.                   
  184.             }  
  185.             else{  
  186.                 alert('该浏览器不支持web socket');  
  187.             }  
  188.   
  189.         });      
  190.         </script>          
  191.     </body>  
  192. </html>  

后端PHP代码部分:

PHP代码
  1. 2.php code:  
  2. <?php  
  3. $host = '127.0.0.1';  
  4. $port = '9090';  
  5. $null = NULL;  
  6.   
  7. //创建tcp socket  
  8. $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);  
  9. socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, 1);  
  10. socket_bind($socket, 0, $port);  
  11.   
  12. //监听端口  
  13. socket_listen($socket);  
  14.   
  15. //连接的client socket 列表  
  16. $clients = array($socket);  
  17.   
  18. //设置一个死循环,用来监听连接 ,状态  
  19. while (true) {  
  20.       
  21.     $changed = $clients;  
  22.     socket_select($changed, $null, $null, 0, 10);  
  23.       
  24.     //如果有新的连接  
  25.     if (in_array($socket, $changed)) {  
  26.         //接受并加入新的socket连接  
  27.         $socket_new = socket_accept($socket);  
  28.         $clients[] = $socket_new;  
  29.           
  30.         //通过socket获取数据执行handshake  
  31.         $header = socket_read($socket_new, 1024);  
  32.         perform_handshaking($header, $socket_new, $host, $port);  
  33.           
  34.         //获取client ip 编码json数据,并发送通知  
  35.         socket_getpeername($socket_new, $ip);  
  36.         $response = mask(json_encode(array('type'=>'system', 'message'=>$ip.' connected')));  
  37.         send_message($response);  
  38.         $found_socket = array_search($socket, $changed);  
  39.         unset($changed[$found_socket]);  
  40.     }  
  41.       
  42.     //轮询 每个client socket 连接  
  43.     foreach ($changed as $changed_socket) {      
  44.           
  45.         //如果有client数据发送过来  
  46.         while(socket_recv($changed_socket, $buf, 1024, 0) >= 1)  
  47.         {  
  48.             //解码发送过来的数据  
  49.             $received_text = unmask($buf);  
  50.             $tst_msg = json_decode($received_text);    
  51.             $user_name = $tst_msg->name;  
  52.             $user_message = $tst_msg->message;  
  53.               
  54.             //把消息发送回所有连接的 client 上去  
  55.             $response_text = mask(json_encode(array('type'=>'usermsg', 'name'=>$user_name, 'message'=>$user_message)));  
  56.             send_message($response_text);  
  57.             break 2;  
  58.         }  
  59.           
  60.         //检查offline的client  
  61.         $buf = @socket_read($changed_socket, 1024, PHP_NORMAL_READ);  
  62.         if ($buf === false) {  
  63.             $found_socket = array_search($changed_socket, $clients);  
  64.             socket_getpeername($changed_socket, $ip);  
  65.             unset($clients[$found_socket]);  
  66.             $response = mask(json_encode(array('type'=>'system', 'message'=>$ip.' disconnected')));  
  67.             send_message($response);  
  68.         }  
  69.     }  
  70. }  
  71. // 关闭监听的socket  
  72. socket_close($sock);  
  73.   
  74. //发送消息的方法  
  75. function send_message($msg)  
  76. {  
  77.     global $clients;  
  78.     foreach($clients as $changed_socket)  
  79.     {  
  80.         @socket_write($changed_socket,$msg,strlen($msg));  
  81.     }  
  82.     return true;  
  83. }  
  84.   
  85.   
  86. //解码数据  
  87. function unmask($text) {  
  88.     $length = ord($text[1]) & 127;  
  89.     if($length == 126) {  
  90.         $masks = substr($text, 4, 4);  
  91.         $data = substr($text, 8);  
  92.     }  
  93.     elseif($length == 127) {  
  94.         $masks = substr($text, 10, 4);  
  95.         $data = substr($text, 14);  
  96.     }  
  97.     else {  
  98.         $masks = substr($text, 2, 4);  
  99.         $data = substr($text, 6);  
  100.     }  
  101.     $text = "";  
  102.     for ($i = 0; $i < strlen($data); ++$i) {  
  103.         $text .= $data[$i] ^ $masks[$i%4];  
  104.     }  
  105.     return $text;  
  106. }  
  107.   
  108. //编码数据  
  109. function mask($text)  
  110. {  
  111.     $b1 = 0x80 | (0x1 & 0x0f);  
  112.     $length = strlen($text);  
  113.       
  114.     if($length <= 125)  
  115.         $header = pack('CC', $b1, $length);  
  116.     elseif($length > 125 && $length < 65536)  
  117.         $header = pack('CCn', $b1, 126, $length);  
  118.     elseif($length >= 65536)  
  119.         $header = pack('CCNN', $b1, 127, $length);  
  120.     return $header.$text;  
  121. }  
  122.   
  123. //握手的逻辑  
  124. function perform_handshaking($receved_header,$client_conn, $host, $port)  
  125. {  
  126.     $headers = array();  
  127.     $lines = preg_split("/\r\n/", $receved_header);  
  128.     foreach($lines as $line)  
  129.     {  
  130.         $line = chop($line);  
  131.         if(preg_match('/\A(\S+): (.*)\z/', $line, $matches))  
  132.         {  
  133.             $headers[$matches[1]] = $matches[2];  
  134.         }  
  135.     }  
  136.   
  137.     $secKey = $headers['Sec-WebSocket-Key'];  
  138.     $secAccept = base64_encode(pack('H*', sha1($secKey . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11')));  
  139.     $upgrade  = "HTTP/1.1 101 Web Socket Protocol Handshake\r\n" .  
  140.     "Upgrade: websocket\r\n" .  
  141.     "Connection: Upgrade\r\n" .  
  142.     "WebSocket-Origin: $host\r\n" .  
  143.     "WebSocket-Location: ws://$host:$port/demo/shout.php\r\n".  
  144.     "Sec-WebSocket-Accept:$secAccept\r\n\r\n";  
  145.     socket_write($client_conn,$upgrade,strlen($upgrade));  
  146. }  
Tags: ,
H5/JS/CSS | 评论(0) | 引用(0) | 阅读(2303)