为什么要写这篇博客

一个是感觉自己的计算机网络基础薄弱,关于七层模型和 tcp、udp 看过几次了,都不够透彻,知其然不知其所以然。再一个,最近和同事有聊到这个事,感觉自己也说不明白,又意识到很重要,所以决定整理一下,自己感觉自己会了和可以给别人讲明白这个事儿,区别还是很大的啊。就参考资料和自己理解记录一下。

先说什么是网络协议

两台设备进行网络通信时,双方要提前约定一些规则。这样才可以让对方设备理解你要做什么。比如,如何发起通信,如何发出/接收数据,如何关闭链接。

再说 OSI 7 层模型 和 TCP/IP 4 层模型

OSI (Open System Interconnection) 开放式系统互联参考模型,为了统一处理,模块化,易于维护,OSI 采用分层结构。包含七层,每一层实现各自的功能和协议,通过接口提供给更高一层并完成与相邻层的接口通信。

IOS 7 层模型是一种网络通信理论模型。其含义就是推荐所有公司使用这个规范来控制网络。这样所有公司都有相同的规范,设备就能互联了。OSI 参考模型是学术上法律上的国际标准,是完整的权威的网络参考模型

关系如下:

OSI 7 层模型功能传送介质对应 TCP/IP 4 层模型对应协议
应用层 Application为应用进程提供网络服务。报文应用层HTTP、FTP、SMTP
表示层 Presentation数据格式化,加密和解密。报文应用层Telnet、Rlogin、SNMP、Gopher
会话层 Session建立应用和应用之间的连接。报文应用层SMTP、DNS
传输层 Transport建立设备和设备之间的连接。报文传输层TCP、UDP
网络层 Network为数据包选择路由,寻址。数据包网络层IP、ICMP、ARP、RARP、AKP、UUCP
数据链路层 Data Link根据以太网协议将一组电信号组成一个数据包,称作”帧”,控制传输。通俗说,就是控制数据在网线、光纤传输。数据帧链路层FDDI、Ethernet、Arpanet、PDN、SLIP、PPP
物理层 Physical把网线,光纤将设备链接起来组网。物理传输介质。比特流链路层IEEE 802.1A、IEEE 802.2 到 IEEE 802.11

TCP/IP 4 层模型 (协议簇)

TCP/IP 协议簇是 internet 的基础,是多个协议的统称,命名为 TCP/IP 是因为TCPIP是其中很重要的两个协议。

TCP/IP 分为四层,每一个层都有各自的协议和功能,其中 TCPUDP 协议位于 TCP/IP 协议簇的传输层。

TCP/IP 借鉴了 OSI 的分层概念建立TCP/IP模型,TCP/IP 已被广泛使用,成为网络互联事实上的标准

使用 TCP/IP 协议传递数据图解

image-20220306115359466

TCP

TCP (Transmission Control Protocol) 全称是传输控制协议,是一种面向连接的可靠的全双工单播传输的基于字节流的传输层通信协议。属于TCP/IP协议簇的传输层。

  • 面向连接: 即传递数据前在两端建立连接,使用“三次握手”确保两端的发送和接收能力,提供可靠的连接
  • 仅支持单播传输:只能进行一对一的数据传输,不支持组播和广播传输方式。
  • 拥堵控制:网络拥堵的时,TCP能够减小向网络注入数据的速率和数量,缓解拥堵,提供对流量控制和服务质量的访问。
  • 全双工: 双端既可以当接收者,也可以当发送者
  • 基于字节流模式: 比如发送端发送 100 字节到目标端,目标端可以分 10 次,每次 10 字节接受,也就是以少量数据分以任意次接收

UDP

UDP(User Data Protocol)全称用户数据报协议,是一种无连接的不可靠的支持组播和广播基于数据报的传输层通信协议。属于TCP/IP协议簇的传输层。

  • 无连接不可靠: 不需要繁琐的三次握手,确认、重传、拥塞控制等机制,没有这些安全机制,速度更快的同时,安全性变差,易丢包。UDP 使用尽可能最大努力交付,但不保证可靠交付。
  • 支持组播和广播: 可以一对一一对多多对一多对多数据传输。
  • 基于数据报模式: 一次发送对应一次接收,一次只读取一个报文,多个报文不可以合并。

UDP 和 TCP 区别总结

指标TCPUDP
连接面向连接无连接
报文面向字节流面向报文
效率
是否可靠可靠不可靠
拥塞控制
速度
双共性全双工一对一、一对多、多对一、多对多

使用 nodejs 实现 TCP 连接

服务端

const net = require("net");
const HOST = "127.0.0.1";
const PORT = 8081;
const server = net.createServer();
server.on("listening", () => {
  console.log(`TCP server at ${HOST}:${PORT}`);
});
server.on("connection", (socket) => {
  socket.on("data", (buffer) => {
    const msg = buffer.toString();
    console.log(msg);
    socket.write(Buffer.from(`来自服务端 ${msg}`));
  });
});
server.on("close", () => {
  console.log("TCP server close!");
});
server.on("error", (err) => {
  console.error(`TCP server error :${err}`);
  setTimeout(() => {
    server.close();
  }, 1000);
});
server.listen(PORT, HOST);

客户端

const net = require("net");
const HOST = "127.0.0.1";
const PORT = 8081;
const client = net.createConnection({
  host: HOST,
  port: PORT,
});
client.on("connect", () => {
  setTimeout(() => {
    client.write("客户端向服务端发送消息: 1");
  }, 1000);
  setTimeout(() => {
    client.write("客户端向服务端发送消息: 2");
  }, 2000);
  setTimeout(() => {
    client.write("客户端向服务端发送消息: 3");
  }, 3000);
});
client.on("data", (buffer) => {
  console.log(buffer.toString());
});
client.on("error", (err) => {
  console.error("TCP server error", err);
});
client.on("close", (err) => {
  console.log("client disconnects", err);
});

903kj94rnyoOIrs

使用 nodejs 实现 UDP 连接

服务端

const dgram = require("dgram");
const HOST = "127.0.0.1";
const PORT = 8082;

const server = dgram.createSocket("udp4");

server.on("listening", function () {
  const address = server.address();
  console.log(`UDP server at ${HOST}:${PORT}`);
});

server.on("message", function (message, remote) {
  console.log(`来自服务端 ${message}`);
});

server.bind(PORT, HOST);

客户端

const dgram = require(`dgram`);
const PORT = 8082;
const HOST = "127.0.0.1";

const client = dgram.createSocket("udp4");

setTimeout(() => {
  sendMsg(Buffer.from(`客户端向服务端发送消息: 1`));
}, 1000);

setTimeout(() => {
  sendMsg(Buffer.from(`客户端向服务端发送消息: 2`));
}, 2000);

setTimeout(() => {
  sendMsg(Buffer.from(`客户端向服务端发送消息: 3`));
}, 3000);

setTimeout(() => {
  client.close();
  console.log("客户端主动关闭");
}, 4000);

function sendMsg(_msg) {
  client.send(_msg, PORT, HOST, function (err, bytes) {
    if (err) throw err;
    console.log(_msg.toString());
  });
}

image-20220222230031275