zoukankan      html  css  js  c++  java
  • 在线客服~~

    SOCKET流程:
    1:服务器端开启端口等待客户端建立TCP连接
    2:客户端建立TCP四次握手协议TCP连接 (TCP的四次握手连接全部被封装好的代码处理)


    3: 客户端发起WS协议
    4:服务器判断 客户端发送消息内容即是WS协议请求
    5:服务器端返回WS连接协议


    6:双方建立WS长连接
    7:此时客户端可以接受服务器推送过来的内容(接受WS加密内容),也可以向服务器端发送内容(服务端解码WS加密内容)。

    双方关闭SOCKET

    先看下效果~~有待加强

    (1)要先链接啊,链接成功后才可以发送消息

         

    (2)下面就是代码的生成了

    先要编写页面,先不写链接(界面中的各个按钮)

    <textarea class="log" style=" 100%; height: 500px;">
    =======websocket======
    </textarea>
    <input type="button" value="连接" onClick="link()"> <input type="button" value="断开" onClick="dis()"> <input type="text" id="text"> <input type="button" value="发送" onClick="send()">

    (3)编写链接功能

    <?php
    class WS {
    	//存储连接资源
    	private $clients;
    	//主线端口
    	private $master;
    	//客户资源
    	private $user;
    	private $ip;
    	private $port;
    	
    	public function __construct($ip="127.0.0.1",$port = 3432) {
    		$this->ip    = $ip;
    		$this->port = $port;
    		error_reporting(E_ALL);
                 set_time_limit(0);
                 ob_implicit_flush();
    		$this->master = $this->WebSocket($this->ip,$this->port);
    		$this->clients = array('s'=>$this->master);
    	}
    	
    	//建立服务器端连接
    	function WebSocket($address,$port){
                $server = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
                socket_set_option($server, SOL_SOCKET, SO_REUSEADDR, 1);
                socket_bind($server, $address, $port);
                socket_listen($server);
                $this->log('开始监听: '.$address.' : '.$port);
                return $server;
            }
    	
    	
    	function run() {
    		while (true) {
    		    $read = $this->clients;
    			//var_dump($read);exit;
    			@socket_select($read, $write = NULL, $except = NULL, null);
    			/*if ( < 1) {
    				//如果没有连接跳出
    				continue;
    			}*/
    			
    			foreach($read as $r) {
    				
    				if($r == $this->master) { 
    				    //建立四步握手协议
    				   //有客户端新进连接进来
    				   //判断服务器socket是否被激活
    				   //接受客户端,并将他添加到客户数组
    				   $this->clients[] = $newCli = socket_accept($this->master);
    				   $this->user[] = array(
    				        'handle'=>false,
    						'socket'=>$newCli
    				   );
    				   
    				   $k = $this->search($newCli);
    				   echo "NUM = ".$k."
    "; //服务器端输出当前连接的 用户ID,既是数组K
    				} else { 
    				    //已有的连接发来的消息所有的客户数据读取
    					// 读到换行符或1024字节
                       // 虽然客户端断开连接时显示错误,所以沉默错误消息
    				   $buffer = '';
    				   
                       $data = socket_recv($r,$buffer ,2048,0);
    				   
    				   // 检查客户端是否断开连接
                       if ($data < 7) {
    
                            // 删除客户端为客户数组
    						$k = $this->search($r);
    						echo "NO---".$k;
                            $this->close($r);
                            // continue to the next client to read from
                            continue;
                        } 
    					
    					$k = $this->search($r);
    					
    					if($this->user[$k]['handle'] == false) { //只是进行了四步握手协议,此时浏览器发来WS协议请求
    					    echo "$k=".$k."
    ";
    						$this->handshake($k,$buffer); //返回WS协议应答
    						
    					} else { //已经建立WS协议,获取通过WS发来的消息
    						$str = $this->uncode($buffer);
    						echo "
    ".$str;
    						$this->sendAll($str,$r);  //发送消息广播
    					}
    				}
    			}
    		}
    	}
    	
    	//WebSocket 握手协议
    	function handshake($k,$buffer){
    		//获取KEY及生成新的KEY
    		$buf  = substr($buffer,strpos($buffer,'Sec-WebSocket-Key:')+18);
    		$key  = trim(substr($buf,0,strpos($buf,"
    ")));
    		$new_key = base64_encode(sha1($key."258EAFA5-E914-47DA-95CA-C5AB0DC85B11",true));
    		
    		//返回HTTP协议
    		$new_message = "HTTP/1.1 101 Switching Protocols
    ";
    		$new_message .= "Upgrade: websocket
    ";
    		$new_message .= "Sec-WebSocket-Version: 13
    ";
    		$new_message .= "Connection: Upgrade
    ";
    		$new_message .= "Sec-WebSocket-Accept: " . $new_key . "
    
    ";
    		socket_write($this->user[$k]['socket'],$new_message,strlen($new_message));
    		$this->user[$k]['handle']=true;
    		return true;
    		
       }
    	
    	//群发消息
    	function sendAll($str,$socket) {
    		// 把这所有的客户在客户数组(除了第一个,这是一个监听套接字)
                    foreach ($this->clients as $send_sock) {
                   
                        // 如果这个资源等于 服务器或是等于它自己则跳过,
                        if ($send_sock == $this->master || $send_sock == $socket)
                            continue;
                       
                        //发送给其他用户一个信息
    					$data = $this->code($str);
                        socket_write($send_sock, $data,strlen($data));
                       
                    }
    		
    	}
    	
    	
    	
    	
    	//查找用户
    	function search($sign) {//通过标示遍历获取id
    		foreach ($this->user as $k=>$v){
    		    if($sign == $v['socket'])
    		        return $k;
    		}
    		return false;
        }
    	
    	
    	//断开连接
    	function close($sign){//通过标示断开连接
            $k = array_search($sign, $this->clients);
            socket_close($sign);  //断开的连接需要在服务器端手动关闭
            unset($this->clients[$k]);
            unset($this->user[$k]);
        }
    	//信息解码
    	function uncode($str){
    		$mask = array();  
    		$data = '';  
    		$msg = unpack('H*',$str);  
    		$head = substr($msg[1],0,2);  
    		if (hexdec($head{1}) === 8) {  
    		  $data = false;  
    		}else if (hexdec($head{1}) === 1){  
    		  $mask[] = hexdec(substr($msg[1],4,2));
    		  $mask[] = hexdec(substr($msg[1],6,2));
    		  $mask[] = hexdec(substr($msg[1],8,2));
    		  $mask[] = hexdec(substr($msg[1],10,2));
    		  $s = 12;  
    		  $e = strlen($msg[1])-2;  
    		  $n = 0;  
    		  for ($i=$s; $i<= $e; $i+= 2) {  
    			$data .= chr($mask[$n%4]^hexdec(substr($msg[1],$i,2)));  
    			$n++;  
    		  }  
    		}  
    		return $data;
        }
        //信息加码
        function code($msg){
    		  $msg = preg_replace(array('/
    $/','/
    $/','/
    $/',), '', $msg);
    		  $frame = array();  
    		  $frame[0] = '81';  
    		  $len = strlen($msg);  
    		  $frame[1] = $len<16?'0'.dechex($len):dechex($len);
    		  $frame[2] = $this->ord_hex($msg);
    		  $data = implode('',$frame);
    		  return pack("H*", $data);
        }
    	
    	
        function ord_hex($data)  {  
    		  $msg = '';  
    		  $l = strlen($data);  
    		  for ($i= 0; $i<$l; $i++) {  
    			$msg .= dechex(ord($data{$i}));  
    		  }  
    		  return $msg;  
        }
    	
    	
    	function log($t){//控制台输出
          
            $t=$t."
    ";
            fwrite(STDOUT, iconv('utf-8','gbk//IGNORE',$t));
          
        }
    	
    	
    }
    
    $ws = new WS("127.0.0.1",8000);
    $ws->run();
    

      

    (4)写js(就是单击链接按钮和断开按钮出现的字)记得要引入jq

    function link(){
        var url='ws://127.0.0.1:8000';
        socket=new WebSocket(url);
        socket.onopen=function(){
            log('连接成功');
    	}
    	
        socket.onmessage=function(msg) {
            log('获得消息:'+msg.data);
    	    console.log(msg);
        }
    	
        socket.onclose=function(){log('断开连接')}
    }
    
    function dis(){
      socket.close();
      socket=null;
    }
    
    function log(var1){
      $('.log').append(var1+"
    ");
    }
    
    function send(){
      socket.send($('#text').val());
    }
    

    这样,简单的在线客服就完成了  

    在运行的时候要先运行ws,这样才能链接成功

  • 相关阅读:
    mysql 用户管理 权限控制
    微信开发--自动回复图片
    MySQL要导出成excel的方法
    mysql 和excel相互转换
    MYSQL 函数复习
    查找算法
    PySpider的安装
    在Windows下安装scrapy
    chromedriver安装
    Sublime Text 3中配置Python3的开发环境
  • 原文地址:https://www.cnblogs.com/nuanai/p/6396646.html
Copyright © 2011-2022 走看看