详解使用nodejs+Socket打造P2P实时聊天室

Posted 勇敢*牛牛

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了详解使用nodejs+Socket打造P2P实时聊天室相关的知识,希望对你有一定的参考价值。

在此之前我们再次聊聊socket服务

Socket 服务

套接字(socket)是一个抽象层,应用程序可以通过它发送或接收数据,可对其进行像对文件一样的打开、读写和关闭等操作。套接字允许应用程序将I/O内容插入到网络中,并与网络中(服务器)的其他应用程序进行通信。网络套接字是IP地址与端口的组合。

我们将一个小区比作一台计算机,一台计算机里面跑了很多程序,怎么区分程序呢,用的是端口,就好像小区用门牌号区分每一户人家一样。手机送到小明家了,怎么进去呢?从大门进啊,怎么找到大门呢?门牌号呀。不就相当于从互联网来的数据找到接收端计算机后再根据端口判断应该给哪一个程序一样吗。小明家的入口就可以用小区地址+门牌号进行唯一表示,那么同样的道理,程序也可以用IP+端口号进行唯一标识那么这个程序的入口就被称作Socket

现在再来说说什么是Socekt编程,我们将TCP协议简化一下,就只有三个核心功能:建立连接发送数据以及接收数据

第一步:简单创建socket服务与客户端client的连接

  • 模块化IP地址和端口号(config.js)(模块化编程更加凸显对程序可维护性的提高)
// 用户的主机号和端口号
module.exports = 
    'port': 3000,
    "host": '127.0.0.1'

  • 在之后一直使用这个模块
/**
 * 创建服务器
 */
var net = require('net');
var path = require('path');
var config = require(path.join(__dirname, './config'));
var serve = net.createServer();
serve.on('connection', function (socket) 
    /*    
        *检测一般客户端是否连接成功
        socket.on("data", function (data) 
            console.log("有客户端接入的信息" + data);
        )
    */
    socket.on("data", function (data) 
        console.log("有客户端接入的信息" + data);
       /*此处暂时可省略很多代码*/
       /*此处暂时可省略很多代码*/
       /*此处暂时可省略很多代码*/
       /*此处暂时可省略很多代码*/
       /*此处暂时可省略很多代码*/
    )
    socket.on('error', function () 
        console.log("有客户端异常退!!!");
    )
)
serve.listen(config.port, config.host, function () 
    console.log("服务器在端口号" + config.port + '启动了监听');
)
  • 搭建简单的socket服务器之后,接入客户端检测是否能成功接入到服务器(client.js)
//导入net
var net = require('net');
var path = require('path')
var config = require(path.join(__dirname, './config'));
// 创建连接,产生socket对象
var client = net.createConnection(
    host: config.host,
    port: config.port
)
var username = '';
// 输入消息
client.on('connect', function () 
    console.log('进入聊天室......\\n请输入用户名:');
    /**
     * 准备输入聊天信息
     * nodejs中提供了process模块,支持终端设备进行IO操作,全局模块。不需要导入
     * stdin对象获得键盘输入(回车后)
     * 接收到键盘输入,就将消息发送到服务器
     */
    process.stdin.on('data', function (data) 
        data = data.toString().trim();

    );
)
//接收服务端的socket信息
client.on('data', function (data) 
    console.log(JSON.parse(data));
  	
);
client.on('error', function () 
    console.log('服务器异常退出。');
)
  • 注册signup.js模块,首次对信息在服务端进行包装
exports.signup = function (socket, data, users) 
    var username = data.username;
    if (!users[username]) //用户不存在,保存用户名和socket
        users[username] = socket;//保存用户名和socket
        // console.log(users);
        var send = 
            mstype: 'signup',
            code: 1000,
            username: username,
            message: "注册成功"
        ;
        socket.write(JSON.stringify(send));
     else 
        var send = 
            mstype: 'signup',
            code: 1001,
            message: '用户名已被占用,请重新输入用户名'
        ;
        socket.write(JSON.stringify(send));
    

  • 注册完自己的信息后开始编写自己的发送信息

第二步:根据不同的类型信息重新构架Message架构

  • 根据构建的信息,判断这个是broadcast还是p2p 的mstype
在这里插入代码片/**
 * 对广播的消息进行处理
 * @param * data 
 * @param * users 
 */
exports.broadcast = function (data, users) 
    // 函数的data形参就是一个对象数据
    var from = data.from;               //获得发消息方
    var message = data.message;         //获得消息
    message = from + '说:' + message;   //改变消息架构

    // 构建发送消息框架
    var send = 
        mstype: 'broadcast',            //因为消息聊天室消息需要广播,所以在此设置类型
        message: message
    

    send = Buffer.from(JSON.stringify(send));   //对象解析为字符串给send,buffer缓冲池
    for (var username in users) 
        if (username != from) 
            users[username].write(send);            //除发送方之外的人写入框架信息
        
    

  • p2p的处理方式
exports.p2p = function (socket, data, users) 
    var from = data.from;
    var to = data.to;
    var message = data.message;
    var receiver = users[to];
    if (!receiver) 
        var send = 
            mstype: 'p2p',
            code: 2001,
            message: "用户" + to + "不存在"
        
        socket.write(JSON.stringify(send));
     else 
        var send = 
            mstype: 'p2p',
            code: 2000,
            from: from,
            message: from + " 对你说" + message
        
        socket.write(JSON.stringify(send));
    

  • 客户端对他们三种情况(注册,broadcast,p2p)接受的处理
//导入net
var net = require('net');
var path = require('path')
var config = require(path.join(__dirname, './config'));
// 创建连接,产生socket对象
var client = net.createConnection(
    host: config.host,
    port: config.port
)
var username = '';
// 输入消息
client.on('connect', function () 
    console.log('进入聊天室......\\n请输入用户名:');
    /**
     * 准备输入聊天信息
     * nodejs中提供了process模块,支持终端设备进行IO操作,全局模块。不需要导入
     * stdin对象获得键盘输入(回车后)
     * 接收到键盘输入,就将消息发送到服务器
     */
    process.stdin.on('data', function (data) 
        data = data.toString().trim();
        // 判断用户是否已经有来注册用户名
        if (!username) // 没有注册的话
            var send = 
                mstype: 'singup',
                username: data
            
            client.write(JSON.stringify(send));
            // console.log("注册成功");
            return;
        
        var regex = /(.1,18):(.+)/;
        var matches = regex.exec(data);
        if (matches) 
            var from = username;
            var to = matches[1];
            var message = matches[2];
            var send = 
                mstype: 'p2p',
                from: from,
                to: to,
                message: message
            
            client.write(JSON.stringify(send));
         else 
            var send = //广播消息
                mstype: 'broadcast',
                from: username,
                message: data
            ;
            client.write(JSON.stringify(send))
        

    );
)
//接收服务端的socket信息
client.on('data', function (data) 
    //console.log(JSON.parse(data));
    data = JSON.parse(data);
    // console.log(data.mstype);
    switch (data.mstype) 
        case "signup":
            var code = data.code;
            switch (code) 
                case 1000:
                    username = data.username;
                    console.log(data.message);
                    break;
                case 1001:
                    console.log(data.message);
                    break;
                default:
                    break;
            
            break;
        case 'broadcast':
            console.log(data.message);
            break;
        case 'p2p':
            var code = data.code;
            switch (code) 
                case 2000:
                    username = data.username;
                    console.log(data.message);
                    break;
                case 2001:
                    console.log(data.message);
                    break;
                default:
                    break;
            
            break;
        default:
            break;
    
);
client.on('error', function () 
    console.log('服务器异常退出。');
)

第三步:按照类型的不同向对方发送信息

/**
 * 创建服务器
 */
var net = require('net');
var path = require('path');
const  p2p  = require('./p2p');
var config = require(path.join(__dirname, './config'));
var broadcast = require(path.join(__dirname, './broadcast'));
var signup = require(path.join(__dirname, './signup'));

var serve = net.createServer();
var users = ;
/*检测congfig加载是否成功
if(config)
    console.log("congfig加载成功");

if (signup) 
    console.log(typeof (signup.signup));
*/

serve.on('connection', function (socket) 
    /*    
        *检测一般客户端是否连接成功
        socket.on("data", function (data) 
            console.log("有客户端接入的信息" + data);
        )
    */
    socket.on("data", function (data) 
        console.log("有客户端接入的信息" + data);
        // 将字符串转化为对象
        data = JSON.parse(data);
        switch (data.mstype) 
            case "singup": signup.signup(socket, data, users); break;
            case "broadcast": broadcast.broadcast(data, users); break;
            case 'p2p': p2p.p2p(socket, data, users); break;
            default: break;
        
    )
    socket.on('error', function () 
        console.log("有客户端异常退!!!");
    )
)
serve.listen(config.port, config.host, function () 
    console.log("服务器在端口号" + config.port + '启动了监听');
)

以上是关于详解使用nodejs+Socket打造P2P实时聊天室的主要内容,如果未能解决你的问题,请参考以下文章

基于 NodeJs 打造 Web 在线聊天室

P2P中的NAT穿越(打洞)方案详解

P2P中的NAT穿越(打洞)方案详解

基于webrtc以及nodejs的P2P实时视频demo

nodejs+websocket实现聊天室功能

nodejs 打造 多人对战游戏服务器(初级入门)