js 网络编程简述

node.js 的 net 实现的 tcp 链接

node.js 内置 net 模块来实现面相 tcp 的套接字编程,并且简化了 tcp 协议底层的很多操作,可以快速搭建一个 tcp 服务器或打开一个 tcp 链接。

建立 tcp 服务器

以下代码可以在9000端口上开启一个简单的 tcp 服务器,并且监听获取的数据流并打印到所运行的终端上。

/** @file server.js */
const net = require("net");
const server = net.createServer();
server.on("connection", connection => {
  connection.write("发送消息!over!\r\n");
  connection.on("data", chunk =>
    console.log("这是链接发送的片段:" + chunk.toString("utf8"))
  );
});
server.listen(9000);

tcp 协议是可以双向通讯的,不论服务器或是客户端,都可以向对方发送信息,也都可以接收对方的消息。因此,tcp 的链接都继承自双工流。双工流同时实现了可读流和可写流,connection.write 就是可写流的方法,而 connection.on("data") 又是可读流的事件。

可以使用 telnet 等工具来访问上述代码运行的服务器,当然也可以自己写一个客户端。

建立 tcp 客户端

以下代码链接了本机上9000端口上的一个 tcp 服务器,在链接成功时输出已连接,发送数据并在接受第一条数据后关闭链接。

/** @file client.js */
const net = require("net");
const connection = net.createConnection({
  host: "127.0.0.1",
  port: 9000
});
connection.on("connect", () => {
  console.log("已连接");
  connection.write("你好,这里是客户端\r\n");
  connection.on("data", chunk => {
    console.log("这里是链接发来的片段:" + chunk.toString("utf8"));
    connection.end();
  });
});

同理,在客户端上建立的链接也继承了双工流,直接调用流的方法和注册事件,就可以实现通讯。

然后来走一遍流程:
启动服务器:

PS D:\document\my doc\test\tsScript\src\socket> node .\server.js

运行客户端:

PS D:\document\my doc\test\tsScript\src\socket> node .\client.js
已连接
这里是链接发来的片段:发送消息!over!

服务器输出:

PS D:\document\my doc\test\tsScript\src\socket> node .\server.js
这是链接发送的片段:你好,这里是客户端

栗子

简单的 tcp 聊天室

聊天室需要在服务器端存储来访问的链接,并广播信息。在客户端需要获取命令行的输入流并输出接收到的广播信息。
服务器端实现:

/** @file server.js */

const conf = {
  name: "玄晓乌屋",
  port: 9000
};

const server = require("net").createServer();
const users = [];
server.on("connection", connection => {
  // 存储连接
  users.push(connection);
  // 广播信息
  connection.on("data", msg =>
    users.forEach(user => user !== connection && user.write(msg))
  );
  // 删除断开的链接
  connection.on("end", () => users.splice(users.indexOf(connection), 1));
  connection.on("error", _error => console.log("意外的错误。"));
});

server.listen(conf.port);
console.log("聊天室启动完毕。");

客户端代码

/** @file client.js */

const option = {
  host: "127.0.0.1",
  port: 9000
};
const connection = require("net").createConnection(option);
const rl = require("readline").createInterface({
  input: process.stdin,
  output: process.stdout
});
let username = "";
rl.question("请输入你的大名:", answer => {
  username = answer;
  connection.write(`${username} 进入了聊天室!`);
});

connection.on("data", chunk => console.log(chunk.toString("utf8")));
rl.on("line", input => connection.write(`${username}${input}`));
// 此事件监听了命令行 【Ctrl + C】 输入
rl.on("SIGINT", () => {
  connection.write(`${username} 退出了聊天室`);
  rl.pause();
  connection.end();
});

验证:首先启动服务器端,然后启动两个或多个客户端终端测试。
验证过程:略。
结果:

PS D:\document\my doc\test\tsScript\src\socket> node .\client.js
请输入你的大名:1号
2号 进入了聊天室!
hello 2号
2号:hello 1号
2号 退出了聊天室

远程终端连接

前几日整理了远程终端的简单连接,在此不赘述。
点此查看

发送http报文

因为 http 是基于 tcp 建立的无状态请求,固可以用 tcp 服务器来实现发送 http 的报文。
首先需要简要了解 http 报文头的相关信息,可以百度或者谷歌查询,然后建立一个简单的 http 响应报文文件,如下:

HTTP/1.1 200 OK
Content-Type:text/html; charset=utf-8
server:TCPServer

<html>
  <head>
    <title>test</title>
  </head>
  <body>
    <h1>Hello World!还有中文咯。</h1>
  </body>
</html>

第一行为状态,标识了 http 协议版本和状态值,第二行到空行都是响应头,空行后是响应数据。

然后就写一个响应此报文的 tcp 服务器如下:

/** @file server.js */
require("net")
  .createServer(connection =>
    require("fs")
      .createReadStream("./http", { encoding: "utf8" })
      .pipe(connection)
  )
  .listen(9000);

其中“./http”是报文文件,我没有设置后缀名。因为要渲染中文字符,还要注意相关字符集。
启动后使用游览器访问地址 “localhost:9000” 得到如下页面:
在这里插入图片描述
然后看看响应的报文:
在这里插入图片描述
和之前定义的一样,没有什么差别。

WebSocket

WebSocket 是 html5 新增的特性,使得 javascript 在游览器和服务器建立一个长连接,实现实时通信,虽然是实时通信,但是 WebSocket 却是基于 http 协议的,也就是说,它并不是直接发起一个 tcp 连接,而是建立了一个 http 的长连接。同时协议简写也为 ws ,从 https?:// 这样的请求变为了 ws:// 这样的请求。

在以下例子中,服务器端使用 ws 库

建立 ws 服务器

首先需要安装 ws 模块:

npm i ws

然后书写 WebSocket 服务器端代码:

/** @file server.js */
const WebSocket = require("ws");

const server = new WebSocket.Server({ port: 9000 });
server.on("connection", ws => {
  ws.on("message", msg => {
    ws.send("收到消息:" + msg);
  });
});

至此就完成了,但是我们不能用简单的 tcp 客户端或者简单的 http 请求去访问。

建立 ws 客户端

新建一个页面如下:

<!DOCTYPE html>
<html lang="ZH-CN">
  <head>
    <meta charset="UTF-8" />
    <title>WebSocket</title>
  </head>
  <body>
    <p>
      <input type="text" />
      <button>发送</button>
    </p>
  </body>
  <script>
    var input = document.getElementsByTagName("input")[0];
    var btSend = document.getElementsByTagName("button")[0];
    var ws = new WebSocket("ws://127.0.0.1:9000");

    ws.onopen = function() {
      btSend.addEventListener(
        "click",
        function(event) {
          if (input.value !== "") {
            ws.send(input.value);
          }
        },
        false
      );
    };
    ws.onmessage = function(messageEvent) {
      console.log(messageEvent.data);
    };
  </script>
</html>

然后把这个客户端页面拖拽到游览器当中并打开控制台,注意 WebSocket 是 html5 的内容,所以需要足够高版本的游览器才能支持。

然后在输入框中输入一些文字,并点击发送按钮,就可以在控制台收到服务器端发来的消息了。
在这里插入图片描述

小结

WebSocket 让 js 和服务器端进行了长连接,是替换以前轮询的最好方式,但是 WebSocket 虽然已经足够简单了,但是长连接本身不够简单,重连,广播等操作都是 socket 常用的逻辑,还是需要大量代码重构,并且还有兼容性等等遗漏的问题没有解决。

WebSocket 可以实现的东西很多,参照 node 中的 tcp 连接相关的栗子就知道,实时通信,页面上的终端等,使用 WebSocket 都可以实现。

socket.io 库

socket.io 库是 js 和 nodejs 通讯的桥梁,使用简单,兼容性好(低版本游览器降低为轮询)。socket.io 支持自动重连、广播、命名空间和自定义事件等等大多常用通讯逻辑,是 web 通讯中非常实用的库。

socket.io 内容较多,可以上 官网查看更多内容。

建立 socket.io 服务器

/** @file server.js */
const io = require("socket.io")(9000);
io.on("connection", socket => {
  socket.on("message", data => console.log(data));
});

虽然代码上看上去并没有比 WebSocket 少多少,但是它内部实现了重连功能。

建立 socket.io 客户端

首先需要建立一个网页文件,并且引入 socket.io 的网页客户端代码,socket.io 的网页客户端代码不用特地去寻找 cdn 等,socket.io 的服务器自带了,所以直接从某个已经建立的 socket.io 服务器获取即可,其路径为:host:port/socket.io/socket.io.js

因为前一节已经在本机的 9000 端口上建立了 socket.io 服务器,直接在网页文件中引入如下字段即可引入 socket.io 网页客户端:

<script src="http://localhost:9000/socket.io/socket.io.js"></script>

网页实现如下:

<!DOCTYPE html>
<html lang="ZH-CN">
  <head>
    <meta charset="UTF-8" />
    <title>socket.io</title>
    <script src="http://localhost:9000/socket.io/socket.io.js"></script>
  </head>
  <body>
    <script>
      var socket = io("http://localhost:9000");
      setInterval(() => {
        socket.send("test text!");
      }, 1000);
    </script>
  </body>
</html>

把这个页面直接拖到浏览器中即可,不过要事先启动 socket 服务器。完全启动后服务器端的终端就会每秒打印网页客户端发来的信息。

需要注意的是,服务器端获取到的数据并不是一个流,所以不要指望使用流相关的操作。

socket.io 本身是一个库,官网上有详细文档,本文只是小试牛刀,不再赘述。

总结

nodejs 使得 js拥有了在服务器端运行的能力,同时 node 的网络模块和 html5 的 WebSocket 模块也大大增强了 js 在服务端的通信能力。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值