亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Node.js websocket使用socket.io庫實現實時聊天室

 更新時間:2021年07月11日 13:11:25   作者:HaoDaWang  
這篇文章主要為大家詳細介紹了Node.js websocket使用socket.io庫實現實時聊天室,具有一定的參考價值,感興趣的小伙伴們可以參考一下

認識websocket

WebSocket protocol 是HTML5一種新的協(xié)議。它實現了瀏覽器與服務器全雙工通信(full-duple)。一開始的握手需要借助HTTP請求完成。

其實websocket 并不是很依賴Http協(xié)議,它也擁有自己的一套協(xié)議機制,但在這里我們需要利用的socket.io 需要依賴到http 。
之前用java jsp寫過一個聊天,其實實現邏輯并不難,只是大部分時間都用在UI的設計上,其實現原理就是一個基于websocket的通信,要想做一個好的聊天室,我覺得大部分精力可能更應該花在與用戶的視覺層交互上。

廢話不閑扯,我們先來看一下websocket 與傳統(tǒng)的ajax 有什么不同之處。
在之前,如果我們想要獲取到服務器更新的信息,我們可以使用ajax 輪詢來完成,然而,這樣做的弊端是增大了我們與服務器的交互次數,然而極大部分的交互都是無意義的,因為我們只是做一個詢問,如果沒有任何新的信息,我們幾乎什么都不用做,因此這樣會極大的浪費服務器資源和帶寬。
然而使用websocket 會使客戶端與服務器建立一個長連接,并且,當服務器有新消息時可以主動推送到客戶端,所以我們可以不用一次次的去詢問服務器是否有新消息,而是直接由服務器主動推送到客戶端,這樣在無消息的狀態(tài)下,客戶端不會頻繁的去請求服務器。
使用websocket 的特點在于服務器可以主動推送消息到客戶端。

使用socket.io 庫實現實時聊天

這也是這篇博文的主題之處。socket.io發(fā)布到npm 平臺上,我們可以直接用npm 來安裝到**當前**node_modules目錄下。

npm install socket.io --save 

下面我們就可以直接使用require 方法來將這個模塊引入

const socket = require("socket.io");

在創(chuàng)建此websocket 服務器之前,它需要依賴于一個已經創(chuàng)建好的http服務器。

let socketServer = socket.listen(require("http").createServer((req,resp) => {
 //返回頁面
 resp.end(require("fs").readFileSync("./socketIOTest1.html"));
}).listen(9999,"localhost",() => {console.log("listening");}));

在上述代碼中socketIOTest1.html 是在當前目錄下的一個html文件,在下面我會貼上詳細的代碼,這里先稍稍帶過。

在websocket 服務器對象中有一個connection事件,這個事件在有客戶端連接到socket服務器時被觸發(fā)。下面我們監(jiān)聽這個事件,打印一句話來表示有用戶連接。

//監(jiān)聽connection 事件
socketServer.on("connection",socket => {
 console.log("有一用戶連接");
}

上述代碼中,callback有一個參數socket為連接到客戶端的一個socket端口對象,這個對象有一個message 事件,當客戶端有消息推送到服務器時,事件循環(huán)會取出這個事件與之對應的回調函數并執(zhí)行。

socket.on("message",msg => {
 console.log(msg);
});

同時,socket對象還可以監(jiān)聽disconnect 事件,來監(jiān)聽用戶斷開連接的情況

socket.on("disconnect",() => {
 console.log("有一用戶退出連接");
});

因為我們這次的主題是要創(chuàng)建一個能夠實時聊天的聊天室,因此光有這些是不夠的,我們還需要一個能夠與用戶交互的客戶端。
下面是我的socketIOTest代碼:

<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <title>Document</title>
</head>
<body>
 <textarea name="" id="content" cols="30" rows="10" ></textarea>
 <input id="write" type="text" placeholder="please write content here">
 <input id="send" type="button" value="send" />
 <script src="./socket.io/socket.io.js"></script>
 <script>
  let send = document.getElementById("send");
  let write = document.getElementById("write");
  let content = document.getElementById("content");
  let socket = io.connect();
  //發(fā)送消息
  send.onclick = () => {
   let msg = write.value;
   // content.innerHTML = content.value + msg + "\n";
   socket.send(msg);
  };
  //接收到消息
  socket.on("message",msg => {
   console.log("從服務器接收到的消息 : " + msg);
   //更新內容
   content.innerHTML = content.value + msg + "\n";
  });
  socket.on("disconnect",() => {
   console.log("與服務器斷開連接");
  });
 </script>
</body>
</html>

在上述代碼中,我用script標簽引入了一個socket.io.js文件,這個文件不需要另外去下載,而直接引入即可,因為socket.io.js是被包含于socket.io模塊中,在上面node的程序代碼中,我們通過require方法引入了socket.io模塊,因此我們可以直接通過相對路徑訪問到它。

<script src="./socket.io/socket.io.js"></script>

接下來我們就可以在script標簽中使用如同服務端的代碼。

let socket = io.connect();

使用io.connect()方法連接到websocket服務器,該方法返回一個與連接的服務器與之對應的一個socket端口對象。

下面我們同樣監(jiān)聽message 和 disconnect事件。

//接收到消息
socket.on("message",msg => {
 console.log("從服務器接收到的消息 : " + msg);
 //更新內容
 content.innerHTML = content.value + msg + "\n";
});
socket.on("disconnect",() => {
 console.log("與服務器斷開連接");
});

為了更能突出websocket的作用,在html代碼中,我只使用了一個textarea標簽來顯示內容,兩個input標簽用于發(fā)送。
使用socket對象的send方法就能使消息在服務器與客戶端進行消息傳遞。

websocket群聊實現

現在我們假設一個場景,有u1和u2兩個用戶,同時連接到服務器,那么我們怎么使他們互相通信呢,實現的方法及其簡單。當u1連接到服務器,在服務器中,使用一個map鍵值對把與u1對應的socket對象進行保存。

//創(chuàng)建一個用于放置用戶對象的map
let map = new Map();
//用于記錄用戶數量的變量,并初始化為0
let userCount = 0;
//監(jiān)聽connection 事件
socketServer.on("connection",socket => {
 console.log("有一用戶連接");
 map.set(++userCount,socket);
 //...
}); 

與此同時,u2也連接上服務器,也由該map把與u2與之對應的socket對象進行儲存。
現在,u1點擊了send按鈕發(fā)送一條消息至服務器,服務器收到消息后遍歷map,轉發(fā)給所有socket對象,實現群聊的實時通信。

socketServer.on("connection",socket => {
 console.log("有一用戶連接");
 map.set(++userCount,socket);
 //監(jiān)聽客戶端來的信息
 socket.on("message",msg => {
  //從客戶端接收的消息
  //遍歷所有用戶
  map.forEach((value,index,arr) => {
   value.send(msg);
  });
 });
}); 

下面我貼上服務端的完整代碼,僅供參考

const socket = require("socket.io");
//創(chuàng)建一個websocket服務器
let socketServer = socket.listen(require("http").createServer((req,resp) => {
 //返回頁面
 resp.end(require("fs").readFileSync("./socketIOTest1.html"));
}).listen(9999,"localhost",() => {console.log("listening");}));

//創(chuàng)建一個用于放置用戶對象的map
let map = new Map();
//用于記錄用戶數量的變量,并初始化為0
let userCount = 0;

//監(jiān)聽connection 事件
socketServer.on("connection",socket => {
 console.log("有一用戶連接");
 map.set(++userCount,socket);
 //監(jiān)聽客戶端來的信息
 socket.on("message",msg => {
  //從客戶端接收的消息
  //遍歷所有用戶
  map.forEach((value,index,arr) => {
   value.send(msg);
  });
 });
 //監(jiān)聽客戶端退出情況
 socket.on("disconnect",() => {
  console.log("有一用戶退出連接");
 });
}); 

websocket私聊實現

在說私聊的實現之前,我們首先要找到對于每一個用戶的唯一標識,在通常的項目開發(fā)中,我們都使用用戶的用戶名進行標識,每個用戶通過注冊獲得與之對應的用戶名。將用戶名保存在數據庫中利用主鍵防止重復。

實現私聊的方法有很多種,這里我的實現方法是這樣的:

① 當用戶連接時,把用戶的socket端口對象使用map進行儲存,儲存的key 為用戶的socket對象,value為用戶的用戶名,寫一個方法用于更新客戶端列表
② 用戶默認用戶名為 <未命名>,指定自定義用戶名時,使用socket.emit方法觸發(fā)服務端的某個事件,遍歷map找到與之對應的key,進行value修改
③ 發(fā)送消息時,根據選擇列表來指定要發(fā)送的人,在服務端,遍歷map,找到要發(fā)送到的用戶名,進行發(fā)送,同時更新到自己的聊天框

以上就是私聊的簡單實現。

下面看一下具體代碼:

//Node.js

const socket = require("socket.io");
//創(chuàng)建一個websocket服務器
let socketServer = socket.listen(require("http").createServer((req,resp) => {
 //返回頁面
 resp.end(require("fs").readFileSync("./socketIOTest1.html"));
}).listen(9999,"localhost",() => {console.log("listening");}));

//創(chuàng)建一個用于放置用戶對象的map
let map = new Map();
//用于記錄用戶數量的變量,并初始化為0
let userCount = 0;
//遍歷map 
let scanMap = func => {
 try{
  map.forEach((value,index,arr) => {
   func(value,index,arr);
  });
 }
 catch(e){
  if(e.message == "break"){
   return;
  }
  else{
   throw e;
  }
 }
}

//通知客戶端彈出對話框
let showDialog = (socket,msg) => {
 socket.emit("showDialog",msg);
}

//更新用戶列表
let updateList = socket => {
 let userArr = [];
 scanMap((value,index) => {
  if(value != undefined){
   userArr.push(value);
  }
 });
 socket.emit("newUser",userArr);
}

//監(jiān)聽connection 事件
socketServer.on("connection",socket => {
 console.log("有一用戶連接");
 //初始化存儲當前socket對象
 map.set(socket,"<未命名>");
 //將用戶信息寫入map
 socket.on("getUser",user => {
  //修改名稱
  map.set(socket,user);
  scanMap((value,index) => {
   updateList(index);
  });
 });
 //通知所有客戶端更新列表
 scanMap((value,index) => {
  updateList(index);
 });
 //監(jiān)聽客戶端來的信息
 socket.on("message",msg => {
  //從客戶端接收的消息
  let sender;
  //遍歷所有用戶
  scanMap((value,index) => {
   if(index == socket){
    sender = value;
   }
  });
  scanMap((value,index) => {
   if(msg.person == "all"){
    index.send(sender + " : " + msg.msg);
   }
   else if(msg.person == value){
    socket.send(sender + " : " +msg.msg);
    index.send(sender + " : " +msg.msg);
    throw new Error("break");
   }
  });
 });
 //監(jiān)聽客戶端退出情況
 socket.on("disconnect",() => {
  //用戶退出,從map里刪除該用戶
  map.set(socket,undefined);
  //通知所有用戶更新列表
  scanMap((value,index) => {
   updateList(index);
  });
  console.log("有一用戶退出連接");
 });
}); 

客戶端:

<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <title>Document</title>
</head>
<body>
 <textarea name="" id="content" cols="30" rows="10" ></textarea>
 <input id="write" type="text" placeholder="please write content here">
 <input id="send" type="button" value="send" />
 <input type="text" id="user" placeholder="user">
 <select style="width: 100px;" size="2" name="" id="userList">
  <option value="all">群聊</option>
 </select>
 <script src="./socket.io/socket.io.js"></script>
 <script>
  let send = document.getElementById("send");
  let write = document.getElementById("write");
  let content = document.getElementById("content");
  let user = document.getElementById("user");
  //用戶列表
  let userList = document.getElementById("userList");
  let socket = io.connect();
  //判斷用戶名是否為空
  let isUserEmpty = () => {
   if(user.value == ""){
    alert("請?zhí)顚懹脩裘?);
    return false;
   }
   else {
    return true;
   }
  }
  //監(jiān)聽用戶名變化
  let oldUser;
  user.onblur = () => {
   if(isUserEmpty()){
    //防止重復發(fā)射
    if(oldUser == user.value){return;}
    oldUser = user.value;
    socket.emit("getUser",user.value);
   }
  }  
  //發(fā)送消息
  send.onclick = () => {
   if(isUserEmpty()){
    let msg = write.value;
    // content.innerHTML = content.value + msg + "\n";
    socket.send({msg:msg,person:userList.value});
   }
   if(select.value == ""){
    alert("請選擇一個聊天對象");
   }
  };
  //接收到消息
  socket.on("message",msg => {
   console.log("從服務器接收到的消息 : " + msg);
   //更新內容
   content.innerHTML = content.value + msg + "\n";
  });
  socket.on("disconnect",() => {
   console.log("與服務器斷開連接");
  });
  //新用戶加入聊天室
  socket.on("newUser",arr => {
   userList.innerHTML = "";
   let all = document.createElement("option");
   all.innerHTML = "群聊";
   all.setAttribute("value","all");
   userList.appendChild(all);
   //添加新用戶
   arr.forEach((value,index) => {
    console.log("value :" + value + "index :" + index);
    let option = document.createElement("option");
    option.innerHTML = value;
    option.setAttribute("value",value);
    userList.appendChild(option);
    userList.setAttribute("size",userList.children.length);
   });
   //默認選中群聊
   userList.value = "all";
  });
  //接收服務器需要彈出對話框的需求
  socket.on("showDialog",msg => {
   alert(msg);
  });
 </script>
</body>
</html>

代碼的具體我就不在詳細講解,都標有注釋,由于只是用于博文,整體代碼沒有重構優(yōu)化,大家看不懂的可以回復我,或者有什么地方錯誤請指出,我會及時改正。

另外在這個聊天室中,當用戶刷新頻率較快時,websocket會出現偽連接現象。

下面附上我的github地址,大家可以下載我的源碼進行修改學習,共勉。
https://github.com/HaoDaWang/chat

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。

相關文章

  • Node.js中的CommonJS模塊化規(guī)范詳解

    Node.js中的CommonJS模塊化規(guī)范詳解

    這篇文章主要介紹了Node.js中的CommonJS模塊化規(guī)范,本文主要介紹了?CommonJS?規(guī)范在?Node?中的簡單應用,主要就是導入和導出模塊,需要的朋友可以參考下
    2023-02-02
  • 使用forever管理nodejs應用教程

    使用forever管理nodejs應用教程

    這篇文章主要介紹了使用forever管理nodejs應用教程,本文介紹了forever的安裝、常用命令等,最有用的莫過于文件改動監(jiān)聽并自動重啟了,這可以增加開nodejs應用的效率,需要的朋友可以參考下
    2014-06-06
  • Node.js中,在cmd界面,進入退出Node.js運行環(huán)境的方法

    Node.js中,在cmd界面,進入退出Node.js運行環(huán)境的方法

    今天小編就為大家分享一篇Node.js中,在cmd界面,進入退出Node.js運行環(huán)境的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-05-05
  • node實現分片下載的示例代碼

    node實現分片下載的示例代碼

    這篇文章主要介紹了node實現分片下載的示例代碼,使用場景包括基于瀏覽器的流文件片段傳輸、基于客戶端的分片下載等。感興趣的小伙伴們可以參考一下
    2018-10-10
  • npm install安裝模塊-save和-save-dev命令的區(qū)別

    npm install安裝模塊-save和-save-dev命令的區(qū)別

    這篇文章介紹了npm install安裝模塊-save和-save-dev命令的區(qū)別,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2022-06-06
  • 使用node.js 制作網站前臺后臺

    使用node.js 制作網站前臺后臺

    本文給大家介紹實用node.js 制作網站前臺和后臺,非常的詳盡,有需要的朋友可以參考下
    2014-11-11
  • Node.js卸載與重裝及zip與msi安裝詳解

    Node.js卸載與重裝及zip與msi安裝詳解

    Node.js是一個JavaScript運行環(huán)境,可以使JavaScript這類腳本語言編寫出來的代碼運行速度獲得極大提升,下面這篇文章主要給大家介紹了關于Node.js卸載與重裝及zip與msi安裝的相關資料,需要的朋友可以參考下
    2023-01-01
  • Node.js連接MongoDB數據庫產生的問題

    Node.js連接MongoDB數據庫產生的問題

    Node.js是使用JavaScript 編寫的可以運行在服務端的JS語言。node.js和mongodb碰撞會產生一系列問題,下面通過本文給大家分享Node.js連接MongoDB數據庫,需要的的朋友參考下
    2017-02-02
  • NPM相關命令之報錯node-gyp...的解決方法

    NPM相關命令之報錯node-gyp...的解決方法

    node-gyp就是為node編譯c++擴展的時候使用的編譯工具,下面這篇文章主要給大家介紹了關于NPM相關命令之報錯node-gyp...的解決方法,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下
    2022-09-09
  • Node.js中的緩沖與流模塊詳細介紹

    Node.js中的緩沖與流模塊詳細介紹

    這篇文章主要介紹了Node.js中的緩沖與流模塊詳細介紹,本文講解了緩沖(buffer)模塊、類:Buffer、寫入緩沖區(qū)、復制緩沖區(qū)、流模塊等內容,需要的朋友可以參考下
    2015-02-02

最新評論