當我們去面試的時候,常常會遇到這樣一個問題:當用戶在瀏覽器地址欄輸入一段url發出資源請求后,到服務端返回數據呈現給用戶的這個過程都發生了什么?
我們把進行通信的這兩個端(這里指的是,瀏覽器和資源獲取的地方)稱之為客戶端和服務端。我們連通兩個端進行通信,靠的就是socket這個東西。他將特定格式的內容進行傳遞,以達到客戶端和服務端通信的目的。
最近剛好在學習node的net模塊,接觸到這一塊內容。下面就來看看node中socket通信的一種實現方式。
client.js
// 客戶端 const net = require('net'); const readline = require('readline'); const rl = readline.createInterface(process.stdin, process.stdout); rl.question('What is your name? ', (name) => { name = name.trim(); if (!name) { throw new Error('名字沒有提供'); } // 創建於服務端的連接 var server = net.connect({ port: 2080, host: '192.168.1.56' }, () => { console.log(`Welcome ${name} to 2080 chatroom`); // 監聽服務端發過來的數據 server.on('data', (chunk) => { try { var signal = JSON.parse(chunk.toString().trim()); var procotol = signal.procotol; switch (procotol) { case 'boardcast': console.log('\nboardcast[' + signal.from + ']> ' + signal.message + '\n'); rl.prompt(); break; default: server.write('再瞅試試!'); break; } } catch (error) { server.write('你瞅啥!'); } }); rl.setPrompt(name + '> '); // 此時沒有寫到控制台 rl.prompt(); // 寫入控制台 // 輸入一行內容敲回車觸發 rl.on('line', (line) => { // {"procotol":"boardcast","from":"張三","message":"你瞅啥!"} var send = { procotol: 'boardcast', from: name, message: line.toString().trim() }; server.write(JSON.stringify(send)); rl.prompt(); }) .on('close', () => { // console.log('Have a great day!'); // process.exit(0); }); }); });
server.js
// 建立一個Socket服務端 const net = require('net'); // 用於存儲所有的客戶端連接 var clients = []; var server = net.createServer((socket) => { // socket.setEncoding('utf8'); // 哪個客戶端與我連接socket就是誰 clients.push(socket); console.log(`Welcome ${socket.remoteAddress} to 2080 chatroom 當前在線${clients.length}`); // 觸發多次 socket .on('data', clientData) .on('error', (err) => { clients.splice(clients.indexOf(socket), 1); console.log(`${socket.remoteAddress}下線了 當前在線${clients.length}`); }); }); // 廣播消息 function boardcast(signal) { // console.log(signal); // 肯定有用戶名和消息 var username = signal.from; var message = signal.message; // 我們要發給客戶端的東西 var send = { procotol: signal.procotol, from: username, message: message }; // 廣播消息 遍歷每一個客戶端,並向其寫入內容 clients.forEach(client => { client.write(JSON.stringify(send)); }); } // 有任何客戶端發消息都會觸發 function clientData(chunk) { // chunk:boardcast|張三|你瞅啥! // chunk:{"procotol":"boardcast","from":"張三","message":"你瞅啥!"} // chunk:{"procotol":"p2p","from":"張三","to":"李四","message":"瞅你咋地!"} try { var signal = JSON.parse(chunk.toString().trim()); var procotol = signal.procotol; switch (procotol) { case 'boardcast': boardcast(signal); break; // case 'p2p': // p2p(signal); // break; // case 'shake': // shake(signal); // break; default: socket.write('再瞅試試!'); break; } } catch (error) { socket.write('你瞅啥!'); } } var port = 2080; server.listen(port, (err) => { if (err) { console.log('端口被占用'); return false; } console.log(`服務端正常啟動監聽【${port}】端口`); });