滑动窗口协议仿真(2024)

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博客

 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

[Redis实战]分布式锁

四、分布式锁 4.1 基本原理和实现方式对比 分布式锁&#xff1a;满足分布式系统或集群模式下多进程可见并且互斥的锁。 分布式锁的核心思想就是让大家都使用同一把锁&#xff0c;只要大家使用的是同一把锁&#xff0c;那么我们就能锁住线程&#xff0c;不让线程进行&#xf…

浏览器的渲染流程

✨专栏介绍 在当今数字化时代&#xff0c;Web应用程序已经成为了人们生活和工作中不可或缺的一部分。而要构建出令人印象深刻且功能强大的Web应用程序&#xff0c;就需要掌握一系列前端技术。前端技术涵盖了HTML、CSS和JavaScript等核心技术&#xff0c;以及各种框架、库和工具…

基于SpringBoot的MusiQ音乐网站

目录 前言 开发环境以及工具 项目功能 用户&#xff1a; 后台&#xff1a; 设计详情​编辑 登陆页面 后台管理页面 首页 视频展示 源码获取 前言 本项目是一个基于IDEA和Java语言开基于SpringBoot的MusiQ音乐网站。应用包含管理端&#xff0c;教师端&#xff0c;学生…

Spring见解 5 Spring整合MyBatis

6.Spring整合MyBatis 6.1.创建工程 6.1.1.pom.xml <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation…

YOLOv5改进 | 损失篇 | VarifocalLoss密集检测专用损失函数 (VFLoss,论文一比一复现)

一、本文介绍 本文给大家带来的是损失函数改进VFLoss损失函数,VFL是一种为密集目标检测器训练预测IoU-aware Classification Scores(IACS)的损失函数,我经过官方的版本将其集成在我们的YOLOv8的损失函数使用上,其中有很多使用的小细节(否则按照官方的版本使用根本拟合不了…

SpringBoot学习(六)-SpringBoot整合Shiro

12、Shiro 12.1概述 12.1.1简介 Apache Shiro是一个强大且易用的Java安全框架 可以完成身份验证、授权、密码和会话管理 Shiro 不仅可以用在 JavaSE 环境中&#xff0c;也可以用在 JavaEE 环境中 官网&#xff1a; http://shiro.apache.org/ 12.1.2 功能 Authentication…

开源加解密库之GmSSL

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

精选顶级期刊中的三幅可复现图表

简介 最近在阅读文献时&#xff0c;发现了一些出色的可视化案例&#xff0c;特此与大家分享。这些图共同的特点是&#xff1a;1. 易懂明晰&#xff1b; 2. 信息丰富&#xff1b; 3. 配色优雅。 小编有话说&#xff1a;以下三幅图选自领域内顶级期刊&#xff0c;虽然并非采用R语…

K8S集群部署解决工作节点couldn‘t get current server API group list问题

最近在自己电脑上装了VMWare Player&#xff0c;在上面装了两个Ubuntu虚拟机&#xff0c;为了方便学习云原生技术&#xff0c;决定在上面装一个2个节点&#xff08;一个控制面&#xff0c;一个工作节点&#xff09;的K8S集群。 参考这篇文章&#xff1a; Ubuntu 22.04 搭建K8…

基于java,springboot的论旅游管理系统设计与实现

环境以及简介 基于java,springboot的论旅游管理系统设计与实现&#xff0c;Java项目&#xff0c;SpringBoot项目&#xff0c;含开发文档&#xff0c;源码&#xff0c;数据库以及ppt 源码下载 环境配置&#xff1a; 框架&#xff1a;springboot JDK版本&#xff1a;JDK1.8 服…

Mac 升级ruby 升级brew update

Mac 自身版本是2.x 查看ruby版本号 打开终端 ruby -v 1.brew update 如果报错 这时候brew更新出问题了 fatal: the remote end hung up unexpectedly fatal: early EOF fatal: index-pack failed error: RPC failed; curl 18 HTTP/2 stream 3 was reset fatal: th…

Guava:Cache强大的本地缓存框架

Guava Cache是一款非常优秀的本地缓存框架。 一、 经典配置 Guava Cache 的数据结构跟 JDK1.7 的 ConcurrentHashMap 类似&#xff0c;提供了基于时间、容量、引用三种回收策略&#xff0c;以及自动加载、访问统计等功能。 基本的配置 Testpublic void testLoadingCache() th…

java碳排放数据信息管理系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 java Web碳排放数据信息管理系统是一套完善的java web信息管理系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环 境为TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库为…

群晖NAS+DMS7.0以上版本+无docker机型安装zerotier

测试机型&#xff1a;群晖synology 218play / DSM版本为7.2.1 因218play无法安装docker&#xff0c;且NAS系统已升级为7.0以上版本&#xff0c;按zerotier官网说法无法安装zerotier, 不过还是可以通过ssh终端和命令方式安装zerotier。 1、在DSM新建文件夹 用于存放zerotier脚…

while猜数字实例——C++版

案例描述&#xff1a;系统随机生成一个1到100之间的数字&#xff0c;玩家进行猜测&#xff0c;如果猜错&#xff0c;提示玩家数字过大或过小&#xff0c;如果猜对恭喜玩家胜利并退出游戏。 逻辑框图&#xff1a; #include<bits/stdc.h> using namespace std; int main()…

使用Enterprise Architect绘制架构图

如何使用Enterprise Architect绘制架构图 之前没有使用过Enterprise Architect软件绘制&#xff0c;目前由于工作需求&#xff0c;需要使用Enterprise Architect绘制一些架构图&#xff0c;现在只使用Enterprise Architect绘制过简单的Flow Chart&#xff0c;想请教一下大神们…

【Qt- C++ Qml 交互】

Qt编程指南 VX&#xff1a;hao541022348 ■ 将C对象注册到 QML中&#xff0c;在QML使用C对象&#xff08;Q_INVOKABLE宏&#xff09;■ C对象注册到元对象系统■ Q_INVOKABLE 宏■ 演示步骤 ■ 将C对象注册到 QML中&#xff0c;在QML使用C对象&#xff08;Q_PROPERTY宏 属性绑定…

python 写自动点击爬取数据

今天来点不一样的&#xff01;哥们 提示&#xff1a; 这里只是用于自己学习的 &#xff0c;请勿用违法地方 效果图 会进行点击下一页 进行抓取 需要其他操作也可以自己写 文章目录 今天来点不一样的&#xff01;哥们前言一、上代码&#xff1f;总结 前言 爬虫是指通过编程自动…

软件安全开发

开发背景 软件工程方法&#xff1a; 方法&#xff1a;抽象化、建模、设计、算法、协议 过程&#xff1a;过程的质量、进度、成本、配置 工具&#xff1a;程序设计语言、编译、配置工具 开发模型 瀑布模型 迭代模型 增量模型 原型 螺旋模型 净室模型---范围小&#xf…

Adobe illustrator各版本安装指南

下载链接 https://pan.baidu.com/s/11sTpMUbQEXhyjpkBlixcLg?pwd0531 #2024版 1.鼠标右击【Ai2024(64bit)】压缩包&#xff08;win11及以上系统需先点击“显示更多选项”&#xff09;【解压到 Ai2024(64bit)】。 2.打开解压后的文件夹&#xff0c;鼠标右击【Setup】选择【以…