https://github.com/luckydrq/tcp-net
Build tcp applications in a stable and elegant way
https://github.com/luckydrq/tcp-net
socket tcp tcp-client tcp-server
Last synced: 8 months ago
JSON representation
Build tcp applications in a stable and elegant way
- Host: GitHub
- URL: https://github.com/luckydrq/tcp-net
- Owner: luckydrq
- License: mit
- Created: 2019-01-07T13:47:51.000Z (over 7 years ago)
- Default Branch: master
- Last Pushed: 2023-07-20T09:56:52.000Z (almost 3 years ago)
- Last Synced: 2025-09-18T08:17:07.820Z (9 months ago)
- Topics: socket, tcp, tcp-client, tcp-server
- Language: JavaScript
- Homepage:
- Size: 27.3 KB
- Stars: 49
- Watchers: 1
- Forks: 6
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: History.md
- License: LICENSE
Awesome Lists containing this project
README
# @luckydrq/tcp-net
编写稳定可靠的TCP长连接应用。
封装TCP连接的拆解包逻辑,支持`Length-Based`和`Line-Based`两种协议格式。
**注意,本模块只支持node 8.x以上。**
[![NPM version][npm-image]][npm-url]
[![build status][travis-image]][travis-url]
[![Test coverage][codecov-image]][codecov-url]
[![David deps][david-image]][david-url]
[![Known Vulnerabilities][snyk-image]][snyk-url]
[![NPM download][download-image]][download-url]
[![Gitter][gitter-image]][gitter-url]
[npm-image]: https://img.shields.io/npm/v/@luckydrq/tcp-net.svg?style=flat-square
[npm-url]: https://npmjs.org/package/@luckydrq/tcp-net
[travis-image]: https://img.shields.io/travis/luckydrq/tcp-net.svg?style=flat-square
[travis-url]: https://travis-ci.org/luckydrq/tcp-net
[codecov-image]: https://img.shields.io/codecov/c/github/luckydrq/tcp-net.svg?style=flat-square
[codecov-url]: https://codecov.io/gh/luckydrq/tcp-net
[david-image]: https://img.shields.io/david/luckydrq/tcp-net.svg?style=flat-square
[david-url]: https://david-dm.org/luckydrq/tcp-net
[snyk-image]: https://snyk.io/test/npm/@luckydrq/tcp-net/badge.svg?style=flat-square
[snyk-url]: https://snyk.io/test/npm/@luckydrq/tcp-net
[download-image]: https://img.shields.io/npm/dm/@luckydrq/tcp-net.svg?style=flat-square
[download-url]: https://npmjs.org/package/@luckydrq/tcp-net
[gitter-image]: https://img.shields.io/gitter/room/luckydrq/tcp-net.svg?style=flat-square
[gitter-url]: https://gitter.im/luckydrq/tcp-net
## Feature
- [x] 长连接
- [x] 连接保持(心跳检测)
- [x] 支持多请求多响应
- [x] 可扩展协议
- [x] 可扩展编解码器
## Protocol
我们对一个tcp包协议格式进行了如下约定:
```
|-----------------------------------------------|
| 1 byte | 4 bytes | 1 byte | N bytes |
|-----------------------------------------------|
| reqType | packetId | packetType | custom body |
|-----------------------------------------------|
```
- reqType: Number, 请求类型。0 - 请求 1 - 响应
- packetId: Number, 包id。
- packetType: Number, 包类型。0 - 普通包 1 - 心跳包
- custom body: 自定义包体。
其中,自定义包体就是用户发送的数据,它可以支持`Length-Based`和`Line-Based`两种子协议。
### Length-Based Protocol
默认内置。适用于用户定义的包长度是确定的场景。原理很简单,先用一个field标识包体的长度,紧接着就是相应长度的包体。field本身长度支持自定义设置,默认是4字节。
```
|------------------|---------------|
| 4 bytes | N bytes |
|------------------|---------------|
| PACKET LENGTH(N) | HEADER | BODY |
|------------------|---------------|
```
### Line-Based Protocol
适用于用户定义的包长度不确定的场景。它用一种边界符来表示包的结束。最典型的例子,`http`协议格式就是`Line-Based`的协议,它的边界符(或者说分隔符)是`CRLF(\r\n)`。边界符支持自定义设置,默认是`CRLF`。
```
|------------------|-----------|
| N bytes | delimiter |
|------------------|-----------|
| PACKET BODY | \r\n |
|------------------|-----------|
```
## Install
```
$ npm i @luckydrq/tcp-net -S
```
## Examples
### Basic
client和server应该使用相同的协议,保持拆解包逻辑一致。
#### server
```js
const net = require('net');
const { Connection } = require('@luckydrq/tcp-net');
net.createServer(socket => {
const conn = new Connection({
socket,
// protocol: new LengthBasedProtocol(), default
});
// 发送一个packet
conn.write('hello world');
// 收到packet
conn.on('packet', ({ packetId, body }) => {
console.log(packetId); // 1
console.log(JSON.parse(body)); // { name: 'xuezu' }
});
}).listen();
```
#### client
```js
const { Connection } = require('@luckydrq/tcp-net');
const conn = new Connection({ host, port });
// 发送一个packet
conn.write({ name: 'xuezu' });
// 收到一个packet
conn.on('packet', ({ packetId, body }) => {
console.log(packetId); // 1
console.log(body); // hello world
});
```
### Heartbeat
内置了心跳检测,默认每隔5秒发起一次心跳检测,响应超时时间为3秒,超时3次则关闭连接。支持配置,在构造函数中传入:
```js
const conn = new Connection({
heartbeatInterval: 5 * 1000, // 心跳间隔
heartbeatTimeout: 3 * 1000, // 超时时间
heartbeatLimit: 3, // 允许超时次数
});
conn.on('heartbeatTimeout', () => {
console.log('连接已经关闭');
});
```
### Transcoder
通常需要对数据做编解码,本例子展示如何接入一个自定义编解码器。如果不提供,默认[只做基本的序列化](https://github.com/luckydrq/tcp-net/blob/master/lib/protocol.js)。
自定义实现一个transCoder,只需要实现`.encode`和`.decode`方法即可,也可以只实现其中之一,不过通常编解码逻辑都是对应的。
#### server
```js
const transCoder = {
encode(buf) {
// 调用hessian编码
// 注意,需要返回Buffer对象
return hessian.encode(buf);
},
decode(data) {
// 可以返回任意类型的数据
return hessian.decode(buf);
},
};
net.createServer(socket => {
const conn = new Connection({
socket,
protocol: new LengthBasedProtocol({ transCoder }), // 在协议中传入transCoder
});
// 收到packet
conn.on('packet', ({ body }) => console.log(body));
}).listen();
```
#### client
```js
const conn = new Connection({
host,
port,
protocol: new LengthBasedProtocol({ transCoder }),
});
// 发一个packet
conn.write({ name: 'xuezu' });
```
### [更多例子](https://github.com/luckydrq/tcp-net/blob/master/test/index.test.js)