使用socket.io寫一個聊天室
阿新 • • 發佈:2018-11-23
之前學習了常用的api,以及概念,這裡為了簡單的使用,寫一個demo,為了方便查詢api,這裡給一個傳送門socket.io
準備
- 老規矩,新建一個目錄,一個index.html, app.js
- index.html 為客戶端
- app.js 為服務端
基礎程式碼
首先使用最簡單的程式碼,然後是實現客戶管和服務端連結成功
-
index.html
- 使用html初始文件,然後引入socket.io指令碼
<script src="/socket.io/socket.io.js"></script>
- 建立socket物件
- 連結服務端,並監聽連結事件
connect
,message
事件
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"
- 使用html初始文件,然後引入socket.io指令碼
-
app.js
let express = require('express') let http = require('http') let app = express() app.use(express.static(__dirname)) app.get('/', function (res, req) { res.header('Content-Type', 'text/html;charset=utf8') res.sendFile(path.resolve('index.html')) }) let server = http.createServer(app) // 因為websocket協議是要依賴http協議實現握手的,所以需要把httpServer的例項傳遞給socket.io let socketIo = require('socket.io') let io = socketIo(server) // 在伺服器監聽客戶端的連結 io.on('connection', socket => { console.log('客戶端連線到伺服器') // 監聽接受客戶端發過來的訊息 socket.on('message', msg => { console.log('客戶端等候掃伺服器的訊息', msg) // 像客戶端傳送資料 socket.send(`伺服器說:${msg}`) }) socket.on('disconect', function () { console.log('斷開連線') }) socket.on('error', () => { console.log('連線錯誤') }) }) server.listen(9999)
實現基本聊天
為了美化一下樣式,這裡使用了bootstarp,
-
index.html 修改如下
- 簡單的佈局,頭部,訊息體,訊息輸入框和傳送訊息按鈕
- 修改,我們這裡把訊息(msg:一個json字串),解析出來,拿到對應的傳送訊息的使用者名稱,訊息內容,小時傳送的時間,然後動態建立li,將內容加入li以後再動態加入到訊息列表
- 傳送訊息的時候檢查訊息是否為空,為空則警告使用者,不為空則傳送小洗,並將輸入框清空
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <!-- 最新版本的 Bootstrap 核心 CSS 檔案 --> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"> <title>socket.io</title> </head> <body> <div class="container"> <div class="row"> <div class="row-md-12"> <div class="panel panel-default"> <!-- 頭部 --> <header class="panel-heading text-center"> <h4>welcome to talk room</h4> </header> <!-- 訊息列表 --> <div class="panel-body"> <ul class="list-group" id="msg-list" style="list-style: none;"> </ul> </div> <!-- 訊息輸入,傳送按鈕 --> <div class="panel-footer"> <div class="row-md-10"> <input type="text" id="content" class="form-control"> <button id="btn" class="btn btn-primary">傳送訊息</button> </div> </div> </div> </div> </div> </div> <script src="/socket.io/socket.io.js"></script> <script> let socket = io() // 相當於new Websocket() let ipt = document.querySelector('#content') let btn = document.querySelector('#btn') let msgList = document.querySelector('#msg-list') let LI = document.createElement('li') socket.on('connect', function () { console.log('客戶端連結成功') }) socket.on('message', function (msg) { let li = LI.cloneNode() msg = JSON.parse(msg) li.innerHTML = `<span style="color: orange">${msg.name}: </span><span style="color: #06c;">${msg.msg}</span><span style="float: right;">${(new Date(msg.timer)).toLocaleString()}</span>` msgList.appendChild(li) }) btn.addEventListener('click',function (params) { let msg = ipt.value if (msg) { socket.emit('message', msg) ipt.value = '' } else { alert('傳送的訊息不能為空!') } }, false) </script> </body> </html>
-
app.js修改如下
- 將使用者第一次傳送的訊息作為使用者的暱稱
- 接收到訊息以後判斷使用者名稱是否存在,不存在就將當前訊息作為使用者名稱儲存,並通知其他客戶端,該使用者(這個使用者的第一個訊息的名字),加入了聊天
- 正常組裝傳送訊息
- 訊息的內容為:傳送者的名稱,訊息內容,訊息時間
let express = require('express') let http = require('http') let app = express() app.use(express.static(__dirname)) app.get('/', function (res, req) { res.header('Content-Type', 'text/html;charset=utf8') res.sendFile(path.resolve('index.html')) }) let server = http.createServer(app) // 因為websocket協議是要依賴http協議實現握手的,所以需要把httpServer的例項傳遞給socket.io let socketIo = require('socket.io') let io = socketIo(server) // 在伺服器監聽客戶端的連結 let sockets = {} // 儲存使用者 let SYS = '系統提示' let t = new Date() // 用來處理訊息傳送時間 io.on('connection', socket => { console.log('客戶端連線到伺服器', socket.name) let username; // 監聽接受客戶端發過來的訊息 socket.on('message', msg => { if (username) { username = msg // 訊息內容 let message = { name: SYS, timer: t.getTime(), msg: `${msg} 進入聊天` } // 將物件儲存,方便後期使用 sockets[username] = socket // 像除了自己別的使用者廣播訊息 socket.broadcast.emit('message', JSON.stringify(message)) } else { // 像客戶端傳送資料 let message = { name: username, timer: t.getTime(), msg: msg } io.emit('message', JSON.stringify(message)) } }) socket.on('disconect', function () { console.log('斷開連線') }) socket.on('error', () => { console.log('連線錯誤') }) }) server.listen(9999)
實現私聊
-
index.html
- 給li新增點選事件,拿到需要私聊的名稱,然後賦值到輸入框中
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <!-- 最新版本的 Bootstrap 核心 CSS 檔案 --> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"> <title>socket.io</title> </head> <body> <div class="container"> <div class="row"> <div class="row-md-12"> <div class="panel panel-default"> <header class="panel-heading text-center"> <h4>welcome to talk room</h4> </header> <div class="panel-body"> <ul class="list-group" id="msg-list" style="list-style: none;"> </ul> </div> <div class="panel-footer"> <div class="row-md-10"> <input type="text" id="content" class="form-control"> <button id="btn" class="btn btn-primary">傳送訊息</button> </div> </div> </div> </div> </div> </div> <script src="/socket.io/socket.io.js"></script> <script> let socket = io() // 相當於new Websocket() let ipt = document.querySelector('#content') let btn = document.querySelector('#btn') let msgList = document.querySelector('#msg-list') let LI = document.createElement('li') socket.on('connect', function () { console.log('客戶端連結成功') }) socket.on('message', function (msg) { let li = LI.cloneNode() msg = JSON.parse(msg) li.innerHTML = `<span style="color: orange" onClick="sendPrive('${msg.name}')">${msg.name}: <span style="color: #06c;">${msg.msg}</span></span><span style="float: right;">${(new Date(msg.timer)).toLocaleString()}</span>` msgList.appendChild(li) }) /** * 設定需要私密通話的物件 */ function sendPrive(name) { let str = `@${name} ` ipt.value = str } btn.addEventListener('click',function (params) { let msg = ipt.value if (msg) { socket.emit('message', msg) ipt.value = '' } else { alert('傳送的訊息不能為空!') } }, false) </script> </body> </html>
-
app.js
- 拿到訊息以後需要做一個解析,判斷是否有私密聊天的name,如果有做類外的邏輯
/^@([^ ]+) (\S)+/
獲取訊息的name和內容,如果只有訊息,則不會有返回值- 如果有則從sockets中找到該物件,然後單獨傳送給該使用者這條訊息
- 如果沒有,則按照廣播的形式正常傳送
let express = require('express') let http = require('http') let app = express() app.use(express.static(__dirname)) app.get('/', function (res, req) { res.header('Content-Type', 'text/html;charset=utf8') res.sendFile(path.resolve('index.html')) }) let server = http.createServer(app) // 因為websocket協議是要依賴http協議實現握手的,所以需要把httpServer的例項傳遞給socket.io let socketIo = require('socket.io') let io = socketIo(server) // 在伺服器監聽客戶端的連結 let sockets = {}