Node.js利用Net模块实现多人命令行聊天室的方法
这篇文章介绍的是Node.js利用Net模块实现命令行式的多人聊天室,下面话不多说,来看看详细的介绍吧。
1、net模块基本API
要使用Node.js的net模块实现一个命令行聊天室,就必须先了解NET模块的API使用。NET模块API分为两大类:
Server和Socket类、工厂方法。
Server类如下图所示:
net.Server类可以用来创建一个TCP或本地服务器,继承了EventEmitter。
Socket类如下:
net.Socket类一般用创建一个socket客户端或者是net.Server connection事件的参数。
工厂方法如下:
以上三个图展示了API的使用,其实NET模块的内部原理和C++网络编程差不多的,都是以下步骤。
服务端:
创建socket套接字 绑定IP和端口 启动监听 等待客户端连接 与客户端进行通信 关闭socket客户端:
创建socket套接字 连接server服务器 与服务器进行通信 关闭socket如下图所示:
2、聊天室的设计和实现
上面学习了NET模块API的使用,接下来便开始实现命令行聊天室,我们不需要做的很复杂,只需实现如下功能即可:
用户自定义昵称,不可更改 当有新的用户进入聊天室,或者用户离开聊天室,广播给其他用户 用户发送信息,需广播给其他用户 客户端与服务端建立心跳机制 用户输入'exit'或者'quit'可以退出聊天室确定功能之后,便开始代码的编写。这里我就不一步步分析,直接上代码了,首先是服务端:
Server:
const net = require('net');
const server = net.createServer();
const clients = {};//保存客户端的连接
var client = null;//当前客户连接
var uid = 0;
server.on('connection',(socket)=>{
//启动心跳机制
var isOnline = !0;
var keepAliveTimer = socket.timer = setInterval(()=>{
if(!isOnline){
isOnline = !1;
client = socket;
quit(socket.nick);
return;
}
if(socket.writable){
socket.write('::');
}else{
client = socket;
quit(socket.nick);
}
},3000);
socket.on('end',()=>{
console.log(`client disconnected.nr`);
socket.destroy();
});
socket.on('error',(error)=>{
console.log(error.message);
});
socket.on('data',(chunk)=>{
client = socket;
var msg = JSON.parse(chunk.toString());
if(msg.cmd=='keep'){
isOnline = !0;
return;
}
dealMsg(msg);
});
});
server.on('error',(err)=>{
console.log(err);
});
server.on('listening',()=>{
console.log(`listening on ${server.address().address}:${server.address().port}nr`);
});
server.listen(8060);//启动监听
function dealMsg(msg){
const cmd = msg.cmd;
const funs = {
'login':login,
'chat':chat,
'quit':quit,
'exit':quit
};
if(typeof funs[cmd] !== 'function') return !1;
funs[cmd](msg);
}
function freeConn(conn){
conn.end();
delete clients[conn.uuid];
conn.timer&&clearInterval(conn.timer);
}
function login(msg){
var uuid = '';
uuid = getRndStr(15)+(++uid);//产生用户ID
client.write(`欢迎你,${msg.nick}:这里总共有${Object.keys(clients).length}个小伙伴在聊天.rn`)
client.nick = msg.nick;
client.uuid = uuid;
clients[uuid] = client;
broadcast(`系统:${msg.nick}进入了聊天室.`);
}
function broadcast(msg){
Object.keys(clients).forEach((uuid)=>{
if((clients[uuid]!=client)& clients[uuid].writable){
clients[uuid].write(msg);
}
});
}
function quit(nick){
var message = `小伙伴${nick}退出了聊天室.`;
broadcast(message);
freeConn(client);
}
function chat(msg){
if(msg.msg.toLowerCase()=='quit'||msg.msg.toLowerCase()=='exit'){
quit(msg.nick);
return ;
}
var message = `${msg.nick}说:${msg.msg}`;
broadcast(message);
}
function getRndStr(len=1){
var rndStr = '';
for (; rndStr.length < len; rndStr += Math.random().toString(36).substr(2));
return rndStr.substr(0, len);
}
客户端代码如下:
client:
const net = require('net');
const cout = process.stdout;
const cin = process.stdin;
var client = null;
var nick = '';
cout.write(`请输入昵称:`);
//监听命令行输入
cin.on('data',(chunk)=>{
if(chunk.toString()!='rn'){
if(client === null){
nick = (chunk+'').replace(/[rn]/ig,"");
createClient();
}else{
msg = (chunk+'').replace(/[rn]/ig,"");
client.write(JSON.stringify({
cmd: 'chat',
msg: msg,
nick: nick
}));
//如果输入是exit或quit则断开连接并退出
if(msg.toLowerCase() == 'exit' || msg.toLowerCase() == 'quit'){
client.end();
cin.end();
return;
}
cout.write(`你说:${msg}nr`);
}
}else{
cout.write(`请输入昵称:`);
}
});
function addListener(client) {
client.on('connect', () => {
cout.write(`已连接到服务器nr`);
client.write(JSON.stringify({
cmd: 'login',
msg: 'hello server',
nick: nick
}));
});
client.on('end', (chunk) => {
cout.write(`与服务器断开连接.nr`);
});
client.on('data', (chunk) => {
//如果是心跳信息则回应keep命令
if(chunk.toString()=='::'){
client.write(JSON.stringify({
cmd: 'keep',
msg: '',
nick: nick
}));
return ;
}
cout.write(`${chunk}nr`);
});
client.on('error', (err) => {
cout.write(`an error has occured.nr${err}`);
});
}
function createClient(){
console.log('33[2J');//清屏操作
cout.write(`输入'EXIT OR QUIT'退出聊天室.rn`);
client = new net.Socket()
client.connect({port:8060});
addListener(client);
}
执行结果如下如下:
到此,一个命令行聊天室便做完了。
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流。
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341