前言: (在NodeJs中,我們想要開啟一個tcp協議的做法就是引入net內置對象:
const net = require('net'); ——ES6
var net = require('net'); ——ES5)
今天,我們來實現一個
基於TCP協議完成node服務器與telnet客戶端通信的聊天程序
首先,思考我們的需求:
1.開啟多個終端頁面,可在不同終端中進行用戶注冊,注冊成功后,即開始聊天
2.使用net開啟TCP服務,net.stream的設計
具體實現界面貼圖:
我們需要做的有兩件事:
1.用NodeJs搭建服務器流 ——to dev
2.實現telnet可視化界面 ——to user
那么,我們就開始用NodeJs搭建服務器:
-
- 首先思考,我們是通過TCP協議進行通信,那么選用net模塊(nodejs內置)
- 其次,我們使用net.createServer創建一個服務,createServer方法中參數為一個回調函數,符合事件驅動概念,該回調函數中的參數為connection對象,咱們就使用該對象進行net.stream數據流的傳遞
濾清思路后,我們開始:
const net = require('net'); // 介於目前ES2015已成新標准,所以采用ES6寫法
let server = net.createServer(function (conn) { // ...code
};
在上述代碼中,我們創建了一個server服務器,接下來我們思考,我們的服務器需要對端口進行監聽:
const net = require('net'); // 介於目前ES2015已成新標准,所以采用ES6寫法
let server = net.createServer(function (conn) { // ...code
}; server.listen(3000, function () { console.log('\033[96m server listening on *:3000\033[39m'); });
監聽端口號為3000,當我們啟動服務器時,可以在終端中顯示:
接下來我們嘗試用telnet客戶端連接咱們剛搭建好的服務器:(在命令行或者終端內輸入 telnet 127.0.0.1 3000)
*Telnet協議是TCP/IP協議族中的一員,是Internet遠程登陸服務的標准協議和主要方式
*若您不知道如何打開telnet,請閱讀——<如何在windows10下開啟telnet服務>
那么,我們在telnet客戶端界面看到,目前沒有任何顯示,所以我們需要去設計一個用戶使用的界面:
效果如圖:
我們考慮:如何在終端上顯示提示符?
connection對象上提供了write方法,可以在通過連接的客戶端上顯示輸入內容,所以我們在server對象內部設計用戶界面:
let server = net.createServer(function (conn) { // 頁面tip
conn.write( '\n > welcome to \033[92mnode-chat\033[39m!'
+ '\n > ' + count + ' other people are connected at this time.'
+ '\n > please write your name and press enter: ' ); };
此時,重新利用終端開啟telnet,此時用戶界面顯示如上圖。
既然已經設計好用戶注冊界面,那么我們應該去考慮如何處理用戶輸入的數據,這時,我們需要通過connection對象對輸入數據注冊事件:
let count = 0;
// 參數count作計算接入客戶端數
let server = net.createServer(function (conn) {
count++; // 頁面tip conn.write( '\n > welcome to \033[92mnode-chat\033[39m!' + '\n > ' + count + ' other people are connected at this time.' + '\n > please write your name and press enter: ' ); conn.on('data', function (data) { // ... code } };
data參數就是用戶輸入的數據了,不過我們考慮,用戶首先輸入的應該是用戶名,其次才是聊天數據,所以我們應該:
1.用列表對用戶名進行保存
2.判斷用戶名是否第一次輸入信息,以便重新注冊
3.判斷用戶輸入昵稱是否已存在
let count = 0; let users = {}; let server = net.createServer(function (conn) { count++; let nickname; // 頁面tip
conn.write( '\n > welcome to \033[92mnode-chat\033[39m!'
+ '\n > ' + count + ' other people are connected at this time.'
+ '\n > please write your name and press enter: ' ); conn.on('data', function (data) { // 刪除回車符,否則會出現空行
data = data.replace('\r\n', ''); if (!nickname) { if (users[data]) { conn.write('\033[93m> nickname already in use. try again:\033[39m '); return; } else { nickname = data; users[nickname] = conn; // 將conn對象賦予用戶,賦予用戶可操作權限
} } else { // 驗證用戶為已注冊,則輸入數據data為聊天信息
for (var i in users) { if (i != nickname) { console.log('\033[96m > ' + nickname + ':\033[39m ' + data + '\n'); } } } } };
實現后效果:
當用戶關閉客戶端時,我們不想保存用戶名,我們可以注冊close事件:
let count = 0; let users = {}; let server = net.createServer(function (conn) { count++; let nickname; // ...code
// 當其中某個用戶斷開連接時,需要清楚數據
conn.on('close', function () { count--; console.log('\033[90m > ' + nickname + ' left the room\033[39m\n'); delete users[nickname]; }); };
到目前為止,我們已經實現了整個聊天程序的功能,那么我們應該思考代碼重構:
我們在用戶接入與斷開連接時,都寫入了提示信息,那么,我們應該將提示信息抽離出來,作為一個廣播函數:
let count = 0; let users = {}; let server = net.createServer(function (conn) { count++; let nickname; // ...code
// 當用戶退出時,進行廣播通知
let broadcast = (msg, exceptMyself) => { for (var i in users) { if (!exceptMyself || i != nickname) { users[i].write(msg); } } }; // 監聽用戶行為作出處理
conn.on('data', function (data) { // 刪除回車符
data = data.replace('\r\n', ''); if (!nickname) { if (users[data]) { conn.write('\033[93m> nickname already in use. try again:\033[39m '); return; } else { nickname = data; // 將conn對象賦予用戶,賦予用戶可操作權限
users[nickname] = conn; broadcast('\033[90m > ' + nickname + ' joined the room\033[39m\n'); } } else { // 驗證用戶為已注冊,則輸入數據(data)為聊天信息
for (var i in users) { if (i != nickname) { broadcast('\033[96m > ' + nickname + ':\033[39m ' + data + '\n', true); } } } }); // 當其中某個用戶斷開連接時,需要清楚數據
conn.on('close', function () { count--; broadcast('\033[90m > ' + nickname + ' left the room\033[39m\n'); delete users[nickname]; }); };
實現廣播效果:
加入:
退出(關閉客戶端):
*注:處理data數據時應設置編碼格式 conn.setEncoding('utf8');
至此,我們的整個聊天程序就大功告成了!
大家可以在我的github上獲取源碼——https://github.com/TimRChen/NodeCLI-telnet
相應操作文檔——click here!