Node.js、Express、Socket.io 入門

jopen 9年前發布 | 22K 次閱讀 前端技術 Socket.IO

 

前言

周末斷斷續續的寫了第一個socket.ioDemo。初次socket.io是從其官網看到的,看著get started做了一遍,根據官網的Demo能提供簡單的服務端和客戶端通訊。 這個Demo的過程中用到最多的就是訂閱事件、觸發事件、廣播事件。

根據官網完成Demo后,看到下面提到了幾個問題,又繼續實現了四個功能,其它幾個還要繼續實現。

①、當有新用戶登錄或離開時廣播消息。

②、添加昵稱。我在demo中的做法是把用戶輸入的第一條消息作為昵稱。

③、發送消息時自己發送的消息不再給自己發送,其實也就是只調用廣播(socket.broadcast.emit)消息的方法即可。

④、顯示當前在線用戶和在線人數。

開發環境

node:0.12.7

express:4.13.7

socket.io:1.3.7

官網Demo中遇到的問題

①、客戶端html頁面<script src="/socket.io/socket.io.js"></script>這樣引用js代碼沒搞明白,百度搜索了一下,有人解釋說是因為express提供的框架轉化了路徑,所以你這樣做是可以引用到該js的,剛接觸應該會感到意外,但是我實驗如果你只是 引用了express 而不是 用express創建項目 的話可能還是不管用。

②、在體驗Demo并且看其他人寫的例子中發現,很多情況下客戶端和服務端觸發的事件名稱都相同,不理解這種情況他們是同一個事件嗎? 會不會產生沖突呢?

效果圖

1、系統初始化,當你打開頁面時會提示你連接至服務器,你輸入第一條消息就是昵稱。

Node.js、Express、Socket.io 入門

2、輸入昵稱,以同樣的方式再打開幾個Tab頁,輸入昵稱。

Node.js、Express、Socket.io 入門

3、兩個客戶端聊天

Node.js、Express、Socket.io 入門

Node.js、Express、Socket.io 入門

服務端實現

var express=require('express');
var app=express();
var http=require('http').Server(app);
var io=require('socket.io')(http);

app.get('/',function(req,res){
  res.sendFile(__dirname+'/index.html');
});

var onlineUserCount=0; //客戶端連接數量
var onlineUsers={}; //統計客戶端登錄用戶

io.on('connection',function(socket){
  socket.emit('open');  //通知客戶端已連接

  //構造客戶端對象
  var client={
    socket:socket,
    name:false
  }

  //監聽客戶端的chat message事件, 該事件由客戶端觸發
  //當服務端收到消息后,再把該消息播放出去,繼續觸發chat message事件, 然后在客戶端監聽chat message事件。
  socket.on('chat message',function(msg){
    console.log('chat message:'+msg);
    var obj={time:getTime()}; //構建客戶端返回的對象

    //判斷是不是第一次連接,以第一條消息作為昵稱
    if(!client.name){
      onlineUserCount++;

      client.name=msg;
      obj['text']=client.name;
      obj['author']='Sys';
      obj['type']='welcome';
      obj['onlineUserCount']=onlineUserCount;   
      socket.name=client.name; //用戶登錄后設置socket.name, 當退出時用該標識刪除該在線用戶
      if(!onlineUsers.hasOwnProperty(client.name)){
        onlineUsers[client.name]=client.name;
      }
      obj['onlineUsers']=onlineUsers; //當前在線用戶集合
      console.log(client.name+' login,當前在線人數:'+onlineUserCount);

      //返回歡迎語
      socket.emit('system',obj);  //發送給自己的消息
      //廣播新用戶已登錄
      socket.broadcast.emit('system',obj); //向其他用戶發送消息
    }else{
      //如果不是第一次聊天,則返回正常的聊天消息
      obj['text']=msg;
      obj['author']=client.name;
      obj['type']='message';
      console.log(client.name+' say:'+msg);

      socket.emit('chat message',obj); //發送給自己的消息 , 如果不想打印自己發送的消息,則注釋掉該句。
      socket.broadcast.emit('chat message',obj); //向其他用戶發送消息 

    }
    //io.emit('chat message',msg); 
  });

  socket.on('disconnect',function(){
    onlineUserCount--;

    if(onlineUsers.hasOwnProperty(socket.name)){
      delete onlineUsers[client.name];
    }

    var obj={
      time:getTime(),
      author:'Sys',
      text:client.name,
      type:'disconnect',
      onlineUserCount:onlineUserCount,
      onlineUsers:onlineUsers
    };

    //廣播用戶退出
    socket.broadcast.emit('system',obj); //用戶登錄和退出都使用system事件播報
    console.log(client.name+' disconnect,當前在線人數:'+onlineUserCount);
  });


});

http.listen(3000,function(){
  console.log('server begin...');
});

var getTime=function(){
  var date = new Date();
  return date.getHours()+":"+date.getMinutes()+":"+date.getSeconds();
}

var getColor=function(){
  var colors = ['aliceblue','antiquewhite','aqua','aquamarine','pink','red','green',
                'orange','blue','blueviolet','brown','burlywood','cadetblue'];
  return colors[Math.round(Math.random() * 10000 % colors.length)];
}


<!doctype html>
<html>
  <head>
    <title>Socket.IO chat</title>
    <style>
      * { margin: 0; padding: 0; box-sizing: border-box; }
      body { font: 13px Helvetica, Arial; }
      div { background: #000; padding: 3px; position: fixed; bottom: 0; width: 100%; }
      div input { border: 0; padding: 10px; width: 90%; margin-right: .5%; }
      div button { width: 9%; background: rgb(130, 224, 255); border: none; padding: 10px; }
      #messages { list-style-type: none; margin: 0; padding: 0; }
      #messages li { padding: 5px 10px; }
      #messages li:nth-child(odd) { background: #eee; }
      p{padding:5px 10px;}
    </style>
  </head>
  <body>
    <p id="onlineUser">在線人數:0</p>
    <ul id="messages"></ul>

    <div action="">
      <input id="m" autocomplete="off" /><button>Send</button>
    </div>
    <script src="https://cdn.socket.io/socket.io-1.2.0.js"></script>
    <script src="http://code.jquery.com/jquery-1.11.1.js"></script>
    <script type="text/javascript">
       var myName=false;

       var socket= io('http://localhost:3000');
       socket.on('open',function(){
          $('#messages').append($('<li>').text('已連接至服務器,請輸入昵稱'));
       });

       //監聽system事件,判斷welcome或者disconnect,打印系統消息
       socket.on('system',function(json){
          var sep='';
          var onlinehtml='';
          var onlineUsers=json.onlineUsers;
          for(key in onlineUsers){
            if(onlineUsers.hasOwnProperty(key)){
              onlinehtml+=sep+onlineUsers[key];
              sep='、';
            }
          }

          if(json.type==='welcome'){
            $('#messages').append($('<li>').text('Sys('+json.time+')welcome '+json.text));           
            $('#onlineUser').text('在線人數:'+json.onlineUserCount+'。在線列表:'+onlinehtml);
          }else if(json.type==='disconnect'){
            $('#messages').append($('<li>').text('Sys('+json.time+')bye '+json.text+''));     
            $('#onlineUser').text('在線人數:'+json.onlineUserCount+'。在線列表:'+onlinehtml);
          }
       });

       //監聽服務端的chat message事件,接受每一條消息
       socket.on('chat message',function(json){
        $('#messages').append($('<li>').text(json.author+'('+json.time+')'+':'+json.text));
       });


       $('#m').keydown(function(e){
          if(e.keyCode===13){
            socket.emit('chat message',$('#m').val());

            //socket.send($('#m').val());
            $('#m').val('');
            if(myName===false){
              myName=$('#m').val();
            }
          }
       })
    </script>
  </body>
</html>

總結

做這個Demo的過程中,感覺目前用到最多的就是 訂閱事件發布事件 ,然后客戶端和服務端接受相應的參數,另外一個就是服務端和客戶端通信可以完全用JSON格式傳參,的確很方便。 目前掌握的方法就是socket.emit()和socket.broadcast.emit(),還沒有搞明白emit()和send()的區分。

提供代碼下載地址: http://pan.baidu.com/s/1mgm12Rm

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!