当我们去面试的时候,常常会遇到这样一个问题:当用户在浏览器地址栏输入一段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(' boardcast[' + signal.from + ']> ' + signal.message + ' '); 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}】端口`); });