# TCP

# 定义

传输控制协议(TCP)是一个面向连接的协议,保证了两台计算机之间数据传输的可靠性和顺序。

Node HTTP 服务器是构建于 Node TCP 服务器之上的。

TCP 的特性:

  • 面向连接的通信和保证顺序的传递
  • 面向字节 - ASCII、Unicode
  • 可靠性
  • 流控制
  • 拥堵控制 - Qos

Socket 是对 TCP 协议的一种封装方式,Socket 本身不是协议,而是一个编程接口。

# telnet 允许在终端手动建立一个 TCP 连接

# 服务端

使用 Node.js 写一个 web 服务器,并监听 3000 端口,然后 node app.js 运行下是否正确

require("http")
  .createServer(function(req, res) {
    res.writeHead(200);
    res.end("Hello world");
  })
  .listen(3000);

# TCP 连接

使用telnet 127.0.0.1 3000建立一个连接,然后输入GET / HTTP/1.1,回车两次,然后服务器端就出现了响应:

~ telnet 127.0.0.1 3000

Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
GET / HTTP/1.1

HTTP/1.1 200 OK
Date: Sun, 15 Sep 2019 06:20:43 GMT
Connection: keep-alive
Transfer-Encoding: chunked

b
Hello world
0

Connection closed by foreign host.

总结:

  • 成功建立了一个 TCP 连接
  • 创建了一个 HTTP 请求
  • 接收到一个 HTTP 响应
  • 到达的数据和在 Node.js 中写的一样

# 基于 TCP 的聊天程序

const net = require("net");

let count = 0,
  users = {};

const server = net.createServer(function(conn) {
  let nickname;

  conn.setEncoding("utf8");
  conn.write(
    "\n > 欢迎访问 \033[92mNode-Chat\033[39m!" +
      "\n > " +
      count +
      "个其他用户已连接" +
      "\n > 请输入你的用户名并回车:"
  );

  count++;

  conn.on("data", function(data) {
    data = data.replace("\r\n", "");
    console.log(data);

    if (!nickname) {
      if (users[data]) {
        conn.write("\033[93m> 昵称已被使用,请重试:\033[39m ");
        return;
      } else {
        nickname = data;
        users[nickname] = conn;
        console.log("users: ", conn);
        broadcast("\033[90m > " + nickname + " 上线了\033[39m\n");
      }
    } else {
      broadcast("\033[96m > " + nickname + ":\033[39m " + data + "\n", true);
    }
  });

  conn.on("close", function() {
    count--;
    delete users[nickname];
    broadcast("\033[90m > " + nickname + " 下线了\033[39m\n");
  });
  // 向每一个用户发送信息
  function broadcast(msg, exceptMyself) {
    for (let i in users) {
      if (!exceptMyself || i != nickname) {
        users[i].write(msg);
      }
    }
  }
});
server.listen(3000, function() {
  console.log("\033[96m  server listening on *: 3000\033[39m");
});

单独运行:telnet 127.0.0.1 3000,比如:

~ telnet 127.0.0.1 3000

Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.

 > 欢迎访问 Node-Chat!
 > 0个其他用户已连接
 > 请输入你的用户名并回车:XiaoMing
 > XiaoMing 上线了
Hi
 > HanMeimei 上线了
 > HanMeimei: Hello
 > LiSi 上线了
 > LiSi: Ni hao ma?

# 第二位用户
 > 欢迎访问 Node-Chat!
 > 1个其他用户已连接
 > 请输入你的用户名并回车:HanMeimei
 > HanMeimei 上线了
Hello

# 第三位用户
 > 欢迎访问 Node-Chat!
 > 2个其他用户已连接
 > 请输入你的用户名并回车:LiSi
 > LiSi 上线了
Ni hao ma?
Last Updated: 5/22/2020, 5:01:49 PM