Nodejs中socket如何同时读写?

Nodejs中socket如何同时读写?

有一个server,同时实现如下功能: 1.读取客户端发送的消息写数据库。 2.读取数据一个表的数据发送个客户端。

不是等待读完再写或者写完再读,而是同时进行。

如果其他语言实现的话可能2个线程一直循环做不同的事情,

请问node.js中如何实现。

非常感谢。

5 回复

在Node.js中,由于其单线程、事件驱动的特性,我们通常使用异步编程来实现并发操作。对于您的需求(同时读取客户端消息并写入数据库,以及从数据库读取数据并发送给客户端),可以利用回调函数、Promise或async/await语法来实现。

以下是一个简单的示例,展示如何使用net模块创建服务器,并同时处理读写操作。这里以一个基本的TCP服务器为例,该服务器将监听客户端消息,同时定期向客户端发送数据。

const net = require('net');

// 创建一个TCP服务器
const server = net.createServer((socket) => {
    console.log('Client connected');

    // 定义一个定时器,每隔一段时间向客户端发送数据
    const sendInterval = setInterval(() => {
        socket.write('Hello from server\n');
    }, 5000);

    // 处理客户端发送的数据
    socket.on('data', (data) => {
        console.log(`Received: ${data.toString()}`);

        // 将接收到的数据写入到数据库(这里简化为打印)
        writeDataToDatabase(data);
    });

    // 处理客户端断开连接
    socket.on('end', () => {
        clearInterval(sendInterval);
        console.log('Client disconnected');
    });
});

// 模拟将数据写入数据库的函数
function writeDataToDatabase(data) {
    console.log(`Writing to database: ${data.toString()}`);
}

server.listen(3000, () => {
    console.log('Server listening on port 3000');
});

解释

  • 服务器创建:使用net.createServer()创建一个TCP服务器。
  • 定时发送:通过setInterval()设置一个定时器,每隔5秒向客户端发送一次消息。
  • 处理数据:当接收到客户端发送的数据时,触发socket.on('data')事件。在这个事件处理程序中,我们打印接收到的数据,并模拟将其写入数据库。
  • 数据库写入:这里的writeDataToDatabase()只是一个简单的函数,用于打印接收到的数据。实际应用中,您可以替换为实际的数据库操作代码。
  • 客户端断开:当客户端断开连接时,清除定时器并打印日志。

这种方法利用了Node.js的非阻塞I/O模型,使得读写操作可以并发执行,而不会阻塞主线程。


两个线程跑就是系统在切换线程执行, 实际上是一个线程在 CPU 上跑. Node 里 JS 执行是单线程的, 但通过回调会调用 JS 引擎以外的代码, 而在触发回调前执行的代码是可以同时多个线程在跑的, 也有交替执行的效果.

比如下面的代码, reqreq2 就是交替打印的:

var http, options, req, req2;

http = require(“http”);

options = { hostname: ‘www.qq.com’, port: 80, path: ‘/’, method: ‘GET’ };

req = http.request(options, function(res) { res.setEncoding(“utf8”); return res.on(“data”, function(chunk) { return console.log(“req…”); }); });

req2 = http.request(options, function(res) { res.setEncoding(“utf8”); return res.on(“data”, function(chunk) { return console.log(“req2…”); }); });

req.end();

req2.end();

谢谢 ” 两个线程跑就是系统在切换线程执行, 实际上是一个线程在 CPU 上跑. “

这个我是明白的,但是node.js不是很熟悉

我的程序结构应该是这样的:

var server = net.createServer( function(c) {

c.on(‘data’, function(data) { //do something //write db });

//1

});

function serverStart () { server.listen(SERVER_PORT, function() { console.log(‘server bound’); });
}

serverStart();

我想在这个主流程之外同时有个循环,主动给客户端发包

while true {
 //read from db
 //write to current client
}

我是想了解,这段代码放在那个位置?

现在的实现是在//1位置放了个: setInterval(SomeFunc, 1000);

但是这个不是很符合我的需求(考虑到一次调用没完成到时间又跑一次,需要一些标记变量来判断是否执行之类的)。

请问如何实现,谢谢。

“读取数据一个表的数据”的回调函数应该是异步的,“读取客户端发送的消息写数据库”的回调函数也是异步的,所以两者之间的发生时间是没有先后顺序的。

在Node.js中,你可以使用事件驱动和非阻塞I/O模型来实现同时读写socket。这里的关键在于利用异步编程技术,例如回调函数、Promise或async/await。为了实现你的需求,可以使用net模块创建TCP服务器,并通过事件处理程序来同时读写socket。

下面是一个简单的示例,展示如何使用net模块实现上述功能:

const net = require('net');
const { promisify } = require('util');

// 创建服务器
const server = net.createServer((socket) => {
    console.log('Client connected');

    // 设置socket的错误监听器
    socket.on('error', (err) => {
        console.error('Socket error:', err);
    });

    // 用于处理从数据库读取数据的操作
    const readFromDatabase = async () => {
        // 假设这是一个异步操作,从数据库读取数据
        const data = await promisify(readDataFromTable)();
        socket.write(data);
    };

    // 模拟从客户端读取消息并写入数据库的操作
    const writeMessageToDB = async (message) => {
        await promisify(writeMessage)(message);
    };

    // 监听socket的数据接收事件
    socket.on('data', async (data) => {
        console.log(`Received message: ${data.toString()}`);
        await writeMessageToDB(data.toString());
    });

    // 定时从数据库读取数据发送给客户端
    setInterval(() => {
        readFromDatabase();
    }, 5000); // 每5秒读一次数据库

    // 处理客户端断开连接
    socket.on('end', () => {
        console.log('Client disconnected');
    });
});

// 启动服务器
server.listen(3000, () => {
    console.log('Server listening on port 3000');
});

// 示例函数:模拟从数据库读取数据
function readDataFromTable() {
    return new Promise(resolve => {
        setTimeout(() => {
            resolve('Data from database');
        }, 1000);
    });
}

// 示例函数:模拟将消息写入数据库
function writeMessage(message) {
    return new Promise(resolve => {
        setTimeout(() => {
            console.log(`Message written to DB: ${message}`);
            resolve();
        }, 1000);
    });
}

解释

  1. 服务器创建:使用net.createServer()创建一个TCP服务器,并传入一个回调函数,当有新连接时调用该函数。
  2. 数据读取与写入:为socket对象添加data事件监听器,当接收到客户端数据时触发。在此示例中,我们将数据作为字符串处理,并将其传递给writeMessageToDB函数以模拟写入数据库的操作。
  3. 定时任务:使用setInterval每5秒调用一次readFromDatabase函数,模拟从数据库读取数据并发送给客户端的过程。
  4. 错误处理:为socket添加error事件监听器,以便在发生错误时捕获它们。
  5. 断开连接:添加end事件监听器来处理客户端断开连接的情况。

以上代码展示了如何在Node.js中同时处理读写socket,同时执行数据库读写操作。注意,这里的数据库读写是模拟的,你需要根据实际情况替换为实际的数据库操作。

回到顶部