> # ♻️ 资源
> **大小:** 1.17MB
> **文档链接:**[**https://www.yuque.com/sxbn/ks/100010469**](https://www.yuque.com/sxbn/ks/100010469)
> **➡️ 资源下载:**[**https://download.csdn.net/download/s1t16/87390866**](https://download.csdn.net/download/s1t16/87390866)
> **注:更多内容可关注微信公众号【神仙别闹】,如当前文章或代码侵犯了您的权益,请私信作者删除!**
> ![qrcode_for_gh_d52056803b9a_344.jpg](https://cdn.nlark.com/yuque/0/2023/jpeg/2469055/1692147256036-49ec7e0c-5434-4963-b805-47e7295c9cbc.jpeg#averageHue=%23a3a3a3&clientId=u8fb96484-770e-4&from=paste&height=140&id=u237e511a&originHeight=344&originWidth=344&originalType=binary&ratio=1.25&rotation=0&showTitle=false&size=8270&status=done&style=none&taskId=ud96bf5f7-fe85-4848-b9c2-82251181297&title=&width=140.1999969482422)
# 网络传输机制-支持 TCP 可靠数据传输
## 实验内容
支持 TCP 可靠数据传输
- 网络丢包
- 超时重传机制
- 有丢包场景下的连接建立和断开
- 发送队列和接收队列
- 超时定时器实现
## 实验步骤
- 修改 tcp_apps.c(以及 tcp_stack.py),使之能够收发文件
- 执行 create_randfile.sh,生成待传输数据文件 client-input.dat
- 运行给定网络拓扑(tcp_topo.py)
- 在节点 h1 上执行 TCP 程序
- 执行脚本(disable_tcp_rst.sh, disable_offloading.sh),禁止协议栈的相应功能
- 在 h1 上运行 TCP 协议栈的服务器模式 (./tcp_stack server 10001)
- 在节点 h2 上执行 TCP 程序
- 执行脚本(disable_tcp_rst.sh, disable_offloading.sh),禁止协议栈的相应功能
- 在 h2 上运行 TCP 协议栈的客户端模式 (./tcp_stack client 10.0.0.1 10001)
- Client 发送文件 client-input.dat 给 server,server 将收到的数据存储到文件 server-output.dat
- 使用 md5sum 比较两个文件是否完全相同
- 使用 tcp_stack.py 替换其中任意一端,对端都能正确收发数据
## 设计思路
- 每个连接维护一个超时重传定时器
- 定时器管理
- 当发送一个带数据/SYN/FIN 的包,如果定时器是关闭的,则开启并设置时间为 200ms
- 当 ACK 确认了部分数据,重启定时器,设置时间为 200ms
- 当 ACK 确认了所有数据/SYN/FIN,关闭定时器
- 触发定时器后
- 重传第一个没有被对方连续确认的数据/SYN/FIN
- 定时器时间翻倍,记录该数据包的重传次数
- 当一个数据包重传 3 次,对方都没有确认,关闭该连接(RST)
### 超时重传实现
- 在 tcp_sock 中维护定时器 `struct tcp_timer retrans_timer`。
- 当开启定时器时,将 retrans_timer 放到 timer_list 中。
- 关闭定时器时,将 retrans_timer 从 timer_list 中移除。
- 定时器扫描,每 10ms 扫描一次定时器队列,重传定时器的值为 200ms * 2^N。
#### `tcp_set_retrans_timer`、`tcp_update_retrans_timer`、tcp_unset_retrans_timer 函数
分别负责定时器的设置、更新以及删除。
#### `tcp_scan_retrans_timer_list` 函数
该函数负责扫描符合条件的定时器,若超时,则判断是否需要重传。
若没有超过重传次数上界(本设计中设计为 5),则调用 `retrans_send_buffer_packet` 函数,重传发送队列 snd_buffer 中第一个数据包。
#### `retrans_send_buffer_packet` 函数
负责重传 send buffer 中第一个数据包。
### 发送队列维护
- 所有未确认的数据/SYN/FIN 包,在收到其对应的 ACK 之前,都要放在发送队列 snd_buffer 中,以备后面可能的重传。
- 发送新的数据时,放到 snd_buffer 队尾,打开定时器。
上述两步在本设计中通过修改 tcp_out.c 中的相关函数实现。
- 收到新的 ACK,将 snd_buffer 中已经确认的数据包移除,并更新定时器。 该步骤通过在 `tcp_process` 函数修改相关状态下的处理流程,从而被调用。
- 重传定时器触发时,重传 snd_buffer 中第一个数据包,定时器数值翻倍。
#### `add_send_buffer_entry`、`alloc_send_buffer_entry` 函数
`alloc_send_buffer_entry` 负责创建一个 buffer 项,并在 `add_send_buffer_entry` 添加到 snd_buffer 队尾。
具体实现如下:
```c
tcp_send_buffer_entry_t * alloc_send_buffer_entry(char *packet, int len) {
tcp_send_buffer_entry_t * entry = (tcp_send_buffer_entry_t *)malloc(sizeof(tcp_send_buffer_entry_t));
bzero(entry, sizeof(tcp_send_buffer_entry_t));
entry->packet = (char *)malloc(len);
memcpy((char*)entry->packet, packet, len);
entry->len = len;
return entry;
}
void add_send_buffer_entry(struct tcp_sock *tsk, char *packet, int len) {
tcp_send_buffer_entry_t * entry = alloc_send_buffer_entry(packet, len);
list_add_tail(&entry->list, &tsk->send_buf);
}
```
其中,`tcp_send_buffer_entry_t` 的数据结构如下:
```c
typedef struct {
struct list_head list;
char * packet;
int len;
} tcp_send_buffer_entry_t;
```
#### `delete_send_buffer_entry` 函数
该函数负责移除已确认的发送数据包,具体实现如下:
```c
void delete_send_buffer_entry(struct tcp_sock *tsk, u32 ack) {
//printf("Delete a send_buffer_entry here.\n");
tcp_send_buffer_entry_t * entry, * entry_q;
list_for_each_entry_safe(entry, entry_q, &tsk->send_buf, list) {
struct tcphdr *tcp = packet_to_tcp_hdr(entry->packet);
u32 seq = ntohl(tcp->seq);
if (less_than_32b(seq, ack)) {
list_delete_entry(&entry->list);
free(entry->packet);
free(entry);
}
}
}
```
### 接收队列维护
- 数据接收方需要维护两个队列
- 已经连续收到的数据,放在 rcv_ring_buffer 中供 app 读取。
- 收到不连续的数据,放到 rcv_ofo_buffer 队列中。
- TCP 属于发送方驱动传输机制
- 接收方只负责在收到数据包时回复相应 ACK。
- 收到不连续的数据包时
- 放在 rcv_ofo_buffer 队列,如果队列中包含了连续数据,则将其移到 rcv_ring_buffer 中。
#### `add_recv_ofo_buf_entry` 函数
该函数负责将收到的不连续数据放到 rcv_ofo_buffer 队列中,具体实现如下:
```c
void add_recv_ofo_buf_entry(struct tcp_sock *tsk, struct tcp_cb *cb) {
rcv_ofo_buf_entry_t * latest_ofo_entry = (rcv_ofo_buf_entry_t *)malloc(sizeof(rcv_ofo_buf_entry_t));
latest_ofo_entry->seq = cb->seq;
latest_ofo_entry->len = cb->pl_len;
latest_ofo_entry->data = (char*)malloc(cb->pl_len);
memcpy(latest_ofo_entry->data, cb->payload, cb->pl_len);
rcv_ofo_buf_entry_t * entry, *entry_q;
list_for_each_entry_safe (entry, entry_q, &tsk->rcv_ofo_buf, list) {
if(less_than_32b(latest_ofo_entry->seq , entry->seq)) {
list_add_tail(&latest_ofo_entry->list, &entry->list);
return;
}
}
list_add_tail(&latest_ofo_entry->list, &tsk->rcv_ofo_buf);
}
```
其中,`rcv_ofo_buf_entry_t` 的数据结构如下:
```c
typedef struct {
struct list_head list;
char * data;
int len;
int seq;
} rcv_ofo_buf_entry_t;
```
#### `put_recv_ofo_buf_entry_to_ring_buf` 函数
该函数负责将已经连续收到的数据,放在 rcv_ring_buffer 中供 app 读取,具体实现如下:
```c
int put_recv_ofo_buf_entry_to_ring_buf(struct tcp_sock *tsk) {
u32 seq = tsk->rcv_nxt;
rcv_ofo_buf_entry_t * entry, * entry_q;
list_for_each_entry_safe(entry, entry_q, &tsk->rcv_ofo_buf, list) {
if (seq == entry->seq) {
while(entry->len > ring_buffer_free(tsk->rcv_buf)) {
sleep_on(tsk->wait_recv);
}
write_ring_buffer(tsk->rcv_buf, entry->data, entry->len);
wake_up(tsk->wait_recv);
seq += entry->len;
tsk->rcv_nxt = seq;
list_delete_entry(&entry->list);
free(entry->data);
free(entry);
} else if (less_than_32b(seq, entry->seq)) {
break;
} else {
return -1;
}
}
return 0;
}
```
## 结果验证
由于实现简单重传机制非常耗时,此实验将传输文本大小缩短到了 500KB,另外为了验证本设计的鲁棒性,丢包率增大到了 10%。
本次实验的结果如下:
![aa0c87a2fd5c052cd4b8d4008a6a9ad7.PNG](https://c
没有合适的资源?快使用搜索试试~ 我知道了~
温馨提示
详情介绍:https://www.yuque.com/sxbn/ks/100010469 实验内容:支持 TCP 可靠数据传输、网络丢包、超时重传机制、有丢包场景下的连接建立和断开、发送队列和接收队列、超时定时器实现。
资源推荐
资源详情
资源评论
收起资源包目录
100010469-基于C语言实现支持 TCP 可靠数据传输实验.zip (50个子文件)
wltcp
lecture
17-网络传输机制实验三.pptx 348KB
~$17-网络传输机制实验三.pptx 165B
assets
result.jpg 391KB
LICENSE 1KB
report
计算机网络实验报告17-网络传输机制实验(三)报告.pdf 934KB
README.md 9KB
code
17-tcp_stack
arpcache.c 5KB
include
icmp.h 1KB
ring_buffer.h 2KB
list.h 2KB
log.h 723B
tcp_timer.h 1KB
tcp.h 3KB
arp.h 1KB
tcp_sock.h 5KB
arpcache.h 2KB
ip.h 3KB
rtable.h 1KB
types.h 156B
checksum.h 407B
hash.h 525B
tcp_apps.h 114B
packet.h 224B
tcp_hash.h 761B
synch_wait.h 2KB
base.h 876B
ether.h 642B
tcp_timer.c 4KB
tcp_apps.c 2KB
icmp.c 2KB
Makefile 473B
arp.c 3KB
create_randfile.sh 75B
rtable_internal.c 4KB
tcp_sock.c 15KB
tcp.c 2KB
tcp_topo_loss.py 2KB
tcp_out.c 3KB
packet.c 1KB
main.c 7KB
tcp_in.c 5KB
tcp_stack.py 1022B
ip.c 3KB
rtable.c 2KB
scripts
disable_ipv6.sh 103B
disable_tcp_rst.sh 67B
disable_ip_forward.sh 84B
disable_offloading.sh 328B
disable_icmp.sh 201B
disable_arp.sh 70B
共 50 条
- 1
资源评论
神仙别闹
- 粉丝: 2674
- 资源: 7640
下载权益
C知道特权
VIP文章
课程特权
开通VIP
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
最新资源
- 基于MIC+NE555光敏电阻的声光控电路Multisim仿真原理图
- python tkinter-08-盒子模型.ev4.rar
- Doozy UI Manager 2023
- 基于matlab实现夜间车牌识别程序(1).rar
- 基于matlab实现无线传感器网络无需测距定位算法matlab源代码 包括apit,dv-hop,amorphous在内的共7个
- 基于python的yolov5实现的旋转目标检测
- 基于matlab实现无线传感器网络 CAB定位仿真程序 这是无线传感器节点定位CAB算法的仿真程序,由matlab完成.rar
- 基于matlab实现图像处理,本程序使用背景差分法对来往车辆进行检测和跟踪.rar
- 基于matlab实现视频监控中车型识别代码,自己写的,希望和大家多多交流.rar
- springcodespringcodespringcodespringcode
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功