websocket+php+socket聊天室

来源:互联网 发布:python 支付宝 api 编辑:程序博客网 时间:2024/06/05 00:54

客户端(聊天前端页面):

<!DOCTYPE html><html><head>  <title>mychat_socket</title>  <meta charset="utf-8">  <meta name="viewport" content="width=device-width,initial-scale=1, maximum-scale=1, user-scalable=no">  <link href="https://cdn.bootcss.com/bootstrap/3.3.2/css/bootstrap.min.css" rel="stylesheet">  <style type="text/css">    <!--    html, body {      min-height: 100%;    }    body {      margin: 0;      padding: 0;      width: 100%;      font-family: "Microsoft Yahei", sans-serif, Arial;    }    .container {      text-align: center;    }    .title {      font-size: 16px;      color: rgba(0, 0, 0, 0.3);      position: fixed;      line-height: 30px;      height: 30px;      left: 0px;      right: 0px;      background-color: white;    }    .content {      background-color: #f1f1f1;      border-top-left-radius: 6px;      border-top-right-radius: 6px;      margin-top: 30px;    }    .content .show-area {      text-align: left;      padding-top: 8px;      padding-bottom: 168px;    }    .content .show-area .message {      width: 70%;      padding: 5px;      word-wrap: break-word;      word-break: normal;    }    .content .write-area {      position: fixed;      bottom: 0px;      right: 0px;      left: 0px;      background-color: #f1f1f1;      z-index: 10;      width: 100%;      height: 160px;      border-top: 1px solid #d8d8d8;    }    .content .write-area .send {      position: relative;      top: -28px;      height: 28px;      border-top-left-radius: 55px;      border-top-right-radius: 55px;    }    .content .write-area #name {      position: relative;      top: -20px;      line-height: 28px;      font-size: 13px;    }    -->  </style></head><body><div class="container">  <div class="title">简易聊天demo</div>  <div class="content">    <div class="show-area"></div>    <div class="write-area">      <div>        <button class="btn btn-default send">发送</button>      </div>      <div><input name="name" id="name" type="text" placeholder="input your name"></div>      <div>        <textarea name="message" id="message" cols="38" rows="4" placeholder="input your message..."></textarea>      </div>    </div>  </div></div><script src="http://libs.baidu.com/jquery/1.9.1/jquery.min.js"></script><script src="https://cdn.bootcss.com/bootstrap/3.3.2/js/bootstrap.min.js"></script><script>  $(function(){    var wsurl = 'ws://127.0.0.1:9505/websocket/server.php';    var websocket;    var i = 0;    if(window.WebSocket){      websocket = new WebSocket(wsurl);      //连接建立      websocket.onopen = function(evevt){        console.log("Connected to WebSocket server.");        $('.show-area').append('<p class="bg-info message"><i class="glyphicon glyphicon-info-sign"></i>Connected to WebSocket server!</p>');      }      //收到消息      websocket.onmessage = function(event){        var msg = JSON.parse(event.data); //解析收到的json消息数据        var type = msg.type; // 消息类型        var umsg = msg.message; //消息文本        var uname = msg.name; //发送人        i++;        if(type == 'usermsg'){          $('.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>');        }        if(type == 'system'){          $('.show-area').append('<p class="bg-warning message"><a name="' + i + '"></a><i class="glyphicon glyphicon-info-sign"></i>' + umsg + '</p>');        }        $('#message').val('');        window.location.hash = '#' + i;      }      //发生错误      websocket.onerror = function(event){        i++;        console.log("Connected to WebSocket server error");        $('.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>');        window.location.hash = '#' + i;      }      //连接关闭      websocket.onclose = function(event){        i++;        console.log('websocket Connection Closed. ');        $('.show-area').append('<p class="bg-warning message"><a name="' + i + '"></a><i class="glyphicon glyphicon-info-sign"></i>websocket Connection Closed.</p>');        window.location.hash = '#' + i;      }      function send(){        var name = $('#name').val();        var message = $('#message').val();        if(!name){          alert('请输入用户名!');          return false;        }        if(!message){          alert('发送消息不能为空!');          return false;        }        var msg = {          message: message,          name   : name        };        try{          websocket.send(JSON.stringify(msg));        }        catch(ex){          console.log(ex);        }      }      //按下enter键发送消息      $(window).keydown(function(event){        if(event.keyCode == 13){          console.log('user enter');          send();        }      });      //点发送按钮发送消息      $('.send').bind('click', function(){        send();      });    }else{      alert('该浏览器不支持web socket');    }  });</script></body></html>


服务端(php+socket):


<?php$host = '127.0.0.1';$port = '9505';$null = NULL;//创建tcp socket$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, 1);socket_bind($socket, 0, $port);//监听端口socket_listen($socket);//连接的client socket 列表$clients = array($socket);//设置一个死循环,用来监听连接 ,状态while(true){    $changed = $clients;    socket_select($changed, $null, $null, 0, 10);    //如果有新的连接    if(in_array($socket, $changed)){        //接受并加入新的socket连接        $socket_new = socket_accept($socket);        $clients[]  = $socket_new;        //通过socket获取数据执行handshake        $header = socket_read($socket_new, 1024);        perform_handshaking($header, $socket_new, $host, $port);        //获取client ip 编码json数据,并发送通知        socket_getpeername($socket_new, $ip);        $response = mask(json_encode(array('type' => 'system', 'message' => $ip . ' connected')));        send_message($response);        $found_socket = array_search($socket, $changed);        unset($changed[$found_socket]);    }    //轮询 每个client socket 连接    foreach($changed as $changed_socket){        //如果有client数据发送过来        while(socket_recv($changed_socket, $buf, 1024, 0) >= 1){            //解码发送过来的数据            $received_text = unmask($buf);            $tst_msg       = json_decode($received_text);            $user_name     = $tst_msg->name;            $user_message  = $tst_msg->message;            //把消息发送回所有连接的 client 上去            $response_text = mask(json_encode(array(                'type'    => 'usermsg',                'name'    => $user_name,                'message' => $user_message            )));            send_message($response_text);            break 2;        }        //检查offline的client        $buf = @socket_read($changed_socket, 1024, PHP_NORMAL_READ);        if($buf === false){            $found_socket = array_search($changed_socket, $clients);            socket_getpeername($changed_socket, $ip);            unset($clients[$found_socket]);            $response = mask(json_encode(array('type' => 'system', 'message' => $ip . ' disconnected')));            send_message($response);        }    }}// 关闭监听的socketsocket_close($sock);//发送消息的方法function send_message($msg){    global $clients;    foreach($clients as $changed_socket){        @socket_write($changed_socket, $msg, strlen($msg));    }    return true;}//解码数据function unmask($text){    $length = ord($text[1]) & 127;    if($length == 126){        $masks = substr($text, 4, 4);        $data  = substr($text, 8);    }elseif($length == 127){        $masks = substr($text, 10, 4);        $data  = substr($text, 14);    }else{        $masks = substr($text, 2, 4);        $data  = substr($text, 6);    }    $text = "";    for($i = 0; $i < strlen($data); ++$i){        $text .= $data[$i] ^ $masks[$i % 4];    }    return $text;}//编码数据function mask($text){    $b1     = 0x80 | (0x1 & 0x0f);    $length = strlen($text);    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);    }    return $header . $text;}//握手的逻辑function perform_handshaking($receved_header, $client_conn, $host, $port){    $headers = array();    $lines   = preg_split("/\r\n/", $receved_header);    foreach($lines as $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));}