<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      swoole+websocket+redis實現一對一聊天

      如同web端的QQ和微信一樣,這是一個web端的聊天程序。

      環境:ubuntu + php + swoole擴展 + redis + mysql

      Redis 實現每個連接websocket的服務都唯一綁定一個用戶。通過 用戶賬號 = websocket fd 存到redis中。

      Mysql 實現離線消息池。如果一個用戶不在線,則其他用戶發送給他的消息暫時存儲在mysql。待該用戶上線時,再從離線消息池取出發送。

      具體參考代碼和相應注釋:

      服務端代碼:

      <?php
      $server = new swoole_websocket_server("0.0.0.0", 9052);
      $redis = new Redis();
      $redis->connect('127.0.0.1', 6379);
      $db = new mysqli('127.0.0.1', 'test', 'test', 'thinkphp5');
      
      $server->on('open', function (swoole_websocket_server $server, $request) {
          echo "server: handshake success with fd{$request->fd}\n";//$request->fd 是客戶端id
      });
      
      $server->on('message', function (swoole_websocket_server $server, $frame) {
          $data = json_decode($frame->data,true); 
          if($data['flag'] == 'init'){
              //用戶剛連接的時候初始化,每個用戶登錄時記錄該用戶對應的fd
              $GLOBALS['redis']->set($data['from'], $frame->fd);
              //處理發給該用戶的離線消息
              $sql = "SELECT `from`,content FROM thinkphp5.app_offline WHERE `to`='{$data['from']}' AND `from`='{$data['to']}' AND `status`='0' ORDER BY addtime ASC;";
              if ($result = $GLOBALS['db']->query($sql)) {
                  $re = array();
                  while ($row = $result->fetch_assoc()) {
                      array_push($re, $row);
                  }
                  $result->free();
                  foreach($re as $content){
                      $content = json_encode($content);
                      $server->push($frame->fd , $content);
                  }
                  //設置消息池中的消息為已發送
                  $sql = "UPDATE thinkphp5.app_offline SET `status`=1 WHERE `to`='{$data['from']}' AND `from`='{$data['to']}';";
                  $GLOBALS['db']->query($sql);
              }
          }else if($data['flag'] == 'msg'){
              //非初始化的信息發送,一對一聊天,根據每個用戶對應的fd發給特定用戶
              $tofd = $GLOBALS['redis']->get($data['to']); //消息要發給誰
              $fds = []; //所有在線的用戶(打開聊天窗口的用戶)
              foreach($server->connections as $fd){
                  array_push($fds, $fd);
              }
              if(in_array($tofd,$fds)){
                  $tmp['from'] = $data['from']; //消息來自于誰
                  $tmp['content']  = $data['content']; //消息內容
                  $re = json_encode($tmp);
                  $server->push($tofd , $re);
              }else{
                  //該玩家不在線(不在聊天室內),將信息發送到離線消息池
                  $time = time();
                  $sql = "INSERT INTO thinkphp5.app_offline (`to`,`from`,`content`,`status`,`addtime`) VALUES ('{$data['to']}','{$data['from']}','{$data['content']}','0','{$time}');";
                  $GLOBALS['db']->query($sql);
              }
          }else if($data['flag'] == 'group'){
              //todo 群聊
              
          }else if($data['flag'] == 'all'){
              //全站廣播
              foreach($server->connections as $fd){
                  $server->push($fd , $data);
              }
          }  
      });
      
      $server->on('close', function ($ser, $fd) {
          echo "client {$fd} closed\n";
      });
      
      $server->start();

       

      客戶端代碼:

      <!DOCTYPE html>
      <html>
      <head>
          <title>XST-app</title>
          <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
          <meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7" />
          <meta name="viewport" content="width=device-width, initial-scale=0.0, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0" />
          <meta name="keywords" content="test" />
          <meta name="description" content="test" />
          <meta name="author" content="XST-APP" />
          <meta content="yes" name="apple-mobile-web-app-capable" />
          <meta content="black" name="apple-mobile-web-app-status-bar-style" />
          <meta content="telephone=no" name="format-detection" />
        <style type="text/css">
          body{background:url(/static/images/yuyin_bg.jpg);background-size:100%;}
          @media all and (min-width: 640px) {
              body,html,.wenwen-footer,.speak_window{width:640px!important;margin:0 auto}
              .speak_window,.wenwen-footer{left:50%!important;margin-left:-320px}
          }
          input,button{outline:none;}
          .wenwen-footer{width:100%;position:fixed;bottom:-5px;left:0;background:#fff;padding:3%;border-top:solid 1px #ddd;box-sizing:border-box;}
          .wenwen_btn,.wenwen_help{width:15%;text-align:center;}
          .wenwen_btn img,.wenwen_help img{height:40px;}
          .wenwen_text{height:40px;border-radius:5px;border:solid 1px #636162;box-sizing:border-box;width:66%;text-align:center;overflow:hidden;margin-left:2%;}
          .circle-button{padding:0 5px;}
          .wenwen_text .circle-button{font-size:14px;color:#666;line-height:38px;}
          .write_box{background:#fff;width:100%;height:40px;line-height:40px;}
          .write_box input{height:40px;padding:0 5px;line-height:40px;width:100%;box-sizing:border-box;border:0;}
          .wenwen_help button{width:95%;background:#42929d;color:#fff;border-radius:5px;border:0;height:40px;}
          #wenwen{height:100%;}
          .speak_window{overflow-y:scroll;height:100%;width:100%;position:fixed;top:50px;left:0;}
          .speak_box{margin-bottom:70px;padding:10px;}
          .question,.answer{margin-bottom:1rem;}
          .question{text-align:right;}
          .question>div{display:inline-block;}
          .left{float:left;}
          .right{float:right;}
          .clear{clear:both;}
          .heard_img{height:60px;width:60px;border-radius:5px;overflow:hidden;background:#ddd;}
          .heard_img img{width:100%;height:100%}
          .question_text,.answer_text{box-sizing:border-box;position:relative;display:table-cell;min-height:60px;}
          .question_text{padding-right:20px;}
          .answer_text{padding-left:20px;}
          .question_text p,.answer_text p{border-radius:10px;padding:.5rem;margin:0;font-size:14px;line-height:28px;box-sizing:border-box;vertical-align:middle;display:table-cell;height:30px;word-wrap:break-word;}
          .answer_text p{background:#fff;}
          .question_text p{background:#42929d;color:#fff;text-align:left;}
          .question_text i,.answer_text i{width:0;height:0;border-top:5px solid transparent;border-bottom:5px solid transparent;position:absolute;top:25px;}
          .answer_text i{border-right:10px solid #fff;left:10px;}
          .question_text i{border-left:10px solid #42929d;right:10px;}
          .answer_text p a{color:#42929d;display:inline-block;}
          .write_list{position:absolute;left:0;width:100%;background:#fff;border-top:solid 1px #ddd;padding:5px;line-height:30px;}
        </style>
      </head>
      
      <body>
      <div id="header" class="head">
              <div class="wrap">
                      <i class="menu_back"><a href="javascript:history.go(-1);"></a></i>
                      <div class="title">
                              <span class="title_d"><p>與 {$tonickname} 的聊天</p></span>
                              <div class="clear"></div>
                      </div>
                      <!--i class="menu_share"></i-->
              </div>
      </div>
      <input type="hidden" name="myemail" id="myemail" value="{$myemail}" />
      <input type="hidden" name="mynickname" id="mynickname" value="{$mynickname}" />
      <input type="hidden" name="myavatar" id="myavatar" value="{$myavatar}" />
      <input type="hidden" name="toemail" id="toemail" value="{$toemail}" />
      <input type="hidden" name="tonickname" id="tonickname" value="{$tonickname}" />
      <input type="hidden" name="toavatar" id="toavatar" value="{$toavatar}" />
      
      <!-- 對話內容 -->
      <div class="speak_window">
          <div class="speak_box">
      
          </div>
      </div>
      
      <!-- 內容輸入-->
      <div class="wenwen-footer">
          <div class="wenwen_btn left"><img src="/static/images/jp_btn.png"></div>
          <div class="wenwen_text left">
              <div class="write_box"><input type="text" class="left" onKeyUp="keyup()" maxlength="100" placeholder="請輸入信息(100字以內)..." /></div>   
          </div>
          <div class="wenwen_help right">
                  <button onClick="send()" class="right">發送</button>
          </div>
          <div style="opacity:0;" class="clear"></div>
      </div>
      
      <script type="text/javascript">
          if ("WebSocket" in window){
              var ws = new WebSocket("ws://192.168.0.1:9052");
              ws.onopen = function(){
                  console.log("握手成功");
                  var myemail = $("#myemail").val();
                  var toemail = $("#toemail").val();
                  var arr = {"flag":"init","from":myemail,"to":toemail};
                  var str = JSON.stringify(arr);
                  ws.send(str);
              };
              ws.onmessage = function(e){
                  var toemail = $("#toemail").val();
                  var toavatar = $("#toavatar").val();
                  var obj = JSON.parse(e.data);
                  console.log(e.data);
                  //但同時與兩個人聊天時,可能兩個人的消息都會出現在當前窗口,所以此處加個判斷,此窗口只接收當前聊天對象的消息,其他則忽略
                  if(obj.from === toemail){
                      var ans  = '<div class="answer"><div class="heard_img left"><img src="'+toavatar+'"></div>';
                          ans += '<div class="answer_text"><p>'+obj.content+'</p><i></i>';
                          ans += '</div></div>';
                          $('.speak_box').append(ans);
                          for_bottom();
                  }
              };
              ws.onerror = function(){
                  console.log("error");
                  var  str  = '<div class="question">';
                  str += '<div class="heard_img right"><img src="/static/images/xitong.jpg"></div>';
                  str += '<div class="question_text clear"><p>聊天服務器出現異常,暫時無法提供服務。</p><i></i>';
                  str += '</div></div>';
                  $('.speak_box').append(str);
                  $('.write_box input').val('');
                  $('.write_box input').focus();
                  autoWidth();
                  for_bottom();
              };
      
              function send() {
                  var content = $('.write_box input').val();
              if(content === ''){
                  alert('請輸入消息!');
                  $('.write_box input').focus();
              }else{
                      var toemail = $("#toemail").val();
                      var myemail = $("#myemail").val();
                      var myavatar = $("#myavatar").val();
                      var arr = {"flag":"msg","to":toemail,"from":myemail,"content":content};
                      var msg = JSON.stringify(arr);
                      console.log(msg);
                      ws.send(msg);    
                      var  str  = '<div class="question">';
                      str += '<div class="heard_img right"><img src="'+myavatar+'"></div>';
                      str += '<div class="question_text clear"><p>'+content+'</p><i></i>';
                      str += '</div></div>';
                  $('.speak_box').append(str);
                  $('.write_box input').val('');
                  $('.write_box input').focus();
                  autoWidth();
                  for_bottom();
                  }
              
              }
          }else{
              alert("您的瀏覽器不支持 WebSocket!");
          }
                 
          function for_bottom(){
          var speak_height = $('.speak_box').height();
          $('.speak_box,.speak_window').animate({scrollTop:speak_height},500);
          }
          
          function autoWidth(){
          $('.question_text').css('max-width',$('.question').width()-60);
          }
          
          autoWidth();
          
      </script>
      
      </body>
      </html>
      
                

       

      數據表結構:

      CREATE TABLE `app_offline` (
        `id` int(11) NOT NULL AUTO_INCREMENT,
        `from` varchar(50) DEFAULT NULL COMMENT '離線發送方',
        `to` varchar(50) DEFAULT NULL COMMENT '離線接收方',
        `content` varchar(1000) DEFAULT NULL COMMENT '發送的離線內容',
        `status` tinyint(4) DEFAULT '0' COMMENT '發送狀態:0-未發送,1-已發送',
        `addtime` int(11) DEFAULT NULL COMMENT '發送方發送時間',
        PRIMARY KEY (`id`)
      ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8

       

      具體效果:

           

      posted @ 2018-09-05 19:01  喜歡哲學的猴子  閱讀(4664)  評論(1)    收藏  舉報
      主站蜘蛛池模板: 平邑县| 无码中文字幕人妻在线一区 | 国产精品福利一区二区久久| 一本一本久久a久久精品综合 | 2020年最新国产精品正在播放 | 少妇人妻真实偷人精品| 色色97| 欧美福利电影A在线播放| 国产大学生自拍三级视频| 国产精品久久久久aaaa| 少妇高潮喷水正在播放| 亚洲精品一二三四区| 宅男噜噜噜66网站高清| 托里县| 少妇被日自拍黄色三级网络| 久久精品国产蜜臀av| 久久天堂无码av网站| 国产色无码精品视频免费| 免费人成在线观看网站| 国产精品一久久香蕉产线看| 元氏县| 日本人妻巨大乳挤奶水免费 | 精品人妻少妇一区二区三区| 18禁免费无码无遮挡网站 | 国产精品久久久久影院亚瑟| 碌曲县| 国产精品99久久久久久www | 国产免费一区二区三区在线观看| 99久久久无码国产麻豆| 亚洲国产一区二区精品专| 久久视频这里只精品| 国产爆乳无码视频在线观看3| 亚洲av永久无码精品网站| 孕妇怀孕高潮潮喷视频孕妇| 色偷偷亚洲女人天堂观看| 26uuu另类亚洲欧美日本| 欧美高清精品一区二区 | 美女人妻激情乱人伦| 亚洲精品国产福利一区二区| 国产成人综合色视频精品| 亚洲av精选一区二区|