前言:
学习视频:中科大郑烇、杨坚全套《计算机网络(自顶向下方法 第7版,James F.Kurose,Keith W.Ross)》课程
该视频是B站非常著名的计网学习视频,但相信很多朋友和我一样在听完前面的部分发现信息量过大,有太多无法理解的地方,在我第一次点开的时候也有相同的感受,但经过了一段时间项目的学习,对计网有了更多的了解,所以我准备在这次学习的时候做一些记录并且加入一些我的理解,希望能够帮助到大家。
往期笔记可以看专栏中的内容😊😊😊
文章目录
- 2.9 UDP 套接字编程
- 03. 传输层
- 3.1 概述和传输层的服务
- 3.1.1 传输服务和协议
- 3.1.2 传输层 VS 网络层
- 3.1.3 Internet 传输层协议
2.9 UDP 套接字编程
💡 与 TCP 不同的是 UDP 在客户端和服务器之间没有连接
- 发送端在报文中要明确的制定目标的 IP 地址和端口号
- 服务器必须从收到的分组中提取出发送端的 IP 地址和端口号。
再来看一下 UDP 套接字编程的代码,与上节的 TCP 编程做一下对比
👉 上节内容:中科大计网学习记录笔记(十二):TCP 套接字编程
因为很多具体的部分上节已经讲过了,这里直接上代码
🍀 服务端
// 创建 UDP 套接字sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (sockfd < 0) {perror("Socket creation failed");exit(EXIT_FAILURE);}// 创建 TCP 套接字if ((client_sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {perror("socket creation failed");exit(EXIT_FAILURE);}
可以看出创建 socket 时指定的套接字类型不同,分别为 SOCK_DGRAM
和 SOCK_STREAM
// 设置服务器地址结构memset(&server_addr, 0, sizeof(server_addr));memset(&client_addr, 0, sizeof(client_addr));server_addr.sin_family = AF_INET;server_addr.sin_addr.s_addr = INADDR_ANY;server_addr.sin_port = htons(PORT);// 将套接字绑定到服务器地址if (bind(sockfd, (const struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {perror("Bind failed");exit(EXIT_FAILURE);}
接下来是设置服务器的 sockaddr
并且将其与 socket 相关联
while (1) {// 接收来自客户端的消息n = recvfrom(sockfd, (char *)buffer, BUF_SIZE, 0, (struct sockaddr *)&client_addr, &len);buffer[n] = '\0';printf("Client : %s\n", buffer);// 将接收到的消息发送回客户端sendto(sockfd, (const char *)buffer, strlen(buffer), 0, (const struct sockaddr *)&client_addr, len);
}
在这里可以发现,服务器并没有 创建新的 socket 而是直接从输入中获得了客户端的信息来直接返回数据。
🍀 客户端
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0) {perror("Socket creation failed");exit(EXIT_FAILURE);
}
// 设置服务器地址结构
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(PORT);
server_addr.sin_addr.s_addr = inet_addr(SERVER_IP);
// 发送信息到服务器
sendto(sockfd, (const char *)buffer, strlen(buffer), 0, (const struct sockaddr *)&server_addr, sizeof(server_addr));
// 接收服务器的响应
n = recvfrom(sockfd, (char *)buffer, BUF_SIZE, 0, NULL, &len);
💡 可以看出是直接发送的数据,而没有经过连接的过程
03. 传输层
提纲:
3.1 概述和传输层服务
3.2 多路复用与解复用
3.3 无连接传输:UDP
3.4 可靠数据传输的原理
3.5 面向连接的传输 TCP
- 段结构
- 可靠数据传输
- 流量控制
- 连接管理
3.6 拥塞控制原理
3.7 TCP 拥塞控制
3.1 概述和传输层的服务
3.1.1 传输服务和协议
💡 传输层为运行在 不同主机 上的 应用进程 提供了逻辑通信
- 在前面的学习中可以得知,网络层提供了端到端的通信,而传输层在网络层的基础上又提供了进程到进程的通信。
-
传输协议(如 TCP、UDP)运行在端系统上,发送方将应用层的报文分割成报文段(UDP 为数据报(datagram))
-
TCP 提供的是数据流的服务,而对于数据的分割需要应用层根据协议来判断
3.1.2 传输层 VS 网络层
💡 传输层提供进程之间的通信,网络层提供端到端的通信
在前面学到:本层对于上层的服务是本层的服务与其下面所有层提供的服务的总和
传输层作为网络层的上层在其端到端的通信的基础上做了如下的增强:
传输层对网络层做了几项主要的增强:
- 可靠性:传输层提供了可靠的数据传输机制。TCP(传输控制协议)通过序列号、确认和重传机制来确保数据的可靠性,即使在网络出现丢包或乱序的情况下也能够按序正确地传输数据。
- 流量控制:传输层通过流量控制机制来控制数据的传输速率,以防止发送方发送速度过快导致接收方无法及时处理数据而造成数据丢失。TCP利用滑动窗口机制进行流量控制。
- 拥塞控制:传输层还实现了拥塞控制机制,以避免网络拥塞并确保网络的高效利用。TCP通过拥塞窗口和拥塞避免算法来控制数据的发送速率,从而避免网络拥塞。
- 多路复用:传输层可以在单个网络连接上同时传输多个数据流,即多路复用。TCP和UDP都支持在同一个端口上通过不同的套接字进行多路复用。
在这些里面需要注意的是多路复用:多路复用就是提供传输多个数据流来为多个进程提供服务,分为两步
- 在传输端需要做到 多路复用
- 在接收端需要 解复用
来举一个现实中的例子:
💡 Ann 家里的 12 个孩子给 Bill 家里的 12 个孩子发邮件
- Ann 家里将所有的邮件打包发出(复用)
- Bill 家里来讲邮件分发给不同的孩子(解复用)
类比:
- 主机 = 家庭
- 进程 = 小孩
- 应用层报文= 信封中的信件
- 传输协议= Ann 和 Bill
- 为家庭小孩提供复用解复用服 务
- 网络层协议 = 邮政服务
- 家庭-家庭的邮包传输服务
3.1.3 Internet 传输层协议
🍀 TCP
提供的服务:
- 可靠的数据传输:TCP通过序列号、确认和重传机制来确保数据的可靠传输,即使在网络出现丢包或乱序的情况下也能够按序正确地传输数据。
- 流量控制:TCP通过滑动窗口机制来进行流量控制,防止发送方发送速度过快导致接收方无法及时处理数据而造成数据丢失。
- 拥塞控制:TCP通过拥塞窗口和拥塞避免算法来控制数据的发送速率,避免网络拥塞并确保网络的高效利用。
- 面向连接:TCP是面向连接的协议,通信双方在通信前需要建立连接,数据传输完成后需要释放连接。这种连接方式提供了一种可靠的通信环境,可以确保数据传输的有序性和可靠性。
- 有序传输:TCP保证数据的有序传输,即发送方发送的数据包按顺序到达接收方,接收方能够按顺序正确地接收和处理数据。
- 多路复用和解复用
🍀 UDP
提供的服务
- 无连接:UDP是一种无连接的协议,通信双方在通信前不需要建立连接,直接进行数据传输。这使得UDP的通信过程更加简单和高效。
- 尽最大努力交付:UDP不保证数据的可靠传输,它尽最大努力将数据包从发送方传输到接收方,但不保证数据的正确性、顺序性和完整性。因此,在不稳定的网络环境下,UDP可能会出现丢包、乱序或重复传输等问题。
- 无流量控制:UDP不提供流量控制机制,发送方可以按照自己的速度发送数据,而不考虑接收方的接收能力。这意味着UDP可能会导致网络拥塞和数据丢失。
- 无拥塞控制:与流量控制类似,UDP也不提供拥塞控制机制,发送方发送数据时不会考虑网络的拥塞情况,可能会导致网络拥塞和数据丢失。
- 数据报格式:UDP使用数据报格式来传输数据,每个数据报都包含了完整的数据信息以及源和目标端口号等信息,这使得UDP适用于对实时性要求较高的应用场景,如音视频传输、在线游戏等。
- 多路复用和解复用