Node.js中TCP及聊天室的实现

前言

OSI网络模型分七层,由下至上分别为:物理层数据链路层网络层传输层会话层表示层应用层,TCP协议处于传输层。

Node.js中TCP

Node.js中的 net 模块提供了对TCP协议的封装,使用 net 模块可以轻松的构建一个TCP服务器,或构建一个连接TCP服务器的客户端。

net模块创建一个服务器

let net = require('net')

let server = net.createServer()
server.on('connection', function (socket) {
    // socket套接字 会话,http有请求 响应
    console.log('connection success')
})
server.listen(3000, function () {
    console.log('server start at 3000')
})
复制代码

这样就创建了一个简单的服务。启动在3000端口,并且会监听客户端的连接。socket表示套接字,是一个可读可写的双工流,可以理解为客户端和服务端之间的会话。

接收数据

socket.setEncoding('utf8')
socket.on('data', function (data) {
    console.log(data)
})
复制代码

响应数据

socket.write('nice to meet you')
复制代码

关闭客户端

socket.end('end...') // 关闭客户端
复制代码

关闭服务端

server.close(); // 如果触发close事件就不会再接收新的请求了
server.unref(); // 也表示关闭 ,没有客户端连接会自己关闭(不会触发close事件)

server.on('close', function () {
    console.log('server closed')
})
复制代码

close调用后, 服务端不再接收新的请求,当没有客户端连接,会触发close事件,并关闭服务端

unref调用后,服务端继续接受新的请求,当没有客户端连接,不会触发close事件,并关闭服务端。

设置最大连接数

server.maxConnections = 2; // 设置最大连接数,超过数量不能连接
复制代码

聊天室的实现

有了上面的知识,我们可以动手实现一个聊天室。

需求

  • 当前用户在线数,最多可连接的用户数;
  • 输入 l:, 查看当前用户列表;
  • 输入 s:zs: hello, 向张三发送消息;
  • 输入 r: ls, 给自己重命名为ls;
  • 输入 b: nice to meet you, 向其他用户广播消息

创建服务

let net = require('net');

let server = net.createServer((socket) => {
    let key = socket.remoteAddress + socket.remotePort
    console.log(key)
})
server.listen(3000, function () {
    console.log('server start at 3000')
})
复制代码

缓存客户端信息

let client = {}
let server = net.createServer((socket) => {
    // 显示欢迎信息
    server.maxConnections = 3;
    server.getConnections(function (err, count) {
        socket.write(`欢迎到来,当前用户 ${count},总容纳 ${server.maxConnections}\r\n`)
    })
    // 缓存用户
    let key = socket.remoteAddress + socket.remotePort
    client[key] = {nickname: '匿名',socket}
})
复制代码

缓存客户端信息到 client中,以客户的ip+port作为key值,nickname默认为匿名,并保存回话socket。

处理客户端输入的指令

    socket.setEncoding('utf8')
    socket.on('data', function (chunk) {
        chunk = chunk.replace(/\r\n/,'')
        let [command, target, content] = chunk.split(':')
        switch (command) {
            case 'l':  //查看用户列表
                showList(socket);
                break;
            case 's':  //私聊
                charTo(target,content, client[key].nickname);
                break;
            case 'r': //重命名
                rename(key, target);
                break;
            case 'b': //想其他用户广播
                broadcast(key, target, client[key].nickname);
                break;
            default:
                break;
        }
    })
复制代码

处理函数的实现

showList 函数的实现

function showList(socket) {
    let users = []
    Object.values(client).forEach(user => {
        users.push(user.nickname)
    })
    socket.write(`当前用户列表:\r\n ${users.join('\r\n')} \r\n`)
}
复制代码

charTo函数的实现

function charTo(target, content, source) {
    let targetSocket;
    Object.values(client).forEach(user => {
        if(user.nickname === target) {
            targetSocket = user.socket
        }
    })
    targetSocket.write(`${source}${content}\r\n`)
}
复制代码

rename函数的实现

function rename(key, content) {
    client[key].nickname = content;
    client[key].socket.write(`重命名为: ${content}\r\n`)
}
复制代码

broadcast函数的实现

function broadcast(key, content, nickname) {
    Object.keys(client).forEach(user => {
        if(user !== key) {
            client[user].socket.write(`${nickname}: ${content}\r\n`)
        }
    })
}
复制代码

成果检验

我们的建议聊天室就做好了,大家可以使用 PuTTY这个软件作为客户端发送tcp请求;

下面是我测试的结果。

结语

自己实现一个聊天室的过程还是挺有意思的,欢迎喜欢捣鼓的同学多多交流。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值