Node学习十二 —— 创建TCP客户端

23 篇文章 0 订阅

构建TCP客户端

TCP协议位于IP协议的上一层,是引用最广泛的互联网传输协议之一,在其之上就是类似HTTP这样的应用层协议。TCP是一种面向连接的协议,即一个终端需要和另一个终端建立专门的连接。该连接为双向数据流,两个终端可以同时控制收或者发数据。

注意:

TCP写入数据的时候,不会收到对方发送来的确认收到信号,而底层的网络实现也许会随机的切包和路由数据包,所以如果出现网络错误或者内部错误,接收方也许只能收到一部分发送的信息。

就是说,TCP只能保证数据包被应用程序按顺序接收,而不能保证它们被全部接收。

但是,TCP并不是面向消息的,它只会提供一个连续的数据流。如果需要识别单独的消息,那么就必须实现一个帧协议,指定每个消息的其实位置和结束位置。

例如,HTTP实现了响应机制,并且请求和响应消息都被明确地制定了界线。

连接服务器

可以使用net模块连接TCP服务器:

const net = require('net');
const port = 1234;

// 还可主机名为第二个参数,为可选参数,默认为localhost
// 最后一个参数可以传入一个回调函数,但是这里不这样做,我采用第二种写法:监听连接事件
const connect = net.createConnection(port);

connect.on('connect', (e) => {
    console.log("New Connection!");
})

发送和接收数据:

const net = require('net');
const port = 1234;

const connect = net.createConnection(port);

connect.on('connect', (e) => {
    console.log("New Connection!");
	// 可以写入一个缓冲区
    connect.write("Hello Server!","utf-8");
})

connect.on('data', (data)=>{
    console.log(data);
})

write方法的第二参数还可以接收一个字符串指定编码。

在上述变量之后还可以传入一个回调,但是并不会在服务器接收数据时被调用,而是只会在数据被写入网络的时候被调用。

如果没有指定流的编码格式,那么传入的数据默认为一个缓冲区,如果想要这个缓冲区在发送之前被编码,需要使用setEncoding指定:

connect.setEncoding("base64");

终止连接

使用connect.end()终止连接。

还可以这样:

connect.end("Goodbye~",'utf-8');

这将会以指定字符集发送数据(缓冲区或字符串),并且在数据发送完毕之后关闭连接。

注意:

当终止连接的时候,实际上是将该操作放入队列之中,当队列清空之前连接是不会被关闭的。

所以,当终止连接之后,你还可以继续监听data事件并收到消息。

错误处理

通过监听error事件来捕获错误

  • error.message :错误信息
  • error.code (字符串)错误码,不是http404那种错误码

创建命令行TCP客户端示例

连接服务器

启用之前学过并写过的TCP服务器,然后使用下面代码连接

const net = require('net');
const port = 1234;
const connect = net.createConnection(port);

connect.on('connect', () => {
    console.log("Connect Success!");
})

connect.on('error', (err) => {
    console.error("ERROR! \N" + err.message);
})

向服务器发送命令行

当Node进程启动的时候,就会准备好一个process.stdin流来接收用户的键盘输入。这个可读流初始处于停止状态,只有使用resume方法恢复之后才能发射data事件。

process.stdin.resume();

现在,有了到服务器的可写流,也有来自用户的输入流,那么可是使用pipe方法将用户输入传送到可写流,写到服务器。

process.stdin.pipe(connect);

打印服务器消息

可以手动将服务器发送给进程标准输出流的消息都打印出来,可以这样做:

connect.pipe(process.stdout);

但是这样做有一个问题,pipe函数会在源流结束时终止目标流,即进程的标准输出流会在连接关闭之后关闭,不过,可以通过pipe的配置传参,让连接关闭之后不终止标准输出流(你不希望每次连接断开功能直接失败吧,就像QQ,就算用户网断了,但是用户输入并发送的消息都会进行缓存,然后尝试重连和发送,而不是当网络断掉之后直接就不让用户输入了)

connect.pipe(process.stdout,{
    end: false
});

连接终止则重新连接

TCP连接也许会被远程服务器关闭,也许会因为网络波动关闭,甚至可能因为长时间没有活动,被超时机制关闭。如果你想关闭之后马上尝试重连,那么这样做:

const port = 1234;
const net = require('net');

const retryInterval = 3000; // 间隔三秒重试,稍定一下让环境稳定一点儿
const retriedTimes = 0; // 已经重连了多少次
const maxTrys = 10; // 最多重连十次

process.stdin.resume();

// 初始立即调用一次连接
(function connect() {
    // 重连方法
    function reconnect() {
        if (retriedTimes >= maxTrys) {
            throw new Error("I can't reconnect,sorry.");
        }
        retriedTimes++;
        // 等到一段时间后重连,注意connect和reconnect
        setTimeout(connect, retryInterval);
    }

    // 思考一下为什么在这儿实例化连接对象而不是一开始就实例化    
    const connect = net.createConnection(port);

    // 监听连接成功
    connect.on('connect', () => {
        // 连接成功就把尝试连接次数清零
        retriedTimes = 0;
        console.log("Connect Sucess!");
    })

    // 如果出错了
    connect.on('error', (err) => {
        console.log("ERROR! \n" + err.message);
    })

    // 连接关闭之后尝试重连
    connect.on('close', () => {
        console.log("Reconnecting......");
        reconnect();
    })

    // 把用户输入传递到服务器
    process.stdin.pipe(connect, {
        end: false
    })
}());

关闭连接

connect.end();

如果你需要用户输入一个命令,例如quit的时候断开连接,可以检测这个字符串:

process.stdin.on('data', (data)=>{
    if (data.toString().trim().toLowerCase() == 'quit') {
        connect.end();
        process.stdin.pause();
    }
})

这段代码有缺点,就是,你还是可以尝试向服务器发送数据,而不管这些数据是不是字符串quit。向一个已经停止接收数据的连接发送数据肯定是不好的。

所以可以使用下面代码去替代:

// 原来if内部的代码替换成
connect.end();
process.stdin.end();// 删除连接

当然,关闭连接会触发重连机制,所以需要设置一个变量,表示这次退出是由用户操作的。

操作起来很简单,就是在手动退出的时候修改变量状态,而在监听关闭事件的时候使用判断该变量,如果是正常退出就跳过重连。

小结

TCP是面向连接的协议,可以为例按顺序处理消息和控制数据流。TCP是传输层的协议,可以基于它创建客户端-服务器协议。

在Node中构建TCP客户端很容易,当尝试与TCP服务器建立连接的时候,通过net.createConnection()返回一个net.Socket实例,他是一个双向流,可是通过该实例传输数据和接受数据。数据既可以是字符串,也可以是指定了编码或未指定编码的缓冲区。

在重连的时候,在多次重连之间需设置间隔时间,同时也需要设置最大尝试次数。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

沧州刺史

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值