實現一個簡單的WebSocket聊天室

WebSocket 簡介

WebSocket 是 HTML5 開始提供的一種在單個 TCP 連接上進行全雙工通訊的協議绩社。
WebSocket 使得客戶端和服務器之間的數據交換變得更加簡單,允許服務端主動向客戶端推送數據宙攻。在 WebSocket API 中黔寇,瀏覽器和服務器只需要完成一次握手,兩者之間就直接可以創(chuàng)建持久性的連接,并進行雙向數據傳輸略号。
在 WebSocket API 中,瀏覽器和服務器只需要做一個握手的動作洋闽,然后玄柠,瀏覽器和服務器之間就形成了一條快速通道。兩者之間就直接可以數據互相傳送诫舅。

為什么傳統(tǒng)的HTTP協議不能做到WebSocket實現的功能羽利?這是因為HTTP協議是一個請求-響應協議,請求必須先由瀏覽器發(fā)給服務器刊懈,服務器才能響應這個請求这弧,再把數據發(fā)送給瀏覽器娃闲。換句話說,瀏覽器不主動請求匾浪,服務器是沒法主動發(fā)數據給瀏覽器的皇帮。

Web

我們先用 express 搭一個基礎的服務端。

創(chuàng)建 index.js 文件

var app = require('express')();
var http = require('http').createServer(app);

app.get('/', function(req, res){
  res.send('<h1>Hello world</h1>');
});

http.listen(3000, function(){
  console.log('listening on *:3000');
});

run node index.js蛋辈,并在瀏覽器打開 http://localhost:3000属拾,訪問成功即可看到

HTML

設計我們的主頁,實現一個簡單的聊天窗口冷溶。

修改 index.js

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

創(chuàng)建 index.html

<!doctype html>
<html>
  <head>
    <title>Socket.IO chat</title>
    <style>
      * { margin: 0; padding: 0; box-sizing: border-box; }
      body { font: 13px Helvetica, Arial; }
      form { background: #000; padding: 3px; position: fixed; bottom: 0; width: 100%; }
      form input { border: 0; padding: 10px; width: 90%; margin-right: .5%; }
      form 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; }
    </style>
  </head>
  <body>
    <ul id="messages"></ul>
    <form action="">
      <input id="m" autocomplete="off" /><button>Send</button>
    </form>
  </body>
</html>

重啟應用并刷新頁面你就可以看到一個如下圖所示

Socket.io

引入socket.io

npm install --save socket.io

修改 index.js

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

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

io.on('connection', function(socket){
  console.log('an user connected');
});

http.listen(3000, function(){
  console.log('listening on *:3000');
});

修改 index.html渐白,在</body>下添加如下代碼

<script src="/socket.io/socket.io.js"></script>
<script>
  var socket = io();
</script>

重啟應用并刷新頁面,就可以看到命令行打印如下

Emitting event

當用戶在聊天窗的輸入框內輸入逞频,并提交時纯衍,觸發(fā) emit 事件,服務端監(jiān)聽到該事件并做出相應的反應虏劲。

修改 index.html

<script src="/socket.io/socket.io.js"></script>
<script src="https://code.jquery.com/jquery-1.11.1.js"></script>
<script>
  $(function () {
    var socket = io();
    $('form').submit(function(e){
      e.preventDefault(); // 防止頁面重新加載
      socket.emit('chat message', $('#m').val());
      $('#m').val('');
      return false;
    });
  });
</script>

服務端監(jiān)聽該事件托酸,在 index.js 文件添加該代碼

io.on('connection', function(socket){
  socket.on('chat message', function(msg){
    console.log('message: ' + msg);
  });
});

展示消息

當服務端收到用戶A發(fā)出的消息,服務端重新發(fā)出該消息柒巫,讓客戶端接收励堡,客戶端監(jiān)聽到該事件后展示該條消息,就可以實現用戶 A, B, C 都接收到該消息堡掏。

修改 index.js

io.on('connection', function(socket){
  socket.on('chat message', function(msg){
    io.emit('chat message', msg);
  });
});

修改 index.html应结,實現消息的展示

<script>
  $(function () {
    var socket = io();
    $('form').submit(function(e){
      e.preventDefault(); // prevents page reloading
      socket.emit('chat message', $('#m').val());
      $('#m').val('');
      return false;
    });
    socket.on('chat message', function(msg){
      $('#messages').append($('<li>').text(msg));
    });
  });
</script>

重啟應用并刷新頁面,可以打開多個瀏覽器頁面同時訪問 localhost:3000泉唁,就可以體驗簡單聊天室的效果鹅龄。

設置昵稱

在每個用戶進入的時候,隨機生成一個數字作為用戶的昵稱亭畜,并且向所有用戶廣播該用戶進入聊天室扮休。當用戶發(fā)送消息時,拼接上用戶的昵稱拴鸵。

修改 index.js

io.on('connection', (socket) => {
  const nickname = 'user' + Math.ceil((Math.random() * 1000))
  socket.broadcast.emit('connection', nickname + ' connected')

  socket.on('chat message', (msg) => {
    io.emit('chat message', nickname + ': ' + msg)
  })
})

修改 index.html玷坠,監(jiān)聽 connection 事件

<script>
    $(() => {
      const socket = io()
      $('form').submit((e) => {
        e.preventDefault()
        socket.emit('chat message', $('#m').val())
        $('#m').val('')
        return false
      });
      socket.on('chat message', (msg) => {
        $('#messages').append($('<li>').text(msg))
      })
      socket.on('connection', (msg) => {
        $('#messages').append($('<li>').text(msg))
      })
    });
  </script>

重啟應用并打開多個客戶端,可以看到如下效果

參考資料

本文大部分案例出自 socket.io 的入門文檔 https://socket.io/get-started/chat/

https://en.wikipedia.org/wiki/WebSocket

廖雪峰官網 WebSocket

菜鳥教程 WebSocket

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末劲藐,一起剝皮案震驚了整個濱河市八堡,隨后出現的幾起案子,更是在濱河造成了極大的恐慌聘芜,老刑警劉巖兄渺,帶你破解...
    沈念sama閱讀 217,826評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異汰现,居然都是意外死亡挂谍,警方通過查閱死者的電腦和手機叔壤,發(fā)現死者居然都...
    沈念sama閱讀 92,968評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來凳兵,“玉大人百新,你說我怎么就攤上這事企软÷ǎ” “怎么了?”我有些...
    開封第一講書人閱讀 164,234評論 0 354
  • 文/不壞的土叔 我叫張陵仗哨,是天一觀的道長形庭。 經常有香客問我,道長厌漂,這世上最難降的妖魔是什么萨醒? 我笑而不...
    開封第一講書人閱讀 58,562評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮苇倡,結果婚禮上富纸,老公的妹妹穿的比我還像新娘。我一直安慰自己旨椒,他們只是感情好晓褪,可當我...
    茶點故事閱讀 67,611評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著综慎,像睡著了一般涣仿。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上示惊,一...
    開封第一講書人閱讀 51,482評論 1 302
  • 那天好港,我揣著相機與錄音,去河邊找鬼米罚。 笑死钧汹,一個胖子當著我的面吹牛,可吹牛的內容都是我干的录择。 我是一名探鬼主播拔莱,決...
    沈念sama閱讀 40,271評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼糊肠!你這毒婦竟也來了辨宠?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,166評論 0 276
  • 序言:老撾萬榮一對情侶失蹤货裹,失蹤者是張志新(化名)和其女友劉穎嗤形,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體弧圆,經...
    沈念sama閱讀 45,608評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡赋兵,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,814評論 3 336
  • 正文 我和宋清朗相戀三年笔咽,在試婚紗的時候發(fā)現自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片霹期。...
    茶點故事閱讀 39,926評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡叶组,死狀恐怖,靈堂內的尸體忽然破棺而出历造,到底是詐尸還是另有隱情甩十,我是刑警寧澤,帶...
    沈念sama閱讀 35,644評論 5 346
  • 正文 年R本政府宣布吭产,位于F島的核電站侣监,受9級特大地震影響,放射性物質發(fā)生泄漏臣淤。R本人自食惡果不足惜橄霉,卻給世界環(huán)境...
    茶點故事閱讀 41,249評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望邑蒋。 院中可真熱鬧姓蜂,春花似錦、人聲如沸医吊。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,866評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽遮咖。三九已至滩字,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間御吞,已是汗流浹背麦箍。 一陣腳步聲響...
    開封第一講書人閱讀 32,991評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留陶珠,地道東北人挟裂。 一個月前我還...
    沈念sama閱讀 48,063評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像揍诽,于是被迫代替她去往敵國和親诀蓉。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,871評論 2 354

推薦閱讀更多精彩內容