> # ♻️ 资源
> **大小:** 1.43MB
> **文档链接:**[**https://www.yuque.com/sxbn/ks/100010205**](https://www.yuque.com/sxbn/ks/100010205)
> **➡️ 资源下载:**[**https://download.csdn.net/download/s1t16/87347702**](https://download.csdn.net/download/s1t16/87347702)
> **注:更多内容可关注微信公众号【神仙别闹】,如当前文章或代码侵犯了您的权益,请私信作者删除!**
> ![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的可靠传输
## 实验综述
本实验基于 Java 6 平台,实现 TCP 协议端到端的可靠传输数据包传送和确认,及对各种传输错误的处理。
实验框架如下:
![e3ef010734cd08c5f632c61e8484b4f4.PNG](https://cdn.nlark.com/yuque/0/2024/png/2469055/1705542696513-e831402a-e918-46fd-8c10-d7e1f49b1324.png#averageHue=%233f949b&clientId=u32f19206-b953-4&from=paste&height=573&id=u2bba2de7&originHeight=716&originWidth=1059&originalType=binary&ratio=1.25&rotation=0&showTitle=false&size=183561&status=done&style=none&taskId=u6079d42f-e5d1-43fd-bdc5-05d9169c45b&title=&width=847.2)
实验流程:RDT1.0(在可靠信道上进行可靠的数据传输) -> RDT2.0(信道上可能出现位错) -> RDT2.1(管理出错的 ACK/NACK) -> RDT2.2(仅使用 ACK) -> RDT3.0(信道上可能出错和丢失数据) -> RDT4.0(流水线协议) -> RDT5.0(拥塞控制)
我实现的 RDT4.0 为 Go-Back-N 协议,RDT5.0 实现至 Reno 版本
## TCP: Go-Back-N
### 原理
在 RDT3.0 版本下,仍使用停止等待协议,即必须要收到一个包的 ACK 才会去发下一个包,不然就阻塞应用层的调用。在实际环境下,这非常影响效率,每一次任何包的任何错误如丢包,位错都会导致计时器超时重发,使得信道利用率很低,大部分时间都在等待计时器超时。这时我们引入流水线协议:发送端允许发送出多个包,他们"悬在空中",等待应答。这带来一个最大的问题:现在无论是发送方,还是收包方,包到达的时间不再是按顺序的。 Go-Back-N 提出了一种方式:
- 发送者在流水线队列维持 N 个没有确认的发送包,用计时器跟踪最久未确认的发送包,计时器到时,重传所有未确认的包。
- 接收方仅发送累积确认,即发送的确认号为当前按序包的最大号,对失序的包不确认(可以选择缓存也可以直接丢弃,这里我实现的是丢弃)。
实现这种方式需要用到窗口
![aaaa9472542de40d2a781c097982bacf.PNG](https://cdn.nlark.com/yuque/0/2024/png/2469055/1705542751977-7fa35d94-880a-46a9-92e0-a8d7f0790beb.png#averageHue=%23edecec&clientId=u32f19206-b953-4&from=paste&height=240&id=ucdfb77be&originHeight=300&originWidth=1491&originalType=binary&ratio=1.25&rotation=0&showTitle=false&size=18117&status=done&style=none&taskId=u99a97262-5e6d-4ea8-9b7a-621e260ac8f&title=&width=1192.8)
- send_base: 窗口内第一个没有被 ACK 的包,也是窗口左沿
- nextseqnum: 下一个可以发送的包
- window size: 窗口大小
对于发送方:
- 当收到一个 ACK 包时,send_base 加 1,窗口向右滑动 1 位。
- 当要发送一个新的包时,先判断 nextseqnum 在不在窗口内,是就发新包然后 nextseqnum 加 1。反之阻塞不允许发送等待收到 ACK
- 维护一个计时器,当发生超时时将窗口内的包全部重发。
对于接受方:
- 维护一个期待收到的包的序号,为当前收到包的按序最大号的下一个。
- 收到一个不是期待的序号的包,丢弃。是期待的序号就发一个 ACK 包回去,自身期待的包的序号加一。
### 状态转移图
- 发送方
![f7fc0358a4e87989f5873e1800d0b4fe.PNG](https://cdn.nlark.com/yuque/0/2024/png/2469055/1705542805357-11059875-cc03-4227-bc96-602f21ed0932.png#averageHue=%23ebeef2&clientId=u32f19206-b953-4&from=paste&height=323&id=udae2e7dd&originHeight=404&originWidth=1043&originalType=binary&ratio=1.25&rotation=0&showTitle=false&size=116348&status=done&style=none&taskId=uc2e10563-078b-42bd-ad63-0ad174aedc4&title=&width=834.4)
- 接收方
![fc3a0d8e9d75d9b214c1eec727b8315f.PNG](https://cdn.nlark.com/yuque/0/2024/png/2469055/1705542817422-f4b5c7fa-2f0e-4783-91be-ee0857662381.png#averageHue=%23edeff3&clientId=u32f19206-b953-4&from=paste&height=629&id=u1b1bee24&originHeight=786&originWidth=950&originalType=binary&ratio=1.25&rotation=0&showTitle=false&size=200983&status=done&style=none&taskId=uf74af106-b609-4bd2-8bb5-7d309de0f28&title=&width=760)
### 代码实现
**实验框架基于 Java 包 TCP_Win_TestSys.jar**
#### 校验
- 使用 CRC 校验
```java
public class CheckSum {
// 计算 TCP 校验核
public static short computeChkSum(TCP_PACKET tcpPack) {
int checkSum = 0;
TCP_HEADER h = tcpPack.getTcpH();
CRC32 crc = new CRC32();
crc.reset();
crc.update(tcpPack.getSourceAddr().getAddress());
crc.update(tcpPack.getDestinAddr().getAddress());
crc.update(0);
crc.update(6);
crc.update(h.getTh_Length());
crc.update(h.getTh_sport());
crc.update(h.getTh_dport());
crc.update(h.getTh_seq());
crc.update(h.getTh_ack());
crc.update(h.getTh_doff());
crc.update(h.getTh_win());
crc.update(h.getTh_urp());
crc.update(h.getTh_mss());
for (int i = 0; i < tcpPack.getTcpS().getData().length; i++) {
crc.update(tcpPack.getTcpS().getData()[i]);
}
checkSum = (int)crc.getValue();
return (short) checkSum;
}
```
#### 发送方
```java
package com.ouc.tcp.test;
import com.ouc.tcp.client.TCP_Sender_ADT;
import com.ouc.tcp.client.UDT_Timer;
import com.ouc.tcp.message.*;
import java.util.concurrent.LinkedBlockingQueue;
enum FlagType {
Stable, //信道无差错
ErrorOnly, //只出错
LossOnly, //只丢包
DelayOnly, //只延迟
ErrorWithLoss, //出错 / 丢包
ErrorWithDelay, //出错 / 延迟
LossWithDelay, //丢包 / 延迟
RealEnv, //实际环境=出错 / 丢包 / 延迟
}
public class TCP_Sender extends TCP_Sender_ADT {
private TCP_PACKET tcpPack; //待发送的TCP数据报
private volatile int flag = 0;
private TCP_PACKET rcvPack; // 已经收到的recv_pkt
private UDT_Timer timer;
private LinkedBlockingQueue<TCP_PACKET> packets;
private short windows = 16;
private int send_base = 1;
private int next_seq = 1;
private TaskPacketsRetransmit task;
public TCP_Sender() {
super();
super.initTCP_Sender(this);
timer = new UDT_Timer();
packets = new LinkedBlockingQueue<TCP_PACKET>();
}
@Override
public void rdt_send(int dataIndex, int[] appData) {
while (next_seq >= send_base + windows){
}
tcpH.setTh_seq(next_seq);
tcpS.setData(appData);
tcpPack = new TCP_PACKET(tcpH, tcpS, destinAddr);
tcpH.setTh_sum(CheckSum.computeChkSum(tcpPack));
tcpPack.setTcpH(tcpH);
udt_send(tcpPack);
try {
if(this.append(tcpPack)){
}
else {
System.out.println("queue is full, this shouldn't has appeared!");
}
} catch (CloneNotSupportedException ignored) {
}
if (send_base == next_seq){
task = new TaskPacketsRetransmit(client, packets);
timer.schedule(task, 3000, 3000);
}
next_seq += 1;
}
@Override
public void udt_send(TCP_PACKET stcpPack) {
tcpH.setTh_eflag((byte) FlagType.RealEnv.ordinal());
client.send(stcpPack);
}
@Override
public void waitACK() {
int ack = this.rcvPack.getTcpH().getTh_ack();
if (ack >= send_base){
int d = (ack + 1) - send_base;
send_base = ack + 1;
this.slide(d);
if (send_base == next_seq){
task.cancel();
}
else {
task.cancel();
task = new TaskPacketsRetransmit(client, packets);
timer.schedule(
基于Java实现 TCP 协议端到端的可靠传输数据包传送和确认【100010205】
版权申诉
81 浏览量
2022-12-26
15:30:04
上传
评论
收藏 1.44MB ZIP 举报
神仙别闹
- 粉丝: 2674
- 资源: 7640
最新资源
- sony 索尼IMX334摄像头模组电路板AD版硬件PCB图(6层板).zip
- 基于flask和echarts融合交易策略的bitfinex可视化微服务.zip
- 包含了wvp-assist.tar wvp-talk.tar zlmediakit.tar .
- 3r4efgh53wgrf43tw
- 2024新版Java基础从入门到精通全套视频+资料下载
- Spring AI大模型视频教程+ChatGPT视频教程+OpenAI大模型视频教程(资料+视频教程)
- ABB工业机器人教程PDF版本
- 123321123323211
- yolov8实战第八天-pyqt5-yolov8实现车牌识别系统(论文(8700+字+数据集+完整部署代码+代码使用说明)
- 三相桥式全桥整流电路MATALB Simulink仿真文件
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈