node.js中net模块、node实现tcp通信

node.js中net

一、net模块感知:

net模块用于创建基于TCP(或IPC)通信的服务器或客户端,它是nodejs内置模块,直接使用require(‘net’)的方式引入,类似http模块。

二、创建一个tcp服务器:

//1.引入net模块
const net = require('net')
//2.使用net的createServe({allowHalfOpen:false,pauseOnConnect:false},connectionListener)方法创建tcp服务,第一个参数为一个对象,其中两个属性值默认都是false;第二个参数是客户端与服务端建立连接的回调函数,且函数的默认参数表示socket端口对象。
const server = net.createServe((socket)=>{console.log('有客户端连接了')console.log(socket)//6.设置客户端与服务端最大链接数量:server.maxConnections = 5;//7.获取客户度接入的数量:server.getConnections(function (err, count) {console.log("当前连接的客户端数量:" + count);});//8.获取客户端传入过来的数据:socket对象的data事件可以获取客户端发送过来的数据,socket对象除了有data事件外,还有connect、end、error、timeout等事件,如:socket.on('data',(dt)=>{const readSize = socket.bytesRead;// 获取接收到客户端数据的长度console.log('客户端数据:'+ dt.toString())})//9.发送数据给客户端:socket.write()用来给客户端发送数,此方法第一个参数为发送内容必选,第二个参数为编码格式可选,回调函数为socket.write('hello server!',() => {const writeSize = socket.bytesWritten;//获取发送数据的长度console.log("数据发送成功且长度为:" + writeSize);});//10.socket对象还有以下属性socket.localPort:本地端口的地址socket.localAddress:本地IP地址socket.remotePort:进程端口地址socket.remoteFamily:进程IP协议族socket.remoteAddress:进程IP地址
})
//3.使用server服务的listen方法监听主机和端口,此方法和http服务类似,listen方法底层实际监测server的listening事件,可以使用on方法监听该事件如:server.on('listening',()=>{console.log('serve is running...')})
server.listen(3000,'127.0.0.1',()=>{console.log('serve is running...')
})
//4.net.Server其他常用事件:
//4-1:connection:新的链接接入时触发,如:
server.on('connection',()=>{console.log('新的接入')})
//4-2:close:服务器关闭时触发,如:
server.on('close',()=>{console.log('服务器关闭了')})
//4-3:error:服务器发生错误时触发,如:
server.on('error',()=>{console.log('服务器错误')})
//5.server.address()方法用于查看服务器监听的地址信息,返回一个对象,其属性有:port:TCP服务器监听的端口号、family:说明TCP服务器监听的地址是IPv6还是IPv4、address:TCP服务器监听的地址;此方法为监听客户端信息,因此应该在listen方法或listening事件的回调函数中使用。 

三、创建一个tcp客户端:

//1.引入net模块:
const net = require('net')
//2.创建tcp客户端:net.Socket(obj)中可以传入一个obj对象,其属性分别为:fd文件描述、readable是否允许可读、writeable是否可写、allowHalfOpen:false时,tcp服务器接收到客户端发送的fin包后会回发,为true时不回发,前三个属性的默认值为false
const client = new net.Socket()
//3.连接tcp服务器:
client.connect(3000,'127.0.0.1',()=>{console.log('服务连接成功')//5.向tcp服务器发送数据:应该在连接到服务器后在发送数据,因此在连接到tcp服务器的回调函数中完成client.write('hello server!')
})
//4.获取服务端发送过来的数据:监听data事件:
client.on('data',(dt)=>{console.log('接收到服务端数据为:'+dt)
})
//6.end事件用于监听客户端发送数据完成:
client.on('end',()=>{console.log('向服务端发送数据完成')
})

四、项目中运用:

项目的基本思路,前端做交互通过tcp通信到tcp服务上

后端tcp客户端代码:

// 参数下设页路由:
const express = require('express')
const router = express.Router()
const connection = require('../config/mysqldbconfig')
const net = require('net') // 载入net模块,用于创建tcp客户端// 设置或读取接口
router.post('/api/postparams',(request,response)=>{try {let obj = request.body;let param;if (obj.isRead){param = 'mod/'+obj.pjtid+'/'+obj.address+'/'+obj.read_cod}else {param = 'mod/'+obj.pjtid+'/'+obj.address+'/'+obj.cod+'/'+obj.inputval}// 查询ip地址和端口号:function getipport(){return new Promise((rej)=>{connection.query('SELECT * FROM system_setting',(error,result)=>{try {if (error) {throw error}else{rej(result[0])}}catch(err){console.log('查询参数下设ip地址接口错误'+err)}})})}async function sendparam () {let ipobj = await getipport()let da = ''//创建TCP客户端,在接口内部创建tcp客户端可以避免每次调用接口而产生的粘包问题,如果将创建tcp客户端的const client = new net.Socket()代码提到接口外面,那么当多次调用接口时就会出现调用一次接口响应多次数据的情况,经查阅资料需要数据的封包与拆包,这种情况需要tcp服务端和tcp客户端同时处理才能实现,我这个项目中tcp服务端不是我本人所写,经测试发现,将代码提到接口中,每次调用接口重新创建tcp客户端可间接地解决粘包问题const client = new net.Socket();client.connect(ipobj.par_port,ipobj.par_ip,() => {client.write(param)})client.on("data", function (data) {da = data.toString()if(da === 'err'){response.writeHead(201)response.end()} else {response.end(da)}})client.on("error",(err)=>{throw err})}sendparam()}catch(err) {console.log('设置下设参数接口错误:'+err)}
})module.exports = router

前端页面主要代码:

<!-- 部分界面代码: -->
<el-dialog v-model="dialogVisible" title='下设参数' width="60%"><el-table :data="paramdata" border height='510'><el-table-column prop="pname" label="参数名称"></el-table-column><el-table-column prop="cod" label="编码"></el-table-column><el-table-column label="读取/写入"><template #default="scope"><input v-if='scope.row.input_type === 1 ? true : false' type='text' v-model="scope.row.inputval" placeholder="输入值"><el-select v-if='scope.row.input_type === 0 ? true : false' v-model="scope.row.inputval" placeholder="选择值"><el-option v-for="item in scope.row.select_value" :key="item.key" :label="item.key" :value="item.val"></el-option></el-select></template></el-table-column><el-table-column fixed="right" label="操作" width="150"><template #default="scope"><el-button type="primary" size="small" @click='setParam(scope.row)'>下设</el-button><el-button type="success" plain size="small" @click='getParam(scope.row)'>读取</el-button></template></el-table-column></el-table>
</el-dialog>//部分逻辑代码:
methods: {getParam (e) { // 读取参数e.isRead = true // 控制是读取还是下设this.sendRequest(e)},setParam (e) { // 下设参数if (e.input_type === 1) {const regstr = '^[0-9]{' + (e.min_value === 0 ? 0 : e.min_value.toString().length) + ',' + e.max_value.toString().length + '}.{0,1}[0-9]{0,' + e.dotted_count + '}$'const reg = new RegExp(regstr)if (reg.test(e.inputval) && e.inputval >= e.min_value && e.inputval <= e.max_value) {this.sendRequest(e)} else {this.ElMessage({ // 表单校验失败,做出提示:message: '提示:输入的值无效!',type: 'warning'})}} else {this.sendRequest(e)}},async sendRequest (el) { // 调用读取或下设的接口const postdata = await this.$http.post('/api/postparams', el)if (postdata.status !== 200) return this.ElMessage('提示:失败')this.ElMessage({message: '提示:成功!',type: 'success'})}}

前端项目我是用vue写的,其中参数e是从数据库中获取过来的值,另外后端接口中obj.pjtid和obj.address是从父元素传入的参数(数字和字符串,这里可忽略,不影响阅读),数据库中的值如下图:
在这里插入图片描述
优化:前端每点击下设或读取一次就建立一次连接的导致的性能问题:

// 参数下设页路由:
const express = require('express')
const router = express.Router()
const connection = require('../config/mysqldbconfig')
const net = require('net') // 载入net模块,用于创建tcp客户端
const client = new net.Socket()
let res = {}
// 获取下设参数数据
router.post('/api/getparamedata',(req,res)=>{let reqobj = req.body;let sql = 'SELECT ps.* FROM param_sets ps INNER JOIN param_user pu ON pu.par_id = ps.id WHERE pu.user_id = "'+reqobj.uid+'" AND ps.show = 1'connection.query(sql,(error,result)=>{try {if(error){throw error;}else{res.send(result)}} catch (err) {console.log('获取下设参数数据接口错误:'+err)}})connection.query('SELECT * FROM system_setting',(error,result)=>{try {if (error) {throw error}else{client.connect(result[0].par_port,result[0].par_ip,()=>{console.log('服务连接成功')})}}catch(err){console.log('查询参数下设ip地址接口错误'+err)}})
})// 设置下设参数接口
router.post('/api/postparams',(request,response)=>{res = responselet obj = request.body;let param;if (obj.isRead){param = 'mod/'+obj.pjtid+'/'+obj.address+'/'+obj.read_cod+'/'}else {param = 'mod/'+obj.pjtid+'/'+obj.address+'/'+obj.cod+'/'+obj.inputval}client.write(param)
})client.on('data',(dt)=>{console.log('接收到服务端数据为:'+dt)res.end(dt)
})client.on('end',()=>{console.log('向服务端发送数据完成')
})module.exports = router

提示:本文图片等素材来源于网络,若有侵权,请发邮件至邮箱:810665436@qq.com联系笔者删除。
笔者:苦海

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/575136.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

struts2--文件上传大小

struts2--文件上传大小 Struts2文件上传的大小限制问题 问题&#xff1a;上传大文件报错……解决&#xff1a;修改struts.xml文件中的参数如下<constant name"struts.multipart.maxSize" value"55000000"/><action name"UploadFile" cl…

element-plus中导航高亮不自动刷新问题

解决使用element-plus el-submenu时页面被this.$router.push(“xxx”)跳转后&#xff0c;导航菜单高亮不能自动刷新问题&#xff0c;需要注意以下几点&#xff1a; 在el-menu加上routerindex必须绑定路由的path,参考上面的例子&#xff0c;/不能少default-active设为当前路由&…

计算机二级考试python怎么报名_计算机二级报名流程和条件

对于第一次参加全国计算机二级考试的考生来说&#xff0c;他们对于计算机二级报名流程和条件不是清楚&#xff0c;小编这就来给大家梳理一下。计算机二级报名流程 一、报名 分为网上报名和现场报名。 网上报名&#xff1a;考生在规定时间内登录本省计算机资格网站&#xff0c;按…

操作对象_DOM进阶——HTML属性操作(对象属性)

上一节我们在“DOM基础”学习了对元素节点的操作&#xff0c;这两节介绍对属性节点的操作。属性节点操作有两种方式&#xff0c;一种是使用“对象属性”&#xff0c;另一种是“对象方法”。本节主要介绍“对象属性”的方式。对属性节点的操作涉及两种操作&#xff0c;分别是获取…

三级菜单数据实现,实现嵌套三级菜单数据

//将数据库中通过关联&#xff08;inner join&#xff09;查询多张表没有嵌套但有嵌套关系的数据进行处理&#xff0c;得到具有嵌套层级且嵌套的父级二级属性不可重复出现&#xff0c;具体实现如下&#xff1a;// 通过关联查询到数据库的数据&#xff08;格式&#xff09;&…

sap相关性不能被编译_经典综述编译丨生物硝化抑制丨NAT PLANTS:现代农业中的氮转化和生物硝化抑制作用...

点击蓝字↑↑↑“农作未来(FarmingFuture)”&#xff0c;轻松关注&#xff0c;农作制度研究与您同行&#xff01;编译&#xff1a;贾蓉 排版&#xff1a;王上原创微文&#xff0c;欢迎转发转载。文章信息原名&#xff1a;Nitrogen transformations in modern agriculture and …

Hadoop学习笔记(一)从官网下载安装包

Hadoop是一个分布式系统基础架构&#xff0c;由Apache基金会所开发。用户能够在不了解分布式底层细节的情况下&#xff0c;开发分布式程序。充分利用集群的威力进行快速运算和存储。要学习Hadoop从下载安装包開始打开Hadoop的官方站点&#xff0c;点击Download Hadoop或点击“G…

版本之间如何兼容_Spring Boot 2.4 版本的系统运行要求

名字Servlet 版本Tomcat 9.04.0Jetty 9.43.1Undertow 2.04.0Spring Boot 2.4.2-SNAPSHOT 版本要求至少 Java 8 及其以上版本&#xff0c;目前最高能够支持到 Java 15 &#xff08;包含 15&#xff09;的版本。 Spring 框架&#xff08;Framework&#xff09; 5.3.2 的版本或者以…

JavaScript异步处理问题,循环处理异步任务,并拿到数据,Nodejs循环异步任务接口处理

一、问题描述及解答&#xff1a; 在Promise(异步事件)中&#xff0c;通过遍历的方式处理数据&#xff0c;最后将带有数据的Promise通过return返回&#xff0c;在async/await处理机制中的到的数据是一个空数据组[]或不完整的数据&#xff0c;如下&#xff1a; 使用定时器后数据…

tomcat lifecyclelistener_大公司程序员带你死磕Tomcat系列(五)——容器

死磕Tomcat系列(5)——容器回顾在死磕Tomcat系列(1)——整体架构中我们简单介绍了容器的概念&#xff0c;并且说了在容器中所有子容器的父接口是Container。在死磕Tomcat系列(2)——EndPoint源码解析中&#xff0c;我们知道了连接器将请求过来的数据解析成Tomcat需要的ServletR…

获取当前周一日期_Excel工作表中最全的时间和日期函数,效率、办公必备

在Excel工作表中&#xff0c;函数也可以分为好几类&#xff0c;今天&#xff0c;小编带大家学习时间和日期函数。一、Excel工作表日期函数&#xff1a;Date。功能&#xff1a;返回特定日期的序列号。语法结构&#xff1a;Date(年,月,日)。目的&#xff1a;将制定的“年”、“月…

这样就算会了PHP么?-11

PHP中关于类的基本内容练习&#xff1a; <?phpclass SportObject{public $name;public $height;public $avirdupois;public function __construct($name, $height,$avirdupois) {$this->name $name;$this->height $height;$this->avirdupois $avirdupois;}func…

一个黑色全屏的计时器_我入手了一个1000多的智能手环,值吗?|Fitbit Charge 4测评...

入手Fitbit Charge 4了。作为一个喜欢晚上做运动的Boy&#xff0c;每次运动带着手机确实有够累赘&#xff0c;比如跑步的时候&#xff0c;掏手机看真的很麻烦&#xff0c;但手环只需抬手即可看时间、心率、步数这些&#xff0c;确实很方便。而且&#xff0c;有了手环之后&#…

python没有用_你可能没有在Python3中使用但却应该使用的东西

Python部落(python.freelycode.com)组织翻译&#xff0c;禁止转载&#xff0c;欢迎转发。 由于Python EOL的发布&#xff0c;许多人开始将他们的Python版本从2切换到3。不幸的是&#xff0c;我发现大多数Python3看起来仍然像Python2&#xff0c;但是要加括号(尽管在我之前的文章…

boost库 bind/function的使用

Boost::Function 是对函数指针的对象化封装&#xff0c;在概念上与广义上的回调函数类似。相对于函数指针&#xff0c;function除了使用自由函数&#xff0c;还可以使用函数对象&#xff0c;甚至是类的成员函数&#xff0c;这个就很强大了哈 #include <boost/function.hpp&g…

10恢复出厂设置_Mac系统如何恢复出厂设置

苹果Mac电脑在什么情况下需要恢复出厂设置呢&#xff1f;例如系统数据损坏、遇到无法卸载的恶意软件、错误更新导致、或者你只是想要闲鱼出售你的Mac电脑&#xff0c;这里系统派教你Mac如何恢复出厂设置。我们先简单将恢复出厂分成两步&#xff0c;一是擦除硬盘数据&#xff0c…

依赖注入的三种方式_Java核心知识 Spring原理十 Spring 依赖注入四种方式

构造器注入/*带参数&#xff0c;方便利用构造器进行注入*/ public CatDaoImpl(String message){ this. message message; } setter 方法注入public class Id { private int id; public int getId() { return id; } public void setId(int id) { this.id id; } } 静态工厂注入…

闪退没由报错_关于floor()报错注入,你真的懂了吗?

0x01 简述floor报错注入也有叫group报错注入的&#xff0c;都一样&#xff0c;指的都是他们。floor报错注入我想大多数人跟我一样&#xff0c;都是会用而不明白其中的原理。这个问题困扰了在下好长时间了&#xff0c;所以决定好好研究下&#xff0c;最终产出了这篇文章。0x02 环…

Photoshop(CC2020)未完

基础知识&#xff1a; 概括&#xff1a; Adobe Photoshop&#xff0c;简称PS&#xff0c;是由美国Adobe Systems开发和发行的图像处理软件。属于再加工型软件&#xff0c;是对很多素材的再次加工处理&#xff0c;并非原创型软件。 功能:Photoshop主要处理以像素构成的位图图像…

使用 做签名的post_基础实操|使用jmeter对聊天软件进行接口测试

前言准备上架一款聊天app&#xff0c;上架之前准备做一些测试工作&#xff0c;模拟用户进入房间&#xff0c;维持心跳&#xff0c;房间送礼&#xff0c;发言等行为(因为用的第三方im以及声网&#xff0c;这些都是基于http的)&#xff0c;也不是很懂测试&#xff0c;听老大说过一…