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 = response
    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
    }
    client.write(param)
})

client.on('data',(dt)=>{
    console.log('接收到服务端数据为:'+dt)
    res.end(dt)
})

client.on('end',()=>{
    console.log('向服务端发送数据完成')
})

module.exports = router

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

  • 4
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: Node.js提供了一个内置的net模块,可以方便地创建TCP服务器和客户端。这个模块允许你创建服务器,监听指定的端口,接受来自客户端的连接请求,并与客户端进行通信。 以下是一个简单的TCP服务器示例: ```javascript const net = require('net'); // 创建服务器 const server = net.createServer((socket) => { console.log('客户端已连接'); // 监听数据事件 socket.on('data', (data) => { console.log(`接收到客户端数据:${data}`); socket.write(`你好,你发送了:${data}`); }); // 监听断开事件 socket.on('end', () => { console.log('客户端已断开连接'); }); }); // 监听端口 server.listen(8000, () => { console.log('服务器已启动,监听端口8000'); }); ``` 上面代码创建了一个TCP服务器,监听端口8000。当有客户端连接时,服务器会打印“客户端已连接”的消息,并监听数据事件和断开事件。当客户端发送数据时,服务器会打印接收到的数据,并回复一个“你好,你发送了:xxx”的消息。当客户端断开连接时,服务器会打印“客户端已断开连接”的消息。 你也可以使用net模块创建TCP客户端,连接到服务器并发送数据: ```javascript const net = require('net'); // 创建客户端 const client = net.createConnection({ port: 8000 }, () => { console.log('已连接到服务器'); // 发送数据 client.write('你好,服务器'); }); // 监听数据事件 client.on('data', (data) => { console.log(`接收到服务器数据:${data}`); }); // 监听断开事件 client.on('end', () => { console.log('已断开与服务器的连接'); }); ``` 上面代码创建了一个TCP客户端,连接到端口8000的服务器。当连接成功时,客户端会打印“已连接到服务器”的消息,并发送一个“你好,服务器”的消息。当客户端接收到服务器的回复时,会打印接收到的数据。当客户端断开连接时,会打印“已断开与服务器的连接”的消息。 ### 回答2: Node.js TCP(传输控制协议)是一种基于事件驱动的服务器端网络通信模型,用于在计算机网络进行可靠的数据传输。Node.js提供了内置的模块,如net模块,用于创建TCP服务器或客户端。 使用Node.jsTCP模块,我们可以轻松地创建一个TCP服务器,通过监听指定的端口接受客户端的连接。一旦建立连接,服务器可以接收和发送数据。这使得我们可以构建各种类型的网络应用程序,如聊天服务器、实时游戏服务器等。 在编写TCP服务器时,我们可以使用事件驱动的回调函数来处理连接、数据接收和错误等事件。Node.js的事件模型可以实现高效的并发处理,因为它不需要为每个连接创建新的线程或进程。相反,它使用单线程和事件循环来处理多个连接。 另外,Node.jsTCP模块还提供了一些常用的功能,如监听特定IP地址、限制同时的连接数、发送和接收原始数据等。我们还可以使用TLS(传输层安全)来加密和保护TCP连接,以实现安全的数据传输。 总而言之,Node.jsTCP模块是一个强大且易于使用的工具,可以帮助我们构建高性能、可扩展的网络应用程序。它通过事件驱动的方式实现了高并发处理,同时提供了多种功能和选项,以满足各种网络通信需求。 ### 回答3: Node.js 是一个开源的、跨平台的 JavaScript 运行环境,可以在服务器端运行 JavaScript。它使用基于事件驱动和非阻塞 I/O 模型,使得可以高效地处理大量并发连接。TCP 是传输控制协议,它是一种可靠的、面向连接的网络传输协议。 在 Node.js ,可以使用内置的 net 模块实现 TCP 客户端和服务器的编程。通过 net 模块,可以创建 TCP 服务器,监听指定的 IP 地址和端口,接受来自客户端的请求,并与客户端进行通信TCP 服务器可以处理多个客户端连接,通过事件回调处理客户端的请求和响应。 TCP 客户端可以连接到指定的 TCP 服务器,发送请求并接收响应。在客户端和服务器之间建立的 TCP 连接是持久的连接,可以保持长时间的通信。 使用 Node.js 的 net 模块编写 TCP 服务器和客户端,可以实现各种基于 TCP 的应用,如网络聊天程序、实时数据传输、远程命令执行等。由于 Node.js 的事件驱动和非阻塞 I/O 特性,可以高效地处理并发连接,提供高性能的网络应用程序。 总之,Node.js 提供了简单且强大的 API 来编写 TCP 服务器和客户端,并且能够高效地处理并发连接。它的特性使得它成为构建高性能网络应用的理想选择。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

苦海123

快乐每一天!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值