使用Node.js的Readline和Socket.io實(shí)現(xiàn)即時聊天
Aug 31, 2023 pm 06:09 PMNode.js 在其標(biāo)準(zhǔn)函式庫中有一個未被充分重視的模組,但卻非常有用。 Readline 模組依照包裝盒上的說明執(zhí)行操作:從終端機(jī)讀取一行輸入。這可用於詢問使用者一兩個問題,或在螢?zāi)坏撞拷⑻崾?。在本教程中,我打算展?Readline 的功能並製作一個由 Socket.io 支援的即時 CLI 聊天室。客戶端不僅可以發(fā)送簡單的訊息,還可以使用 /me
發(fā)送表情命令,使用 /msg
發(fā)送私人訊息,並允許使用 /nick
。
#關(guān)於 Readline 的一點(diǎn)
這可能是 Readline 最簡單的用法:
var readline = require('readline'); var rl = readline.createInterface(process.stdin, process.stdout); rl.question("What is your name? ", function(answer) { console.log("Hello, " + answer ); rl.close(); });
我們包含該模組,使用標(biāo)準(zhǔn)輸入和輸出流創(chuàng)建 Readline 接口,然後向用戶詢問一個一次性問題。這是Readline的第一個用法:問問題。如果您需要與使用者確認(rèn)某些內(nèi)容,可能採用流行的形式,“您想這樣做嗎?(y/n)”,這種形式普遍存在於CLI 工具中,readline.question ()
就是這樣做的方法。
#Readline 提供的另一個功能是提示,可以根據(jù)其預(yù)設(shè)的「>」字元進(jìn)行自訂,並暫時暫停以防止輸入。對於我們的 Readline 聊天用戶端,這將是我們的主要介面。將會出現(xiàn)一次 readline.question()
來詢問使用者暱稱,但其他所有內(nèi)容都會是 readline.prompt()
。
#管理您的依賴項(xiàng)
讓我們從無聊的部分開始:依賴關(guān)係。專案將使用 socket.io
、socket.io-client
套件和 ansi-color
。您的 packages.json
檔案應(yīng)如下所示:
{ "name": "ReadlineChatExample", "version": "1.0.0", "description": "CLI chat with readline and socket.io", "author": "Matt Harzewski", "dependencies": { "socket.io": "latest", "socket.io-client": "latest", "ansi-color": "latest" }, "private": true }
運(yùn)行 npm install
就可以了。
#伺服器
在本教學(xué)中,我們將使用一個非常簡單的 Socket.io 伺服器。沒有比這更基本的了:
var socketio = require('socket.io'); // Listen on port 3636 var io = socketio.listen(3636); io.sockets.on('connection', function (socket) { // Broadcast a user's message to everyone else in the room socket.on('send', function (data) { io.sockets.emit('message', data); }); });
它所做的只是從一個客戶端接收傳入訊息並將其傳遞給其他所有人。對於更大規(guī)模的應(yīng)用程式來說,伺服器可能會更加健壯,但對於這個簡單的範(fàn)例來說,它應(yīng)該足夠了。
#這應(yīng)該保存在專案目錄中,名稱為 server.js
。
#客戶端:包括和設(shè)定
#在我們開始有趣的部分之前,我們需要包含我們的依賴項(xiàng),定義一些變量,並啟動 Readline 介面和套接字連接。
var readline = require('readline'), socketio = require('socket.io-client'), util = require('util'), color = require("ansi-color").set; var nick; var socket = socketio.connect('localhost', { port: 3636 }); var rl = readline.createInterface(process.stdin, process.stdout);
此時,程式碼幾乎是不言自明的。我們已經(jīng)有了暱稱變數(shù)、套接字連接(透過 socket.io-client
套件)和 Readline 介面。
在此範(fàn)例中,Socket.io 將透過連接埠 3636
連接到本機(jī),當(dāng)然,如果您正在製作生產(chǎn)聊天應(yīng)用程序,這將變更為您自己的伺服器的網(wǎng)域和連接埠。 (與自己聊天沒有太大意義?。?/p>
客戶端:詢問使用者名稱
#現(xiàn)在我們第一次使用 Readline!我們想詢問用戶選擇的暱稱,這將在聊天室中識別他們。為此,我們將使用 Readline 的 question()
方法。
// Set the username rl.question("Please enter a nickname: ", function(name) { nick = name; var msg = nick + " has joined the chat"; socket.emit('send', { type: 'notice', message: msg }); rl.prompt(true); });
我們將先前的 nick 變數(shù)設(shè)定為從使用者收集的值,向伺服器發(fā)送訊息(該訊息將轉(zhuǎn)發(fā)到其他客戶端)我們的使用者已加入聊天,然後將 Readline 介面切換回提示模式。傳遞給 prompt()
的 true
值可確保正確顯示提示符號。 (否則遊標(biāo)可能會移動到該行的零位置,並且不會顯示“>”。)
不幸的是,Readline 在 prompt()
方法方面有令人沮喪的問題。它與console.log()
配合得不太好,它會將文字輸出到與提示字元相同的行,從而在各處留下雜散的“>”字符和其他字符怪異。為了解決這個問題,我們不會在此應(yīng)用程式中的任何位置使用 console.log
,僅保留一個位置。相反,輸出應(yīng)該傳遞給此函數(shù):
function console_out(msg) { process.stdout.clearLine(); process.stdout.cursorTo(0); console.log(msg); rl.prompt(true); }
這個稍微的hacky解決方案可確??刂婆_中的當(dāng)前行為空,並且在列印輸出之前遊標(biāo)位於零位置。然後它明確要求再次輸出提示。
#因此,在本教學(xué)的其餘部分中,您將看到 console_out()
?而不是 console.log()
。
客戶端:處理輸入
使用者可以輸入兩種類型的輸入:聊天和命令。我們知道命令前面有斜杠,因此很容易區(qū)分兩者。
#Readline 有幾個事件處理程序,但最重要的無疑是 line
。每當(dāng)在輸入流中檢測到換行符(通過 return 或 Enter 鍵)時,就會觸發(fā)此事件。因此,我們需要為我們的輸入處理程序掛鉤 line
。
rl.on('line', function (line) { if (line[0] == "/" && line.length > 1) { var cmd = line.match(/[a-z]+\b/)[0]; var arg = line.substr(cmd.length+2, line.length); chat_command(cmd, arg); } else { // send chat message socket.emit('send', { type: 'chat', message: line, nick: nick }); rl.prompt(true); } });
如果輸入行的第一個字符是斜杠,我們就知道這是一個命令,這將需要更多的處理。否則,我們只是發(fā)送常規(guī)聊天消息并重置提示。請注意此處通過套接字發(fā)送的數(shù)據(jù)與上一步中的加入消息之間的差異。它使用不同的 type
,因此接收客戶端知道如何格式化消息,并且我們還傳遞 nick
?變量。
命令名稱(cmd
)和后面的文本(arg
)用一些正則表達(dá)式和子字符串魔術(shù)隔離,然后我們將它們傳遞給處理函數(shù)命令。
function chat_command(cmd, arg) { switch (cmd) { case 'nick': var notice = nick + " changed their name to " + arg; nick = arg; socket.emit('send', { type: 'notice', message: notice }); break; case 'msg': var to = arg.match(/[a-z]+\b/)[0]; var message = arg.substr(to.length, arg.length); socket.emit('send', { type: 'tell', message: message, to: to, from: nick }); break; case 'me': var emote = nick + " " + arg; socket.emit('send', { type: 'emote', message: emote }); break; default: console_out("That is not a valid command."); } }
如果用戶輸入 /nick gollum
,則 nick
變量將重置為 gollum
,它可能是 smeagol
?之前,并將通知推送到服務(wù)器。
如果用戶輸入 /msg bilbo 珍貴在哪里?
,使用相同的正則表達(dá)式來分隔接收者和消息,然后是一個類型為 tell
?被推送到服務(wù)器。這將與普通消息的顯示方式略有不同,并且其他用戶不應(yīng)該看到。誠然,我們過于簡單的服務(wù)器會盲目地將消息推送給每個人,但客戶端會忽略未發(fā)送到正確昵稱的通知。更強(qiáng)大的服務(wù)器可以更加離散。
表情命令的使用形式為/我正在吃第二頓早餐
。昵稱以任何使用過 IRC 或玩過多人角色扮演游戲的人都應(yīng)該熟悉的方式添加到表情符號中,然后將其推送到服務(wù)器。
客戶端:處理傳入消息
現(xiàn)在客戶端需要一種接收消息的方法。我們需要做的就是掛鉤 Socket.io 客戶端的 message
事件并適當(dāng)?shù)馗袷交瘮?shù)據(jù)以進(jìn)行輸出。
socket.on('message', function (data) { var leader; if (data.type == 'chat' && data.nick != nick) { leader = color("<"+data.nick+"> ", "green"); console_out(leader + data.message); } else if (data.type == "notice") { console_out(color(data.message, 'cyan')); } else if (data.type == "tell" && data.to == nick) { leader = color("["+data.from+"->"+data.to+"]", "red"); console_out(leader + data.message); } else if (data.type == "emote") { console_out(color(data.message, "cyan")); } });
客戶端使用我們的昵稱發(fā)送的類型為 chat
?的消息將與昵稱和聊天文本一起顯示。用戶已經(jīng)可以看到他們在 Readline 中輸入的內(nèi)容,因此沒有必要再次輸出它。在這里,我使用 ansi-color
包對輸出進(jìn)行一點(diǎn)著色。這并不是絕對必要的,但它使聊天更容易理解。
類型為 notice
或 emote
的消息按原樣打印,但顏色為青色。
如果消息是 tell
,且昵稱等于此客戶端的當(dāng)前名??稱,則輸出采用 [Somebody->You] Hi!
的形式。當(dāng)然,這并不是非常私密的事情。如果您想查看每個人的消息,您只需取出 && data.to == nick
部分即可。理想情況下,服務(wù)器應(yīng)該知道將消息推送到哪個客戶端,而不是將其發(fā)送給不需要它的客戶端。但這增加了不必要的復(fù)雜性,超出了本教程的范圍。
點(diǎn)燃它!
現(xiàn)在讓我們看看是否一切正常。要對其進(jìn)行測試,請通過運(yùn)行 node server.js
啟動服務(wù)器,然后打開幾個新的終端窗口。在新窗口中,運(yùn)行 node client.js
并輸入昵稱。假設(shè)一切順利,那么您應(yīng)該能夠在他們之間聊天。
希望本教程向您展示了 Readline 模塊的入門是多么容易。您可能想嘗試向聊天應(yīng)用程序添加更多功能,以進(jìn)行更多練習(xí)。最后,查看 Readline 文檔以獲取完整的 API。
以上是使用Node.js的Readline和Socket.io實(shí)現(xiàn)即時聊天的詳細(xì)內(nèi)容。更多資訊請關(guān)注PHP中文網(wǎng)其他相關(guān)文章!

熱AI工具

Undress AI Tool
免費(fèi)脫衣圖片

Undresser.AI Undress
人工智慧驅(qū)動的應(yīng)用程序,用於創(chuàng)建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費(fèi)的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費(fèi)的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強(qiáng)大的PHP整合開發(fā)環(huán)境

Dreamweaver CS6
視覺化網(wǎng)頁開發(fā)工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

Node.js 安裝目錄中有兩個與 npm 相關(guān)的文件:npm 和 npm.cmd,區(qū)別如下:擴(kuò)展名不同:npm 是可執(zhí)行文件,npm.cmd 是命令視窗快捷方式。 Windows 使用者:npm.cmd 可以在命令提示字元中使用,npm 只能從命令列執(zhí)行。相容性:npm.cmd 特定於 Windows 系統(tǒng),npm 跨平臺可用。使用建議:Windows 使用者使用 npm.cmd,其他作業(yè)系統(tǒng)使用 npm。

Node.js 可作為後端框架使用,因?yàn)樗峁└咝?、可擴(kuò)展性、跨平臺支援、豐富的生態(tài)系統(tǒng)和易於開發(fā)等功能。

是的,Node.js可用於前端開發(fā),主要優(yōu)勢包括高效能、豐富的生態(tài)系統(tǒng)和跨平臺相容性。需要考慮的注意事項(xiàng)有學(xué)習(xí)曲線、工具支援和社群規(guī)模較小。

Node.js 中存在以下全域變數(shù):全域物件:global核心模組:process、console、require執(zhí)行階段環(huán)境變數(shù):__dirname、__filename、__line、__column常數(shù):undefined、null、NaN、Infinity、-Infinity

是的,Node.js 是一種後端開發(fā)語言。它用於後端開發(fā),包括處理伺服器端業(yè)務(wù)邏輯、管理資料庫連接和提供 API。

要連接 MySQL 資料庫,需要遵循以下步驟:安裝 mysql2 驅(qū)動程式。使用 mysql2.createConnection() 建立連接對象,其中包含主機(jī)位址、連接埠、使用者名稱、密碼和資料庫名稱。使用 connection.query() 執(zhí)行查詢。最後使用 connection.end() 結(jié)束連線。

Node.js 適用於以下專案類型:網(wǎng)頁和伺服器應(yīng)用程式事件驅(qū)動應(yīng)用程式即時應(yīng)用程式資料密集型應(yīng)用程式命令列工具和腳本輕量級微服務(wù)

Node.js 專案的伺服器部署步驟:準(zhǔn)備部署環(huán)境:取得伺服器存取權(quán)限、安裝 Node.js、設(shè)定 Git 儲存庫。建置應(yīng)用程式:使用 npm run build 產(chǎn)生可部署程式碼和相依性。上傳程式碼到伺服器:透過 Git 或檔案傳輸協(xié)定。安裝依賴項(xiàng):SSH 登入伺服器並使用 npm install 安裝應(yīng)用程式相依性。啟動應(yīng)用程式:使用 node index.js 等命令啟動應(yīng)用程序,或使用 pm2 等進(jìn)程管理器。設(shè)定反向代理(可選):使用 Nginx 或 Apache 等反向代理路由流量到應(yīng)用程式
