很多时候,当您与服务器进行实时通讯时,在浏览器端可以使用的方式包括长轮询,短轮询以及WebSocket。

由于TCP也是一种实时通讯协议,你可能会存在与TCP服务器进行消息传递的场景。

浏览器仅支持Websocket的实时通讯,要想与后端TCP服务器通讯,你可能需要像websockify或者websockify-js类似这样的项目。

但有时候处于调试目的,你可能需要自己实现一个Websocket转发到TCP服务器隧道。

Webscoekt客户端

我们的websocket客户端很简单仅仅是发送一个消息,然后将此消息打印在浏览器开发工具的控制台中。

我们建议使用Typescript创建Webscoekt客户端,但你也可以使用Javascript。

现在选择一个你喜欢创建前端项目的工具。比如ViteCreate React App

如果你喜欢从头开始可以使用webpack等类似工具创建项目。在本教程中,我们将使用Vite创建一个Typescript项目。

使用vite创建一个Typescript前端项目,我们将会使用Vue作为模板,但我们不需要编写Vue代码。运行yarn create vite命令创建Typescript前端项目。

yarn create vite

这将会下载Vite的模板创建,此过程需要一些时间,具体取决你的网络。

当完成后会在终端提示你填写项目名称,选择一个你要使用的框架,然后选择所使用的语言ts是Typscript,如果没有ts后缀则是Javascript。

success Installed "create-vite@2.9.3" with binaries:
      - create-vite
      - cva
✔ Project name: … websocket-client
✔ Select a framework: › vue
✔ Select a variant: › vue-ts

Scaffolding project in /home/myfreax/work/typescript/wsc...

如上所示,我们选择Vue作为框架,然后使用Typescript作为主要编写语言。至此前端项目已经创建完成。

现在我们使用vscode打开项目并安装项目Node.js模块依赖,如果你是Linux用户你可以使用cd命令切换到项目目录。

然后使用yarn命令安装模块依赖,再后运行vscode命令打开项目。

cd wsc
yarn
code .

当使用vscode打开项目后,使用以下Typescript代码替换src/main.ts文件。

这将创建一个简单的websocket客户端,仅发送一个helloworld消息,然后接收消息并打印在浏览器控制台。

export async function main() {
  const websocket = new WebSocket("ws://127.0.0.1:8080");
  websocket.onclose = () => console.info("websoket connection closed");
  websocket.onopen = () => console.info("websoket connected");
  websocket.onmessage = (event) => console.info(event.data);
  websocket.onerror = (event) => console.info(event);
}
main().then().catch(console.error);
src/main.ts

至此,Websocket客户端已经创建完成,如果你需要在浏览器运行该代码请运行以下yarn命令。然后在浏览器打开地址http://localhost:3000/

yarn dev

TCP服务器

TCP服务器的代码也是非常简单。TCP服务器接收到消息后,不做任何处理发送回TCP客户端,这非常适合用于调试。也经常称为回显服务器。

现在我们将使用已经创建好的Typescript/Node.js模板项目typescript-backend-template创建后端项目。

可以节省不必要的项目配置时间,例如配置Typescript,Vscode的调试配置,监听文件变化重启Node.js配置等。

我们不建议你使用Vite创建前端项目一样创建后端项目。除非你非常熟悉Typescript每一项配置参数,否则你会遇到ES模块导入的错误。

运行以git命令创建使用我们模板创建Node.js项目,然后使用cd命令切换到tcp-server目录中并安装Node.js模块依赖,再后使用vscode打开tcp-server项目。

git clone git@github.com:myfreax/typescript-backend-template.git tcp-server
cd tcp-server
yarn
code .

当使用使用vscode打开项目后,使用以下Typescript代码替换src/main.ts文件。这将创建一个简单的TCP服务器。

import { Server, Socket } from 'net';
const port = 8081;
const server = new Server();
server.listen(port, function () {
  console.log(
    `Server listening for connection requests on socket localhost:${port}`,
  );
});

server.on('connection', function (socket: Socket) {
  console.log('A new connection has been established.');
  socket.on('data', function (buffer) {
    socket.write(buffer);
    console.log(`Data received from client`);
  });
  socket.on('end', function () {
    console.log('Closing connection with the client');
  });
  socket.on('error', function (err: Error) {
    console.error(err);
  });
});
src/main.ts

至此,我们已经完成TCP服务器端项目的创建,如你需要运行它,运行yarn start:dev命令即可启动tcp服务器。

此命令监听文件的变化以重新启动你的Node.js应用程序。

yarn start:dev

Webscoekt转发TCP

要实现Webscoekt数据装发到TCP服务器。我们还必须实现TCP客户端和Websocket服务器。

由于Node.js没有默认Websocket的实现。因此我们将使用第三方模块的websocket实现。

ws是Node.js的Websocket的实现,简单易用、快速且经过全面测试的Node.js WebSocket客户端和服务器,在这里我们仅使用WebSocket服务器端。

为了实现Websocket到TCP数据转发。我们继续使用Node.js/Typescript后端模板typescript-backend-template创建项目websocket-tcp。

运行以下命令创建websocket-tcp项目,该项目和TCP项目一样,也是后端类型项目。

git clone git@github.com:myfreax/typescript-backend-template.git webscoket-tcp

cd webscoket-tcp
yarn
code .

创建项目完成后,使用yarn命令添加ws模块到你的webscoket-tcp项目中:

yarn add ws

然后使用Typescript代码替换src/main.ts文件。这代码很简单,下面我们简单解释一下代码。

import WebSocket, { WebSocketServer } from 'ws';
import { Socket } from 'net';
const tcp = new Socket();
tcp.connect(8081, '127.0.0.1', function () {
  console.log('Connected Server');
});
tcp.on('close', function () {
  console.log('Server Connection closed');
});
const wss = new WebSocketServer({ port: 8080 });
wss.on('connection', function connection(ws) {
  ws.on('message', function message(data: WebSocket.RawData) {
    const u8 = data.valueOf() as Uint8Array;
    tcp.write(u8);
  });
  tcp.on('data', function (data: Buffer) {
    ws.send(data);
  });
});
src/main.ts

它使用Node.js net模块的socket对象,创建一个TCP连接通过connect方法,连接到127.0.0.1:8081即本地主机8081端口。

然后创建WebSocketServer的实例创建websocket服务器在端口8080

当websocket服务器的message事件接收到浏览器端的数据后,它是一个RawData数据,

而TCP socekt的write方法要求参数是Uint8Array。因此我们需要RawData转换为Uint8Array

RawDatavalueOf方法可帮助我们将websocket的数据转换为Uint8Array。这是也是实现转发数据的核心与最难的一点。

现在我们实现了数据的转换,接下来使用TCP socket的write发送TCP服务器。我们的TCP服务器将次数据不做任何处理返回到TCP客户端。

TCP socket监听data事件接收来自TCP服务器的数据,该数据是一个Buffer,因此我们不需要做任何处理即可将该数据使用websocket的send方法发送到浏览器。整个过程已经完成。

结论

你已学会如何使用Node.js/Typescript创建websocket客户端/服务器以及TCP服务器/客户端。在浏览器创建websocekt客户端。转发websocket数据到TCP服务器。如果您有任何疑问或反馈,请随时在下面评论。