摘要: 网络是通信互联的基础,Node.js提供了net、http、dgram等模块,分别用来实现TCP、HTTP、UDP的通信,本文主要对使用Node.js的TCP通信部份进行实践记录。

本文分享自华为云社区《一文搞懂如何使用Node.js进行TCP网络通信》,作者:lwq1228 。

1、构建TCP服务器

1.1、使用Node.js创建TCP服务器

为了使用Node.js创建TCP服务器,首先要调用require(‘net’)来加载net模块,然后调用net模块的createServer方法就可以轻松地创建一个TCP服务器,语法格式如下:

net.createServer([options][, connectionListener])

options是一个对象参数值,有两个布尔类型的属性allowHalfOpen和pauseOnConnect。这两个属性默认都是false;
connectionListener是一个当客户端与服务端建立连接时的回调函数,这个回调函数以socket端口对象作为参数。

1.2、监听客户端的连接

使用TCP服务器的listen方法就可以开始监听客户端的连接,语法格式如下:

server.listen(port[, host][, backlog][, callback]);

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

以下代码可以创建一个TCP服务器并监听8001端口:

//引入net模块
const net = require('net');
//创建TCP服务器
const server = net.createServer(function (socket) {
console.log('有新的客户端接入');
});
//设置监听端口
server.listen(8001, function () {
console.log('服务正在监听中。。。')
});

运行这段代码,可以在控制台看到执行了listen方法的回调函数,如图所示:

可以使用相应的TCP客户端或者调试工具来连接这个已经创建好的TCP服务器。例如,要使用Windows的Telnet就可以用以下命令来连接:

telnet localhost 8001

连接成功后可以看到控制台打印了“有新的客户端接入”字样,表明createServer方法的回调函数已经执行,说明已经成功连接到这个创建好的TCP服务器。

server.listen()方法其实触发的是server下的listening事件,所以也可以手动监听listening事件,代码如下:

//设置监听端口
server.listen(8001);
//设置监听时的回调函数
server.on('listening', function () {
console.log("服务正在监听中。。。")
});

除了listening事件外,TCP服务器还支持以下事件:

connection:当有新的链接创建时触发,回调函数的参数为socket连接对象。
close:TCP服务器关闭的时候触发,回调函数没有参数。
error:TCP服务器发生错误的时候触发,回调函数的参数为error对象。

下列代码通过net.Server类来创建一个TCP服务器,添加以上事件:

//引入net模块
const net = require('net');
//实例化一个服务器对象
const server = new net.Server();
//监听connection事件
server.on('connection', function (socket) {
console.log('有新的客户端接入');
});
//设置监听端口
server.listen(8001);
//设置监听时的回调函数
server.on('listening', function () {
console.log('服务正在监听中。。。');
});
//设置关闭时的回调函数
server.on('close', function () {
console.log('服务已关闭');
});
//设置出错时的回调函数
server.on('error', function (err) {
console.log('服务运行异常', err);
});

1.3、查看服务器监听的地址

当创建了一个TCP服务器后,可以通过server.address()方法来查看这个TCP服务器监听的地址,并返回一个JSON对象,因为这个方法返回的是TCP服务器监听的地址信息,所以应该在调用了server.listen()方法或者绑定了事件listening中的回调函数中调用该方法。这个对象的属性有:

port:TCP服务器监听的端口号;
family:说明TCP服务器监听的地址是IPv6还是IPv4;
address:TCP服务器监听的地址。

代码如下:

//引入net模块
const net = require('net');
//创建TCP服务器
const server = net.createServer(function (socket) {
console.log('有新的客户端接入');
});
//设置监听端口
server.listen(8001);
//设置监听时的回调函数
server.on('listening', function () {
//获取地址信息
let address = server.address();
//获取地址详细信息
console.log("服务器监听的端口是:" + address.port);
console.log("服务器监听的地址是:" + address.address);
console.log("服务器监听的地址类型是:" + address.family);
});

运行结果如图:

1.4、连接服务器的客户端数量

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

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

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

//引入net模块
const net = require('net');
//创建TCP服务器
const server = net.createServer(function (socket) {
console.log('有新的客户端接入');
//设置最大连接数量
server.maxConnections = 3;
server.getConnections(function (err, count) {
console.log("当前连接的客户端个数为:" + count);
});
});
//设置监听端口
server.listen(8001, function () {
console.log("服务正在监听中。。。")
});

运行这段代码,并尝试用多个客户端连接。可以发现当客户端连接数超过3的时候,新的客户端就无法连接这个服务器了,如图所示:

1.5、获取客户端发送的数据

createServer方法的回调函数参数是一个net.Socket对象(服务器所监听的端口对象),这个对象同样也有一个address()方法,用来获取TCP服务器绑定的地址,同样也是返回一个含有port、family、address属性的对象。通过socket对象可以获取客户端发送的流数据,每次接收到数据的时候触发data事件,通过监听这个事件就可以在回调函数中获取客户端发送的数据,代码如下:

//引入net模块
const net = require('net');
//创建TCP服务器
const server = net.createServer(function (socket) {
//监听data事件
socket.on("data", function (data) {
//打印数据
console.log("接收到数据:" + data.toString());
});
});
//设置监听端口
server.listen(8001, function () {
console.log("服务正在监听中。。。")
});

测试结果如下:

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

1.6、发送数据给客户端

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

//引入net模块
const net = require('net');
//创建TCP服务器
const server = net.createServer(function (socket) {
//设置消息内容
const message = "Hello Client......";
//发送数据
socket.write(message, function () {
const writeSize = socket.bytesWritten;
console.log("数据发送成功,数据长度为:" + writeSize);
}); //监听data事件
socket.on("data", function (data) {
const readSize = socket.bytesRead;
//打印数据
console.log("接收到数据为:" + data.toString(), ";接收的数据长度为:" + readSize);
});
});
//设置监听端口
server.listen(8001, function () {
console.log("服务正在监听中。。。")
});

测试结果如下:

在上面这段代码中还用到了socket对象的bytesWritten和bytesRead属性,这两个属性分别代表着发送数据的字节数和接收数据的字节数。除了上面这两个属性外,socket对象还有以下属性:

socket.localPort:本地端口的地址;
socket.localAddress:本地IP地址;
socket.remotePort:进程端口地址;
socket.remoteFamily:进程IP协议族;
socket.remoteAddress:进程IP地址。

2、构建TCP客户端

Node.js在创建一个TCP客户端的时候同样使用的是net(网络)模块。

2.1、使用Node.js创建TCP客户端

为了使用Node.js创建TCP客户端,首先要调用require(‘net’)来加载net模块。创建一个TCP客户端只需要创建一个连接TCP客户端的socket对象即可:

//引入net模块
const net = require('net');
//创建TCP客户端
const client = new net.Socket();

创建一个socket对象的时候可以传入一个json对象。这个对象有以下属性:

fd:指定一个存在的文件描述符,默认值为null;
readable:是否允许在这个socket上读,默认值为false;
writeable:是否允许在这个socket上写,默认值为false;
allowHalfOpen:该属性为false时,TCP服务器接收到客户端发送的一个FIN包后,将会回发一个FIN包;该属性为true时,TCP服务器接收到客户端发送的一个FIN包后不会回发FIN包。

2.2、连接TCP服务器

创建了一个socket对象后,调用socket对象的connect()方法就可以连接一个TCP服务器,代码如下:

//引入net模块
const net = require('net');
//创建TCP客户端
const client = new net.Socket();
//设置连接的服务器
client.connect(8001, '127.0.0.1', function () {
console.log("连接服务器成功");
});

连接成功如下图所示:

2.3、获取从TCP服务器发送的数据

socket对象有data、error、close、end等事件,因可以通过监听data事件来获取从TCP服务器发送的数据,代码如下:

//引入net模块
const net = require('net');
//创建TCP客户端
const client = new net.Socket();
//设置连接的服务器
client.connect(8001, '127.0.0.1', function () {
console.log("连接服务器成功");
});
//监听data事件
client.on("data", function (data) {
//打印数据
console.log("接收到数据为:" + data.toString());
});

先启动TCP服务端,再运行上面客户端,可以发现命令行中已经输出了来自服务端的数据,说明此时已经实现了服务端和客户端之间的通信:

2.4、向TCP服务器发送数据

因为TCP客户端是一个socket对象,所以可以使用以下代码来向TCP服务器发送数据:

//引入net模块
const net = require('net');
//创建TCP客户端
const client = new net.Socket();
//设置连接的服务器
client.connect(8001, '127.0.0.1', function () {
console.log("连接服务器成功");
//给服务端发送数据
client.write("Hello Server......");
});
//监听data事件
client.on("data", function (data) {
//打印数据
console.log("接收到数据为:" + data.toString());
});
//监听end事件
client.on("end", function () {
console.log("客户端发送数据结束")
});

客户端控制台输出:

服务端控制台输出:

至此使用Node.js进行TCP网络通信完成,如有不对的地方欢迎指正

点击关注,第一时间了解华为云新鲜技术~

一文搞懂如何使用Node.js进行TCP网络通信的更多相关文章

  1. 一文搞懂 js 中的各种 for 循环的不同之处

    一文搞懂 js 中的各种 for 循环的不同之处 See the Pen for...in vs for...of by xgqfrms (@xgqfrms) on CodePen. for &quo ...

  2. Web端即时通讯基础知识补课:一文搞懂跨域的所有问题!

    本文原作者: Wizey,作者博客:http://wenshixin.gitee.io,即时通讯网收录时有改动,感谢原作者的无私分享. 1.引言 典型的Web端即时通讯技术应用场景,主要有以下两种形式 ...

  3. 一文搞懂所有Java集合面试题

    Java集合 刚刚经历过秋招,看了大量的面经,顺便将常见的Java集合常考知识点总结了一下,并根据被问到的频率大致做了一个标注.一颗星表示知识点需要了解,被问到的频率不高,面试时起码能说个差不多.两颗 ...

  4. 一文搞懂RAM、ROM、SDRAM、DRAM、DDR、flash等存储介质

    一文搞懂RAM.ROM.SDRAM.DRAM.DDR.flash等存储介质 存储介质基本分类:ROM和RAM RAM:随机访问存储器(Random Access Memory),易失性.是与CPU直接 ...

  5. 基础篇|一文搞懂RNN(循环神经网络)

    基础篇|一文搞懂RNN(循环神经网络) https://mp.weixin.qq.com/s/va1gmavl2ZESgnM7biORQg 神经网络基础 神经网络可以当做是能够拟合任意函数的黑盒子,只 ...

  6. 一文搞懂 Prometheus 的直方图

    原文链接:一文搞懂 Prometheus 的直方图 Prometheus 中提供了四种指标类型(参考:Prometheus 的指标类型),其中直方图(Histogram)和摘要(Summary)是最复 ...

  7. 一文搞懂vim复制粘贴

    转载自本人独立博客https://liushiming.cn/2020/01/18/copy-and-paste-in-vim/ 概述 复制粘贴是文本编辑最常用的功能,但是在vim中复制粘贴还是有点麻 ...

  8. 三文搞懂学会Docker容器技术(中)

    接着上面一篇:三文搞懂学会Docker容器技术(上) 6,Docker容器 6.1 创建并启动容器 docker run [OPTIONS] IMAGE [COMMAND] [ARG...] --na ...

  9. 三文搞懂学会Docker容器技术(下)

    接着上面一篇:三文搞懂学会Docker容器技术(上) 三文搞懂学会Docker容器技术(中) 7,Docker容器目录挂载 7.1 简介 容器目录挂载: 我们可以在创建容器的时候,将宿主机的目录与容器 ...

随机推荐

  1. C语言自学第一天

    直接上代码 1 #include<stdio.h> 2 #include<math.h> 3 /*定义符号常量(预处理)注:可为各种类型*/ 4 #define STUDY & ...

  2. Run Clojure Script with External Dependencies without leiningen

    The normal way of deploy clojure files is using leiningen. But if we have no leiningen, or the scrip ...

  3. 关于shell脚本——echo、for语句、while语句、until语句

    目录 一.echo 1.1.echo命令用法 1.2.echo截取字符 二.for语句 2.1.实例 创建用户名文件 创建脚本文件 运行脚本 三.while语句 3.1.实例 创建脚本文件 运行脚本 ...

  4. 树莓派远程连接工具SSH使用教程

    树莓派远程连接工具SSH使用教程 树莓派 背景故事 树莓派作为一款迷你小主机,大部分的使用场景都会用到远程调试,远程调试用到最多的方式一般就是VNC和SSH,SSH就是命令行型的远程方式,简单来说就是 ...

  5. JavaScript-DOM-节点简介与分类

    简介 节点(node)是一个网络术语,它表示网络中的一个连接点.一个网络就是由一些节点构成的集合. 在DOM里,文档是由节点构成的集合,此时的节点是文档树上的树枝和树叶. 分类 DOM中包含许多不同类 ...

  6. C# 插件编写

    //加载插件 private void LoadPlugins() { string path = Path.Combine(Path.GetDirectoryName(Assembly.GetExe ...

  7. C# Unity容器的使用

    最简单的使用方式(记得安装Unity NuGet包呀) Console.WriteLine("***************Unity容器的初步应用***************" ...

  8. 常见递归&非递归实现

    void my_strcpy(char *to,const char *from) { if('\0' == *from){ *to = '\0'; return ; } *to++ = *from+ ...

  9. 在Java泛型

    1,泛型的定义以及存在意义 泛型,即"参数化类型".就是将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也定义成参数形式(可以称之为类型形参),然后在使用/调用时传 ...

  10. Python打印图片

    准备好图片:(我女票) python代码: # by gubin 6.20 from dyy from PIL import Image import sys import os def _main( ...