Node.js 的 TCP 和 UDP使用示例代碼詳解
TCP
Node.js 的 net
模塊是其內置模塊之一,主要用于創(chuàng)建基于 TCP(Transmission Control Protocol)的網(wǎng)絡應用,包括服務器和客戶端。
核心功能與 API
1. 創(chuàng)建 TCP 服務器
使用 net.createServer()
方法創(chuàng)建服務器,通過回調函數(shù)處理連接事件:
const net = require('net'); const server = net.createServer((socket) => { // 處理客戶端連接 console.log('客戶端已連接'); // 監(jiān)聽數(shù)據(jù)事件(客戶端發(fā)送數(shù)據(jù)時觸發(fā)) socket.on('data', (data) => { console.log(`收到數(shù)據(jù):${data.toString()}`); socket.write('服務器已收到消息'); // 向客戶端發(fā)送響應 }); // 監(jiān)聽連接關閉事件 socket.on('end', () => { console.log('客戶端已斷開連接'); }); }); // 啟動服務器,監(jiān)聽指定端口 server.listen(3000, () => { console.log('服務器已啟動,監(jiān)聽端口 3000'); });
2. 創(chuàng)建 TCP 客戶端
使用 net.createConnection()
方法創(chuàng)建客戶端,連接到服務器:
const net = require('net'); const client = net.createConnection({ port: 3000 }, () => { // 連接成功后發(fā)送數(shù)據(jù) console.log('已連接到服務器'); client.write('你好,這是客戶端發(fā)送的消息'); }); // 監(jiān)聽服務器響應 client.on('data', (data) => { console.log(`收到服務器響應:${data.toString()}`); client.end(); // 關閉連接 }); // 監(jiān)聽連接關閉事件 client.on('end', () => { console.log('已斷開與服務器的連接'); });
3. 核心對象與事件
net.Server
:服務器對象,常用方法:
server.listen(port, callback)
:啟動服務器監(jiān)聽。server.close()
:關閉服務器。server.maxConnections
:設置最大連接數(shù)。
net.Socket
:表示單個客戶端連接,常用事件和方法:
事件:
'data'
:收到數(shù)據(jù)時觸發(fā)。'end'
:連接關閉時觸發(fā)。'error'
:發(fā)生錯誤時觸發(fā)。'connect'
:客戶端連接成功時觸發(fā)。
方法:
socket.write(data)
:向對方發(fā)送數(shù)據(jù)。socket.end()
:關閉連接(允許發(fā)送緩沖區(qū)數(shù)據(jù))。socket.destroy()
:立即關閉連接。socket.pipe(destination)
:數(shù)據(jù)管道傳輸。
完整案例:簡單的 TCP 聊天應用
服務器端代碼
const net = require('net'); // 存儲所有連接的客戶端 const clients = new Set(); const server = net.createServer((socket) => { // 為每個客戶端分配唯一標識符 const clientId = `客戶端${Date.now().toString().slice(-4)}`; clients.add(socket); console.log(`${clientId} 已連接`); socket.write(`歡迎,你是 ${clientId}`); // 廣播消息給其他客戶端 socket.on('data', (data) => { const message = `${clientId}: ${data.toString()}`; clients.forEach((client) => { if (client !== socket) { client.write(message); } }); }); // 客戶端斷開連接 socket.on('end', () => { clients.delete(socket); console.log(`${clientId} 已斷開連接`); }); // 錯誤處理 socket.on('error', (err) => { console.error(`客戶端 ${clientId} 發(fā)生錯誤:`, err.message); clients.delete(socket); socket.destroy(); }); }); server.listen(3000, () => { console.log('聊天服務器已啟動,監(jiān)聽端口 3000'); });
客戶端代碼
const net = require('net'); const readline = require('readline'); // 創(chuàng)建標準輸入輸出接口 const rl = readline.createInterface({ input: process.stdin, output: process.stdout, }); // 連接到服務器 const client = net.createConnection({ port: 3000 }, () => { console.log('已連接到聊天服務器'); console.log('輸入消息并按 Enter 發(fā)送,輸入 "exit" 退出'); // 從標準輸入讀取用戶消息并發(fā)送給服務器 rl.on('line', (input) => { if (input.trim().toLowerCase() === 'exit') { client.end(); rl.close(); } else { client.write(input); } }); }); // 接收服務器消息并打印 client.on('data', (data) => { console.log(data.toString()); }); // 處理連接關閉 client.on('end', () => { console.log('已斷開與服務器的連接'); rl.close(); }); // 錯誤處理 client.on('error', (err) => { console.error('連接錯誤:', err.message); rl.close(); });
使用步驟
啟動服務器:
node server.js
啟動多個客戶端(在不同終端窗口):
node client.js
測試:
- 在客戶端輸入消息,按 Enter 發(fā)送。
- 所有客戶端(包括發(fā)送者)都會收到消息。
- 輸入
exit
退出客戶端。
注意事項
- 數(shù)據(jù)編碼:默認情況下,
net
模塊以二進制形式傳輸數(shù)據(jù),需通過toString()
轉換為字符串。 - 錯誤處理:務必監(jiān)聽
'error'
事件,避免未捕獲的異常導致程序崩潰。 - 連接管理:生產環(huán)境中需限制最大連接數(shù)(
server.maxConnections
),并實現(xiàn)心跳機制檢測死連接。 - 數(shù)據(jù)完整性:TCP 是流協(xié)議,需自行處理消息邊界(如通過分隔符或長度前綴)。
UDP
Node.js 的 dgram
模塊提供了創(chuàng)建 UDP(User Datagram Protocol)服務器和客戶端的功能。UDP 是一種無連接的傳輸協(xié)議,與 TCP 相比,它更輕量、傳輸速度更快,但不保證數(shù)據(jù)的可靠傳輸和順序。下面詳細介紹其核心功能、API 及使用案例。
核心功能與 API
1. 創(chuàng)建 UDP 服務器
使用 dgram.createSocket()
方法創(chuàng)建 UDP 套接字,監(jiān)聽消息:
const dgram = require('dgram'); // 創(chuàng)建 UDP 服務器(UDP4 表示 IPv4,UDP6 表示 IPv6) const server = dgram.createSocket('udp4'); // 監(jiān)聽消息事件 server.on('message', (msg, rinfo) => { console.log(`收到來自 ${rinfo.address}:${rinfo.port} 的消息: ${msg.toString()}`); // 向客戶端發(fā)送響應 const response = Buffer.from('服務器已收到消息'); server.send(response, rinfo.port, rinfo.address, (err) => { if (err) console.error('發(fā)送響應失敗:', err); }); }); // 監(jiān)聽錯誤事件 server.on('error', (err) => { console.error('服務器錯誤:', err); server.close(); }); // 監(jiān)聽啟動成功事件 server.on('listening', () => { const address = server.address(); console.log(`服務器監(jiān)聽在 ${address.address}:${address.port}`); }); // 綁定端口啟動服務器 server.bind(3000);
2. 創(chuàng)建 UDP 客戶端
同樣使用 dgram.createSocket()
創(chuàng)建套接字,向服務器發(fā)送消息并接收響應:
const dgram = require('dgram'); // 創(chuàng)建 UDP 客戶端 const client = dgram.createSocket('udp4'); // 準備要發(fā)送的消息 const message = Buffer.from('你好,這是客戶端發(fā)送的消息'); // 向服務器發(fā)送消息 client.send(message, 3000, 'localhost', (err) => { if (err) { console.error('發(fā)送消息失敗:', err); client.close(); return; } console.log('消息已發(fā)送到服務器'); }); // 監(jiān)聽服務器響應 client.on('message', (msg, rinfo) => { console.log(`收到來自 ${rinfo.address}:${rinfo.port} 的響應: ${msg.toString()}`); client.close(); }); // 監(jiān)聽錯誤事件 client.on('error', (err) => { console.error('客戶端錯誤:', err); client.close(); });
3. 核心對象與事件
dgram.Socket
:UDP 套接字對象,常用方法:socket.send(msg, port, address, callback)
:向指定地址和端口發(fā)送消息。socket.bind(port, [address], [callback])
:綁定端口啟動監(jiān)聽(服務器端使用)。socket.close()
:關閉套接字。socket.setBroadcast(flag)
:設置是否允許廣播。
常用事件:
'message'
:收到消息時觸發(fā),回調參數(shù)為(msg, rinfo)
,其中rinfo
包含發(fā)送方的地址和端口信息。'listening'
:套接字開始監(jiān)聽時觸發(fā)。'error'
:發(fā)生錯誤時觸發(fā)。'close'
:套接字關閉時觸發(fā)。
完整案例:簡單的 UDP 消息應用
服務器端代碼
const dgram = require('dgram'); // 創(chuàng)建 UDP 服務器 const server = dgram.createSocket('udp4'); // 存儲所有客戶端信息(實際應用中可能需要更復雜的管理) const clients = new Set(); // 監(jiān)聽消息事件 server.on('message', (msg, rinfo) => { const clientKey = `${rinfo.address}:${rinfo.port}`; // 首次收到消息時記錄客戶端信息 if (!clients.has(clientKey)) { clients.add(clientKey); console.log(`新客戶端 ${clientKey} 已連接`); } console.log(`收到 ${clientKey} 的消息: ${msg.toString()}`); // 廣播消息給所有客戶端(除發(fā)送者外) clients.forEach((client) => { if (client !== clientKey) { const [address, port] = client.split(':'); server.send(`${clientKey}: ${msg.toString()}`, parseInt(port), address); } }); }); // 監(jiān)聽錯誤事件 server.on('error', (err) => { console.error('服務器錯誤:', err); server.close(); }); // 監(jiān)聽啟動成功事件 server.on('listening', () => { const address = server.address(); console.log(`服務器監(jiān)聽在 ${address.address}:${address.port}`); }); // 綁定端口啟動服務器 server.bind(3000);
客戶端代碼
const dgram = require('dgram'); const readline = require('readline'); // 創(chuàng)建標準輸入輸出接口 const rl = readline.createInterface({ input: process.stdin, output: process.stdout, }); // 創(chuàng)建 UDP 客戶端 const client = dgram.createSocket('udp4'); // 服務器地址和端口 const serverAddress = 'localhost'; const serverPort = 3000; // 提示用戶輸入消息 console.log('輸入消息并按 Enter 發(fā)送,輸入 "exit" 退出'); // 從標準輸入讀取用戶消息并發(fā)送給服務器 rl.on('line', (input) => { if (input.trim().toLowerCase() === 'exit') { client.close(); rl.close(); return; } const message = Buffer.from(input); client.send(message, serverPort, serverAddress, (err) => { if (err) console.error('發(fā)送消息失敗:', err); }); }); // 監(jiān)聽服務器或其他客戶端的消息 client.on('message', (msg, rinfo) => { console.log(`收到 ${rinfo.address}:${rinfo.port} 的消息: ${msg.toString()}`); }); // 監(jiān)聽錯誤事件 client.on('error', (err) => { console.error('客戶端錯誤:', err); client.close(); rl.close(); }); // 綁定客戶端端口(可選,不指定時系統(tǒng)會分配隨機端口) client.bind(() => { const address = client.address(); console.log(`客戶端已啟動,使用端口 ${address.port}`); });
使用步驟
啟動服務器:
node udp_server.js
啟動多個客戶端(在不同終端窗口):
node udp_client.js
測試:
- 在任一客戶端輸入消息,按 Enter 發(fā)送。
- 所有客戶端(包括發(fā)送者)都會收到消息。
- 輸入
exit
退出客戶端。
注意事項
- 消息大小限制:UDP 數(shù)據(jù)包有最大大小限制(通常為 65,507 字節(jié)),超過限制的消息會被丟棄。
- 不可靠傳輸:UDP 不保證消息的可靠到達和順序,適合對實時性要求高但對數(shù)據(jù)完整性要求較低的場景(如視頻流、游戲)。
- 廣播和組播:UDP 支持廣播(
255.255.255.255
)和組播(如224.0.0.1
),可通過socket.setBroadcast(true)
啟用。 - 錯誤處理:盡管 UDP 不可靠,但仍需監(jiān)聽
'error'
事件處理網(wǎng)絡錯誤。
到此這篇關于Node.js 的 TCP 和 UDP的文章就介紹到這了,更多相關Node.js TCP 和 UDP內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
一文詳解Node中module.exports和exports區(qū)別
這篇文章主要介紹了一文詳解Node中module.exports和exports區(qū)別2023-03-03輕松創(chuàng)建nodejs服務器(7):阻塞操作的實現(xiàn)
這篇文章主要介紹了輕松創(chuàng)建nodejs服務器(7):阻塞操作的實現(xiàn),本文先是組出了代碼,然后對代碼一一分析,需要的朋友可以參考下2014-12-12用node擼一個監(jiān)測復聯(lián)4開售短信提醒的實現(xiàn)代碼
這篇文章主要介紹了用node擼一個監(jiān)測復聯(lián)4開售短信提醒的實現(xiàn)代碼,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2019-04-04