滑动窗口协议仿真(2024)

news2024/11/18 11:38:12

1.题目描述

滑动窗口协议以基于分组的数据传输协议为特征,该协议适用于在数据链路层以及传输层中对按 顺序传送分组的可靠性要求较高的环境。在长管道传输过程(特别是无线环境)中,相应的滑动窗口 协议可实现高效的重传恢复。附录 3 给出了一个选择性重传的滑动窗口协议的简单实现,以此为参考, 设计并实现一个滑动窗口协议的仿真,显示数据传送过程中的各项具体数据,双方帧的个数变化,帧 序号,发送和接受速度,重传提示等。


2.程序演示

 这里我们使用Socket来模拟滑动窗口协议,实现了双方帧的个数变化,帧序号,发送和接受速度控制,重传显示。

控制帧发送速度

双方帧的个数变化

丢失包


3.参考代码

接收端代码

#include <winsock2.h>
#include <iostream>
#include <list>
#include <time.h>
#include <unistd.h>
#pragma comment(lib, "ws2_32.lib")
using namespace std;

//函数说明------------------------------
DWORD WINAPI ThreadFun(LPVOID lpThreadParameter);

void init_app();

//---------------------------------------
WSADATA wd;
SOCKET Socket;
sockaddr_in addrClient;
int len = sizeof(sockaddr_in);

//变量------------------------------
struct Data {
    //消息类型定义
    int Type_ACK = 0;
    int Type_Msg = 1;
    int Type_Requst = 2;
    int Type_Retransmission=3;
    //消息内容
    int Msg_Code = 0;//消息序号
    int Msg_Type = 1;//消息类型
    int Msg_ACK=0;//是否已经ACK了
    char *Msg_Content[128];//消息内容
    int Send_WinSize = 4;//发送窗口大小
};


Data Send_Msg_Data;
Data *Get_Msg_Data;
char Get_buf[1024] = {0}, send_buf[1024] = {0};

int main() {
    //提示=======================================================================
    cout << "滑动窗口协议仿真(Socket模拟)_接收方" << endl;
    //初始化=======================================================================
    init_app();
    //==========================================================================
}

DWORD WINAPI ThreadFun(LPVOID lpThreadParameter) {
    // 接受数据
    SOCKET This_Socket = (SOCKET) lpThreadParameter;
    cout << "*连接成功" << endl;
    // 循环接收客户端数据
    int ret = 0;
    do {
        //接收
        ret = recv(This_Socket, Get_buf, sizeof(Get_buf), 0);
        Get_Msg_Data = (Data *) Get_buf;
        cout << "\n收到消息:" << endl;
        cout << "类型:" << Get_Msg_Data->Msg_Type << " 序号: " << Get_Msg_Data->Msg_Code << endl;
        //发送
        if (Get_Msg_Data->Msg_Type==3)
        {
            Send_Msg_Data.Msg_Type =3;
        } else
        {
            Send_Msg_Data.Msg_Type = 0;
        }

        Send_Msg_Data.Msg_Code = Get_Msg_Data->Msg_Code;
        memcpy(send_buf, &Send_Msg_Data, sizeof(Data));
        sleep(1);
        if (send(This_Socket, send_buf, sizeof(send_buf), 0) > 0) {
            cout << "\n回复帧:" << Send_Msg_Data.Msg_Code << " ACK" << endl;
        } else {
            cout << "\n失败回复:" << Send_Msg_Data.Msg_Code << " ACK" << endl;
        }
    } while (ret != SOCKET_ERROR && ret != 0);
    return 0;
}


void init_app() {
    if (WSAStartup(MAKEWORD(2, 2), &wd) != 0) {
        cout << "WSAStartup Error:" << WSAGetLastError() << endl;
        return;
    }
    // 创建流式套接字
    Socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (Socket == INVALID_SOCKET) {
        cout << "socket error:" << WSAGetLastError() << endl;
        return;
    }
    //绑定端口和ip
    sockaddr_in addr;
    memset(&addr, 0, sizeof(sockaddr_in));
    addr.sin_family = AF_INET;
    addr.sin_port = htons(8000);
    addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    //服务端bind绑定
    if (bind(Socket, (SOCKADDR *) &addr, len) == SOCKET_ERROR) {
        cout << "bind Error:" << WSAGetLastError() << endl;
        return;
    }
    // 监听
    listen(Socket, 5);
    //主线程循环接收客户端的连接
    while (true) {
        cout << "*等待连接..." << endl;
        // 接受成功返回与client通讯的Socket
        SOCKET Client = accept(Socket, (SOCKADDR *) &addrClient, &len);
        if (Client != INVALID_SOCKET) {
            // 创建线程,并且传入与client通讯的套接字
            HANDLE hThread = CreateThread(NULL, 0, ThreadFun, (LPVOID) Client, 0, NULL);
            CloseHandle(hThread); // 关闭对线程的引用
        }
    }
}

发送端代码

#include<winsock2.h>//winsock2的头文件
#include<iostream>
#include <list>
#include <ctime>

#pragma comment(lib, "ws2_32.lib")

using namespace std;

//定义========================
void Init_Socket();

void *SendMsg(void *pVoid);

int getRand(int min, int max);

void Sycn();

void Send_Win_Move();

void Retransmission(int Num);

//发送的数据=======================
struct Data {
    //消息类型定义
    int Type_ACK = 0;
    int Type_Msg = 1;
    int Type_Requst = 2;
    int Type_Retransmission = 3;
    //消息内容
    int Msg_Code = 0;//消息序号
    int Msg_Type = 1;//消息类型
    int Msg_ACK = 0;//是否已经ACK了
    char *Msg_Content[128];//消息内容
    int Send_WinSize = 4;//发送窗口大小
};

//默认参数=======================
int Rand_Num = 5;//随机概率1/5
int Receiver_WinSize = 10;
int Send_WinSize = 5;
int Send_Size = 10;
int ACK_OutTime = 10;
int Send_Num = 100;
char *Send_Msg = "0123456789";
SOCKET Socket;
int Win_Now_Size = 0;


//消息列表=======================
list<Data> MSG_Win_List;
Data Send_Msg_Data;
Data *Get_Msg_Data;
Data *Temp_Msg_Data;
int Num = 0;
char send_buf[1024] = {0}, Get_buf[1024] = {0};

void init_data() {
    char auto_data;
    //提示=======================================================================
    cout << "*====滑动窗口协议仿真(Socket模拟)_发送方====*\n";
    cout << "\n-------------------------------\n";
    cout << " 请输入必要参数(y/n):";
    cin >> auto_data;
    if (auto_data == 'n') {
        cout << " 发送窗口: ", cout << Send_WinSize << endl;
        cout << " 消息帧数: ", cout << Send_Num << endl;
//        cout << " 发送内容: ", cout << Send_Msg << endl;
    } else {
        cout << " 发送窗口: ", cin >> Send_WinSize;
        cout << " 消息帧数: ", cin >> Send_Num;
    }
    cout << "-------------------------------" << endl;
    system("pause");

}

int main() {
    init_data();
    Init_Socket();
    //接收服务端的消息
    pthread_t tids;
    pthread_create(&tids, NULL, SendMsg, &Socket);
    //随时给服务端发消息
    do {
        int ret = 0;
        do {
            ret = recv(Socket, Get_buf, sizeof(Get_buf), 0);
            Get_Msg_Data = (Data *) Get_buf;
            if (ret != SOCKET_ERROR && ret != 0) {
                cout << "\n\n\t==>收到帧:" << " ACK: " << Get_Msg_Data->Msg_Code << endl;
                list<Data>::iterator iter;
                for (iter = MSG_Win_List.begin(); iter != MSG_Win_List.end(); iter++) {
                    if (Get_Msg_Data->Msg_Code == iter->Msg_Code) {
                        (*iter).Msg_ACK = 1;

                        if (Get_Msg_Data->Msg_Type == 3) {
                            cout << "\n\t重传删除了一个" << endl;
                            Win_Now_Size--;
                            MSG_Win_List.erase(iter);
                        }
                        break;
                    }
                }
                Sycn();
            }
        } while (ret != SOCKET_ERROR && ret != 0);
    } while (true);
    //关闭监听套接字
    closesocket(Socket);
    WSACleanup();

}

void Init_Socket() {
    WSADATA wd;
    //加载winsock2的环境
    if (WSAStartup(MAKEWORD(2, 2), &wd) != 0) {
        cout << "WSAStartup  error:" << GetLastError() << endl;
        return;
    }
    //创建流式套接字
    Socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (Socket == INVALID_SOCKET) {
        cout << "socket  error:" << GetLastError() << endl;
        return;
    }
    //连接服务器
    sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(8000);
    addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    int len = sizeof(sockaddr_in);
    if (connect(Socket, (SOCKADDR *) &addr, len) == SOCKET_ERROR) {
        cout << "connect  error:" << GetLastError() << endl;
        return;
    }
}

void *SendMsg(void *pVoid) {
    do {
        Send_Win_Move();
        Sycn();
        system("pause");
        Send_Msg_Data.Msg_Code = Num;
        Send_Msg_Data.Msg_Type = 1;
        memcpy(send_buf, &Send_Msg_Data, sizeof(Data));
        if (Win_Now_Size == Send_WinSize) {
            list<Data>::iterator iter;
            for (iter = MSG_Win_List.begin(); iter != MSG_Win_List.end(); iter++) {
                if (iter->Msg_ACK == 0) {
                    Send_Msg_Data.Msg_Code = iter->Msg_Code;
                    Send_Msg_Data.Msg_Type = 3;
                    memcpy(send_buf, &Send_Msg_Data, sizeof(Data));
                    if (send(Socket, send_buf, sizeof(send_buf), 0) > 0) {
                        cout << "\n\t<==发送重传帧:" << iter->Msg_Code << endl;
                    } else {
                        cout << "\n\t<==失败发送重传帧:" << iter->Msg_Code << endl;
                    }

                    break;
                }
            }
            continue;
        }
        if (getRand(1, Rand_Num) == Rand_Num)//随机丢失
        {
            cout << "\n\t<=xxxx=随机丢失帧:" << Num++ << endl;
        } else {
            if (send(Socket, send_buf, sizeof(send_buf), 0) > 0) {
                cout << "\n\t<==发送帧:" << Num++ << endl;
            } else {
                cout << "\n\t<<==失败发送帧:" << Num++ << endl;
            }
        }
        Win_Now_Size++;
        Send_Num--;
        MSG_Win_List.push_back(Send_Msg_Data);
    } while (Send_Num > 0);
}

void Send_Win_Move() {

    if (MSG_Win_List.begin()->Msg_ACK == 0) return;
    list<Data>::iterator iter=MSG_Win_List.begin();
    while (iter->Msg_ACK==1)
    {
        MSG_Win_List.erase(iter);
        Win_Now_Size--;
        iter=MSG_Win_List.begin();
    }
    cout << "\n\t窗口移动了" << endl;
}

int getRand(int min, int max) {
    return (rand() % (max - min + 1)) + min;
}

void Sycn() {

    cout << "\n\t------------------------------" << endl;
    cout << "\t当前发送窗口:" << Send_WinSize << "\t可用窗口大小:" << Send_WinSize - Win_Now_Size << endl;
    list<Data>::iterator iter;
    for (iter = MSG_Win_List.begin(); iter != MSG_Win_List.end(); iter++) {
        cout << "\t#帧序号:" << iter->Msg_Code << "\t#是否ACK:" << iter->Msg_ACK << endl;
    }
    cout << "\t------------------------------" << endl;
}

 4.导入ws2_32库到Clion :

导入ws2_32库到Clion项目-CSDN博客

 

 2024 HNUST计算机网络课程设计-(ᕑᗢᓫ∗)˒芒果酱-参考文章

(代码可以参考,૮₍ ˃ ⤙ ˂ ₎ა 但同学们要认真编写哦)
-------------------------------------------------------------------------
1、网络聊天程序的设计与实现
C++ Socket 多线程 网络聊天室 支持用户端双向交流(2023)-CSDN博客
2、Tracert 与 Ping 程序设计与实现
Tracert 与 Ping 程序设计与实现(2024)-CSDN博客
3、滑动窗口协议仿真
滑动窗口协议仿真(2024)-CSDN博客
4、OSPF 路由协议原型系统设计与实现
OSPF 路由协议原型系统设计与实现-CSDN博客
5、基于 IP 多播的网络会议程序
基于 IP 多播的网络会议程序(2024)-CSDN博客
6、编程模拟 NAT 网络地址转换
编程模拟 NAT 网络地址转换(2024)-CSDN博客
7、网络嗅探器的设计与实现
网络嗅探器的设计与实现(2024)-转载-CSDN博客
8、网络报文分析程序的设计与实现
网络报文分析程序的设计与实现(2024)-CSDN博客
9、简单 Web Server 程序的设计与实现
简单 Web Server 程序的设计与实现 (2024)-CSDN博客
10、路由器查表过程模拟

计算机网络 - 路由器查表过程模拟 C++(2024)-CSDN博客

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1363082.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Guava Cache 异步刷新技巧

前言 Guava Cache是一款非常优秀的本地缓存框架&#xff0c;提供简洁易用的 API 供开发者使用。 这篇文章&#xff0c;我们聊聊如何使用 Guava Cache 异步刷新技巧带飞系统性能 。 1 基本用法 首先&#xff0c;在 Java 应用中添加 maven 依赖&#xff1a; <dependency&g…

jsES6+新语法

目录 模板字符串标签模板字符串 函数增强默认值与解构剩余参数rest和arguments 箭头函数 展开语法SymbolSetSet方法weakSetweakSet常用方法 MapMap常用方法weakMapweakMap常用方法 PromiseProxy/Reflect迭代器与生成器ES6新增方法includes**Object.valuesObject.entriespadStar…

【SpringBoot】公共字段自动填充功能实现(枚举、自定义注解、AOP、反射)

1. 自定义注解 使用interface语法来定义注解&#xff08;Annotation&#xff09;。 注解的参数类似无参数方法&#xff0c;可以用default设定一个默认值&#xff0c;比如String value() default "";。 元注解&#xff1a;有一些注解可以修饰其他注解&#xff0c;这…

Diffusion扩散模型学习2:DDPM前向加噪过程torch实现

参考: https://arxiv.org/pdf/2006.11239.pdf ##论文 https://github.com/dtransposed/code_videos/blob/main/01_Diffusion_Models_Tutorial/Diffusion%20Model.ipynb ##code https://spaces.ac.cn/archives/9119 1、红色框: 前向过程论文公式推出可以从x0原图一步到最终噪声…

学习Redis缓存

学习Redis缓存 NoSQL和SQL的区别缓存缓存作用缓存成本添加Redis缓存 Redis特征Redis中数据结构Redis通用命令String类型Key的层级格式Hash类型Redis的Java客户端 NoSQL和SQL的区别 缓存 缓存就是数据交换的缓冲区&#xff0c;是存储数据的临时地方&#xff0c;一般读写性比较高…

数据分析——火车信息

任务目标 任务 1、整理火车发车信息数据&#xff0c;结果的表格形式为&#xff1a; 2、并输出最终的发车信息表 难点 1、多文件 一个文件夹&#xff0c;多个月的发车信息&#xff0c;一个excel&#xff0c;放一天的发车情况 2、数据表的格式特殊 如何分析表是一个难点 数…

洛谷 P1019 单词接龙

题目背景 注意&#xff1a;本题为上古 NOIP 原题&#xff0c;不保证存在靠谱的做法能通过该数据范围下的所有数据。 NOIP2000 提高组 T3 题目描述 单词接龙是一个与我们经常玩的成语接龙相类似的游戏&#xff0c;现在我们已知一组单词&#xff0c;且给定一个开头的字母&…

mysql视图和sql语句

mysql视图和sql语句 一.mysql视图1.数据的虚拟表示&#xff1a;2.简化复杂查询&#xff1a;3.安全性和权限控制&#xff1a;4.逻辑数据组织&#xff1a;5.更新限制&#xff1a;6.视图的创建&#xff1a; 二.mysq语句使用案列 MySQL的视图&#xff08;View&#xff09;是一个虚拟…

深入剖析pcap中的网络异常:TTL过期攻击、ARP中毒、TCP重传与重叠碎片等

网络流量数据包捕获是网络安全领域的重要部分&#xff0c;而pcap文件则是这一过程的常见载体。为了深入解析pcap文件中潜在的可疑网络流量&#xff0c;我们需要运用强大的网络安全威胁评估与审计工具。这些工具能够帮助我们捕捉、记录、检测和诊断网络中的数据传输问题&#xf…

c#调试程序一次启动两个工程(多个工程)

概述 c# - Visual Studio : debug multiple projects at the same time? 以在解决方案中设置多个启动项目(右键单击解决方案&#xff0c;转到设置启动项目&#xff0c;选择多个启动项目)&#xff0c;并为包含在解决方案(无、开始、不调试就开始)。如果您将多个项目设置为开始…

LeetCode 42:接雨水

一、题目描述 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图&#xff0c;计算按此排列的柱子&#xff0c;下雨之后能接多少雨水。 示例 1&#xff1a; 输入&#xff1a;height [0,1,0,2,1,0,1,3,2,1,2,1] 输出&#xff1a;6 解释&#xff1a;上面是由数组 [0,1,0,2,1,0,…

并发(3)

目录 11.Synchronized本质上是通过什么保证线程安全的&#xff1f; 12.Synchronized使得同时只有一个线程可以执行&#xff0c;性能比较差&#xff0c;有什么提升的方法&#xff1f; 13.Synchronized由什么样的缺陷&#xff1f;Java Lock是怎么弥补这些缺陷的&#xff1f; 1…

物联网协议Coap中Californium CoapClient解析

目录 前言 一、CoapClient对象 1、类定义 2、Client方法调用 二、发送请求 1、构建请求 2、发起请求 3、接收响应 总结 前言 在之前的博客中物联网协议Coap之Californium CoapServer解析&#xff0c;文中简单介绍了CoapServer的实现。在物联网开发环境中&#xff0c;除了…

跨平台开发教学:构建同时支持iOS和Android的教育网校APP

当下&#xff0c;教育行业也逐渐迎来了数字化转型的时代。构建一款支持iOS和Android的教育网校APP&#xff0c;不仅可以提供更好的用户体验&#xff0c;还能扩大应用的覆盖面&#xff0c;满足不同用户群体的需求。 一、选择合适的跨平台开发框架 在开始构建教育网校APP之前&a…

PPT插件-大珩助手-免费功能-特殊格式介绍

上、下标切换 直接切换选中的字符为上、下标。 大小金额 支持超大金额的大写金额转换 当前日期 本次打开文件的时间 转二维码 将当前选中的文字&#xff0c;转为二维码图片&#xff0c;并插入到PPT当前位置 特殊字符 内置常用的特殊字符&#xff0c;点击使用 软件介绍 …

ssm基于vue.js的购物商场的设计与实现论文

摘 要 传统办法管理信息首先需要花费的时间比较多&#xff0c;其次数据出错率比较高&#xff0c;而且对错误的数据进行更改也比较困难&#xff0c;最后&#xff0c;检索数据费事费力。因此&#xff0c;在计算机上安装购物商场软件来发挥其高效地信息处理的作用&#xff0c;可以…

SpringBoot配置Swagger2与Swagger3

swagger是什么&#xff1f; 在平时开发中&#xff0c;一个好的API文档可以减少大量的沟通成本&#xff0c;还可以帮助新加入项目的同事快速上手业务。大家都知道平时开发时&#xff0c;接口变化总是很多&#xff0c;有了变化就要去维护&#xff0c;也是一件比较头大的事情。尤…

开源加解密库之GmSSL

一、简介 GmSSL是由北京大学自主开发的国产商用密码开源库&#xff0c;实现了对国密算法、标准和安全通信协议的全面功能覆盖&#xff0c;支持包括移动端在内的主流操作系统和处理器&#xff0c;支持密码钥匙、密码卡等典型国产密码硬件&#xff0c;提供功能丰富的命令行工具及…

java数据结构与算法刷题-----LeetCode64. 最小路径和

java数据结构与算法刷题目录&#xff08;剑指Offer、LeetCode、ACM&#xff09;-----主目录-----持续更新(进不去说明我没写完)&#xff1a;https://blog.csdn.net/grd_java/article/details/123063846 很多人觉得动态规划很难&#xff0c;但它就是固定套路而已。其实动态规划只…

基于Python新闻推荐系统 大数据毕业设计 爬虫+可视化+推荐算法 vue框架+Django框架(附源码)✅

毕业设计&#xff1a;2023-2024年计算机专业毕业设计选题汇总&#xff08;建议收藏&#xff09; 毕业设计&#xff1a;2023-2024年最新最全计算机专业毕设选题推荐汇总 &#x1f345;感兴趣的可以先收藏起来&#xff0c;点赞、关注不迷路&#xff0c;大家在毕设选题&#xff…