服务器与客户端的TCP连接


我们的目的是在终端实现服务器和客户端的TCP通讯:
也就是说以代码来实现:
程序的缺点:当其中一个客户端退出,服务器就退出了,导致其他正在访问的客户端与服务器失去了连接;

相关的网站:

https://blog.youkuaiyun.com/qq_41885673/article/details/122216791
https://www.v5w.com/plc/566.html
https://www.v5w.com/js/js%e7%9f%a5%e8%af%86%e7%82%b9/433.html
https://www.youkuaiyun.com/tags/NtDaMgwsNDYwMS1ibG9n.html
https://zhuanlan.zhihu.com/p/411656922

一.第一个案例

链接:https://blog.youkuaiyun.com/weixin_36247891/article/details/112831201?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522165216334016781683970991%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=165216334016781683970991&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allfirst_rank_ecpm_v1~rank_v31_ecpm-1-112831201-null-null.142v9control,157v4control&utm_term=ModbusTCP%E7%9A%84js%E5%AE%9E%E7%8E%B0&spm=1018.2226.3001.4187
nodejs中使用modbus-serial库创建Modbus TCP读取设备的数据

在nodejs中安装modbus-serial库

本人使用的开发环境是Windows10下的VSCode,安装并配置好了npm、node、cnpm等工具,使用cnpm安装了modbus-serial库,可以在npm中搜到modbus-serial包以及它的介绍,

在对应的VSCode终端下使用cnpm install modbus-serial -g安装modbus-serial库
cnpm install modbus-serial -g

非甲烷总烃分析仪有三个关键参数,即总烃、CH4、NMHC的浓度,对应Modbus寄存器地址分别为:22,25,28,获取对应寄存器数据后还需要乘以0.01

使用modbus-serial库,使用Modbus TCP协议读取对应寄存器中的数据

相关nodejs代码如下:

var moment = require('moment')

// create an empty modbus client(创建一个空的 modbus 客户端)

var ModbusRTU = require("modbus-serial")

var client = new ModbusRTU();

// open connection to a tcp line(打开与 tcp 线路的连接)

// 创建Modbus TCP连接,IP是15.18.200.23,端口502

client.connectTCP("15.18.200.23", { port: 502 });

// 读取非甲烷总烃的关于总烃、甲烷、NMHC这3个寄存器(寄存器地址分别为22,25,28)中的浓度

// 每隔5秒钟读取保持寄存器的值,从寄存器地址22开始读取,读10个寄存器到data数组中

setInterval(function(){

client.readHoldingRegisters(22, 10, function(err, data){

// 获取当前时间

//moment.locale('zh-cn');

console.log("----------------------------------------------------------------------");

console.log("数据时间是:" + moment().format('YYYY年MM月DD日 HH时mm分ss秒'));

console.log("总烃的浓度是:" + data.data[0] * 0.01 + "ppmV");// 总烃浓度对应的寄存器地址为22

console.log("CH4的浓度是:" + data.data[3] * 0.01 + "ppmV"); // CH4浓度对应的寄存器地址为25

console.log("NHMC的浓度是:" + data.data[6] * 0.01 + "ppmV"); // NHMC浓度对应的寄存器地址为28

console.log("----------------------------------------------------------------------");

//console.log(data.data);

});

}, 5000);

上述代码使用了JavaScript 日期处理类库Moment.js对当前日期进行格式化,相关介绍见Moment.js-JavaScript 日期处理类库

使用很简单,比如项要获取当前的时间,按照2019年12月9日 16时07分23秒这种格式输出,代码如下:

var moment = require('moment');

var currentTime = moment().format('YYYY年MM月DD日 HH时mm分ss秒');

console.log("当前时间为:" + currentTime);

nodejs中安装moment库也很简单,一条命令搞定,如下:

cnpm install moment -g

相关代码测试输出如下:


数据时间是:2019年12月11号 16时07分56秒

总烃的浓度是:2.78ppmV

CH4的浓度是:2.07ppmV

NHMC的浓度是:0.70ppmV



数据时间是:2019年12月11号 16时08分01秒

总烃的浓度是:2.78ppmV

CH4的浓度是:2.07ppmV

NHMC的浓度是:0.70pmV



数据时间是:2019年12月11号 16时08分06秒

总烃的浓度是:2.78ppmV

CH4的浓度是:2.07ppmV

NHMC的浓度是:0.70ppmV
—————————————————😁————————————————


二.Node.js使用TCP通讯

  Node.js 的 net 模块可以方便的创建TCP 服务,,以下是使用 net 模块创建的tcp 服务和客户端的一个简单例子。

(一)、创建TCP Server

var net = require('net');
var tcp_server = net.createServer();  // 创建 tcp server

var Sockets = {};
var SocketID = 1;

// 监听 端口
tcp_server.listen(5678,function (){
    console.log('tcp_server listening 5678');
});

// 处理客户端连接
tcp_server.on('connection',function (socket){
    console.log(socket.address());
    Sockets[SocketID] =socket;
    SocketID++;
    DealConnect(socket)
})

tcp_server.on('error', function (){
    console.log('tcp_server error!');
})

tcp_server.on('close', function () {
    console.log('tcp_server close!');
})


// 处理每个客户端消息
function DealConnect(socket){

    socket.on('data',function(data){
        data = data.toString();
        // 向所有客户端广播消息
       for(var i in Sockets){
           Sockets[i].write(data);
       }
        // socket.write(data);
        console.log('received data %s',data);
    })

    // 客户端正常断开时执行
    socket.on('close', function () {
        console.log('client disconneted!');
    })
// 客户端正异断开时执行
    socket.on("error", function (err) {
        console.log('client error disconneted!');
    });
}

(二)、创建 TCP Client

var net = require('net');

// 指定连接的tcp server ip,端口
var options = {
    host : '172.30.20.10',  
    port : 5678
}

var tcp_client = net.Socket();

// 连接 tcp server
tcp_client.connect(options,function(){
    console.log('connected to Server');
    tcp_client.write('I am tcp_client of node!');
})

// 接收数据
tcp_client.on('data',function(data){
    console.log('received data: %s from server', data.toString());
})

tcp_client.on('end',function(){
    console.log('data end!');
})

tcp_client.on('error', function () {
    console.log('tcp_client error!');
})

三.Node.js 搭建TCP服务器

概述

TCP协议就是位于传输层的协议。Node.js在创建一个TCP服务器的时候使用的是net(网络)模块

创建TCP服务

使用Node.js创建TCP服务器,首先要引用net模块,之后使用net模块的createServer方法就可以创建一个TCP服务器.
使用TCP服务器的listen方法就可以开始监听客户端的连接.
server.listen(port[,host][,backlog][,callback]);

  • port参数为需要监听的端口号,参数值为0的时候将随机分配一个端口号。
  • host为服务器地址。
  • backlog为等待队列的最大长度
  • callback为回调函数

下面代码构建一个TCP服务器:

//引入net模块
const net=require('net');
//创建TCP服务器
let server=net.createServer(function(socket){
    console.log('someone connets');
})
//监听客户端的连接
server.listen(18001,function(){
    
    console.log('server is listening');
});

TCP服务端API

回调事件

支持如下回调事件:

  • connection:当前新的链接创建时触发,回调函数的参数为socket连接对象,同net.createServer的第二个函数参数。
  • close:TCP服务器关闭的时候触发,回调函数没有参数
  • error:TCP服务器发生错误的时候触发,回调函数的参数为error对象
  • listening:调用server.listen时触发的回调
//设置监听时的回调函数
server.on('listening',function(){
    console.log('server is listening');
});

//设置关闭时的回调函数
server.on('close',function(){
    console.log('sever closed');
});

//设置出错时的回调函数
server.on('error',function(){
    console.log('error');
});

连接服务器的客户端数量

在创建一个TCP服务器的基础下,可以通过server.getConnection()方法获取连接这个TCP服务器的客户端数量。这个方法是一个异步的方法,回调这个函数有两个参数:

  • 第一个参数为error对象
  • 第二个参数为连接TCP服务器的客户端数量。

除了获取连接数量外,也可以通过设置TCP服务器的maxConnections属性来设置这个TCP服务器最大连接数量。如果当连接的数量超过最大的数量的时候,服务器会拒绝新的连接。

在下面的代码中设置创建这个TCP服务器的最大连接数量为3:

var net=require('net');
//创建服务器
var server=net.createServer(function(socket){
    console.log('someone connects');
    //设置连接最大数量
    server.maxConnection=3;
    server.getConnections(function(err,count){
        console.log('the count of clieent is'+count);
    });
});
//设置监听端口
server.listen(18001,function(){
    
    console.log('server is listening');
});

获取客户端发送的数据

createServer方法的回调函数参数是一个net.Socket对象(服务器所监听的端口对象),这个对象同样也有一个address方法,用来获取TCP服务器绑定的地址,同样也返回一个含有port、family、address属性的对象。

  //监听dada事件
    socket.on('data',function(data){
        
        //打印data
        console.log(data.toString());
    });

socket对象除了有data事件外,还有connect,end、error、timeout等事件

发送数据给客户端

使用socket.write方法可以使TCP服务器发送数据。这个方法只有一个必须参数,就是需要发送的数据;第二个参数为编码格式,可选,同时,可以为这个方法设置一个回调函数,当有用户连接TCP服务器的时候,将发送数据给客户端。

 //发送数据
   socket.write(message,function(){
       
       var writeSize=socket.bytesWritten;
       
       console.log(message+'has send');
       console.log('the size of message is'+writeSize);
   });

运行这段代码并连接TCP服务器,可以看到Telnet中收到了TCP服务器发送的数据,Telnet也可以发送数据给TCP服务器
这段代码中还用到了socket对象的bytesWritten和byteRead属性,这两个属性分别代表着发送数据的字节数和接收数据的字节数。

var net=require('net');

//创建服务器
var server=net.createServer(function(socket){
   
   //获取地址信息
   var address=server.address();
   var message='client,the server address is'+JSON.stringify(address);
   //发送数据
   socket.write(message,function(){
       
       var writeSize=socket.bytesWritten;
       
       console.log(message+'has send');
       console.log('the size of message is'+writeSize);
   });
   
   //监听dada事件
   socket.on('data',function(data){
       
       //打印data
       console.log(data.toString());
       var readSize=socket.bytesRead;
       console.log('the size of data is'+readSize);
   });
});
//设置监听端口
server.listen(18001,function(){
   
   console.log('server is listening');
});

四.最终的实现(建立了一个服务器程序,两个客户端程序)

1.server.js服务器程序:

const net = require('net');//引入net模块;
const PORT = 18001;
const HOST = '127.0.0.1';
let server = net.createServer(function (socket) { //创建一个TCP服务器(net模块的createServer方法);
    console.log('someone connets(注意:有客户端在连接)');


    //设置新的链接创建时的回调函数
    server.on('connection', function () {    //connection:新的链接创建时触发回调;
        console.log('服务器正在连接');
    });
    //设置监听时的回调函数
    server.on('listening', function () {    //listening:调用server.listen时触发的回调;
        console.log('server is listening');
    });
    //设置关闭时的回调函数
    server.on('close', function () {    //close:TCP服务器关闭的时候触发,回调函数没有参数;
        console.log('sever closed');
    });
    //设置出错时的回调函数
    server.on('error', function () {   //error:TCP服务器发生错误的时候触发,回调函数的参数为error对象;
        console.log('error');
    });


    server.maxConnection = 3;//设置连接最大数量,TCP服务器的最大连接数量为3
    server.getConnections(function (err, count) {   //通过server.getConnection()方法获取连接这个TCP服务器的客户端数量;
        console.log('客户端的数量是:' + count);
    });


    //createServer方法的回调函数参数是一个net.Socket对象,该对象有一个address方法,用来获取TCP服务器绑定的地址,同样也返回一个含有port、family、address属性的对象。
    var address = server.address();   //自动获取地址信息(IP,端口号,family等)
    var message = 'client,服务器的地址是:' + JSON.stringify(address); //将服务器地址信息传给message;

    //获取客户端发送的数据;
    socket.on('data', function (data) {        //监听dada事件;
        console.log(data.toString());//打印data
    });


    //发送数据;可以为这个方法设置一个回调函数,当有用户连接TCP服务器的时候,将发送数据给客户端;
    socket.write(message, function () {   //使用socket.write方法可以使TCP服务器发送数据;第一个参数message是需要发送的数据;
        var writeSize = socket.bytesWritten;
        console.log(message + '已发送');      //打印"message信息已发送"
        console.log('message的大小是:' + writeSize);   //打印message信息的大小;
    });

});
//设置监听端口
server.listen(PORT, HOST, function () {//监听客户端的连接;
    console.log(`服务器已启动,运行在:http://${HOST},端口号:${PORT}`);
});

2.client1.js客户端1程序

const net = require('net');
const HOST = '127.0.0.1';
const PORT = 18001;

const client = new net.Socket();

client.setEncoding = 'UTF-8';

//与服务器进行连接
client.connect(PORT, HOST, () => {

  console.log('已连接到: ' + HOST + ':' + PORT);

  // 建立连接后向服务器发送数据,服务器将收到这些数据 
  client.write('我是client,我来自客户端!');


});

// 为客户端添加data事件处理函数
// data是服务器发回的数据
client.on('data', data => {

  console.log(data.toString());


});

// 为客户端添加error事件处理函数
client.on('error', error => {
  console.log('error' + error);
  client.end();
});

// 为客户端添加close事件处理函数
client.on('close', () => {
  console.log('服务器端下线了');


});

3.client2.js客户端2程序

const net = require('net');
const HOST = '127.0.0.1';
const PORT = 18001;

const client = new net.Socket();

client.setEncoding = 'UTF-8';

//与服务器进行连接
client.connect(PORT, HOST, () => {

    console.log('已连接到: ' + HOST + ':' + PORT);

    // 建立连接后向服务器发送数据,服务器将收到这些数据 
    client.write('我是client2,我来自客户端!');


});

// 为客户端添加data事件处理函数
// data是服务器发回的数据
client.on('data', data => {

    console.log(data.toString());


});

// 为客户端添加error事件处理函数
client.on('error', error => {
    console.log('error' + error);
    client.end();
});

// 为客户端添加close事件处理函数
client.on('close', () => {
    console.log('服务器端下线了');
});

sever端

const net = require("net");
const HOST = "127.0.0.1";
const PORT = 6868;

const server = net.createServer();
server.listen(PORT, HOST);

// 重要:双方建立链接时,会自动获得一个socket对象(std,socket描述符)
server.on("connection", (socket) => {
  // 远程客户端地址
  console.log(`connected:${socket.remoteAddress}:${socket.remotePort}`);
  // 本地服务端地址
  console.log(`local:${socket.localAddress}:${socket.localPort}`);
  // 向客户端发送数据
  socket.write("服:你好客户端");
  // 收到客户端数据时
  socket.on("data", (data) => {
    console.log(`${data}`);
  });
  // 客户端主动断连,触发end事件
  socket.on("end", (data) => {
    console.log(`客户端${socket.remoteAddress}:${socket.remotePort}已断连`);
  });
  // 如果链接断开,write方法就无效了
  setInterval(() => {
    socket.write(`服:定时消息${Date.now()}`);
  }, 1000);
});

console.log(`server listen on ${HOST}:${PORT}`);

client端

const net = require("net");
const HOST = "127.0.0.1";
const PORT = 6868;

const client = new net.Socket();

client.connect(PORT, HOST, () => {
  console.log(`connected to:${HOST}:${PORT}`);
  // 向服务端发送数据
  client.write("客:你好服务端");
  // 收到服务端数据时
  client.on("data", (data) => {
    console.log(data.toString());
    client.write("客:已收到");
    // client.end(); // 主动关闭此次tcp长连接
  });
  // 客户端主动断连,触发自己的end事件
  client.on("end", () => {
    console.log("链接已主动断开");
  });
});
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值