La programación de sockets basada en c++ simula el proceso GBN y SR

Objetivo:

Cree dos procesos, un proceso simula al usuario y el otro simula al servidor, el usuario puede enviar archivos al servidor a través de GBN y SR, y el servidor también puede enviar archivos al usuario.

principio:

GBN significa retroceder N pasos. Cuando se produce una pérdida de paquetes y se agota el tiempo de espera, el remitente retransmite directamente todo el contenido dentro de la ventana deslizante. ACK adopta el modo de confirmación acumulativa, es decir, cuando un acuse de recibo con el número de secuencia N llega al remitente, el remitente puede Considérelo convenientemente: El receptor ha recibido todos los paquetes con números de secuencia inferiores a N.

SR es una retransmisión selectiva. El receptor puede almacenar en caché una cierta cantidad de paquetes desordenados y responder al remitente con el reconocimiento correspondiente. Cuando llega el primer paquete de datos no confirmado, el receptor puede recibir varios paquetes en secuencia hasta que encuentre un paquete no confirmado. paquete agrupación. Faltan palabras y las palabras no transmiten el significado. La explicación de GBN y SR no está clara, así que compréndala usted mismo.

Ideas de implementación:

GBN:

Primero mire al remitente. Originalmente quería usar una matriz de longitud fija como caché, pero el tamaño de la ventana no es seguro y el código para implementar el deslizamiento es más complicado, así que después de pensarlo, usé una cola. El remitente lee el archivo a transmitir, lo agrupa primero y almacena los paquetes en secuencia en la cola q1 (utilizada para almacenar los paquetes a enviar). Al enviar, los paquetes enviados ingresan a la cola q2 (el usuario almacena los paquetes enviados pero no confirmados). ), y recibe el reconocimiento del receptor al mismo tiempo. Si el número de secuencia del reconocimiento es mayor que el número de secuencia del grupo principal de q2, el jefe del equipo será retirado de la cola y se repetirá el proceso de comparación anterior. hasta que el número de secuencia del jefe del equipo sea menor o igual al número de secuencia del acuse de recibo (el número de secuencia del acuse de recibo es el número de secuencia que se espera recibir y no ha sido confirmado).

En segundo lugar, mire el receptor: la lógica del receptor es relativamente simple, por lo que el receptor de GBN solo necesita mantener un búfer de recepción de tamaño uno, y los paquetes que llegan fuera de orden pueden descartarse directamente. Al recibir un paquete, el receptor compara su número de secuencia con el número de secuencia que espera recibir, si son iguales, el paquete pasa a la aplicación superior (esto es solo una simulación, solo lo escribo en un archivo), y el número de secuencia que espera recibir se incrementa en 1. Enviar acuse de recibo, esperar, no importa, descartar el paquete.

SR:

Todavía mira primero al remitente, lo cual es similar a GBN, excepto que cada paquete dentro de la ventana deslizante tiene un temporizador independiente para la retransmisión cuando se agota el tiempo de espera. Para ser vago, solo utilicé un temporizador, que es el del primer paquete enviado sin confirmar. Ahora que lo pienso, en realidad no coincide con mi método de cola, porque si la cola no muestra elementos, solo puedo acceder al principio y al final de la cola, pero no puedo acceder a los temporizadores de otros grupos. También encontré el mismo problema en el lado receptor. Por ejemplo, llegan paquetes con números de secuencia 1, 3 y 4. Si dibujamos un diagrama del búfer de recepción del receptor en este momento, lo más probable es que dejemos un espacio entre 1 y 3. Sin embargo, a nivel de código no podemos. Es tan simple como una demostración en papel: primero, si usamos una matriz como búfer de recepción, ¿cómo determinamos el índice de matriz del grupo? Y cómo identificar si el paquete ha sido recibido o no. La única diferencia entre ellos que deben almacenarse en el caché es el número de secuencia. Dado que mi dominio del chino no ha mejorado desde que me gradué de la escuela secundaria, realmente no puedo expresar el problema con claridad. Puede encontrarlo simulando el proceso de almacenamiento de cada grupo en la matriz de caché en papel.

Código:

Tenga en cuenta que aquí nombré el archivo que se transferirá en el lado del cliente como test.txt y en el lado del servidor como data.txt. Estos archivos deben crearse en la carpeta actual con anticipación; de lo contrario, se producirá un error al abrir el archivo.

El entorno de ejecución es vs2022 y se han descargado extensiones relacionadas con C++.

Cliente:

#include <stdio.h>
#include "stdlib.h"
#include <tchar.h>
#include <Windows.h>
#include <process.h>
#include <string.h>
#include<mutex>									
#include <iostream>
#include <fstream>
#include <string>
#include<queue>
#include<map>
#pragma comment(lib,"Ws2_32.lib")
#define windowSize 5//最大窗口大小
#define clientPort 666//客户端的端口为666
#define serverPort 888//服务器端口为888
#define maxDataSize 1048//最大分组长度
#define TimerCount 2//倒计时的时间
#define orderCount 12//序号的大小
#define sendLossRate 0.3//模拟发送丢包率
#define canRepeat 2//可以重传的次数
#define ackLossRate 0.2//模拟接收丢包率
using namespace std;
queue<string> q1;//发送缓存
queue<string> q2;//已发送但未被接收
int Index = 0, len = sizeof(SOCKADDR),RepeatChance=canRepeat;//index用于读取文件的时候,给每个分组标序号,由于序号空间为12,因此index应该在0至11间循环
int lastAckedIndex = 0;
struct sockaddr_in addr;//发送目标的地址
SOCKET clientSocket;//客户端的套接字
sockaddr_in clientSocketAddr;//客户端的地址
double Timer=TimerCount;//计时器,为了偷懒我只设置了一个
BOOL InitSocket() {
    //加载套接字库(必须)
    WORD wVersionRequested;
    WSADATA wsaData;
    //套接字加载时错误提示
    int err;
    //版本 2.2
    wVersionRequested = MAKEWORD(2, 2);
    //加载 dll 文件 Scoket 库
    err = WSAStartup(wVersionRequested, &wsaData);
    if (err != 0) {
        //找不到 winsock.dll
        printf("加载 winsock 失败,错误代码为: %d\n", WSAGetLastError());
        return FALSE;
    }
    if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)
    {
        printf("不能找到正确的 winsock 版本\n");
        WSACleanup();
        return FALSE;
    }
    clientSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if (INVALID_SOCKET == clientSocket) {
        printf("创建套接字失败,错误代码为:%d\n", WSAGetLastError());
        return FALSE;
    }
    clientSocketAddr.sin_family = AF_INET;
    clientSocketAddr.sin_port = htons(clientPort);
    clientSocketAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
    if (bind(clientSocket, (SOCKADDR*)&clientSocketAddr, sizeof(SOCKADDR)) == SOCKET_ERROR) {
        printf("绑定套接字失败\n");
        return FALSE;
    }
    addr.sin_family = AF_INET;
    addr.sin_port = htons(serverPort);
    addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    int iMode = 1;//非阻塞
    ioctlsocket(clientSocket, FIONBIO, (u_long FAR*)& iMode);
    return TRUE;
}//初始化套接字库,绑定地址,以及设置接收方式为非阻塞
//其实是就是+1再模序号大小
void increaseIndex() {
    if (Index == orderCount - 1) {
        Index = 0;
    }
    else
        Index++;
}
//从文件读入数据,并分组,标序号
void readFile() {
    Index = 0;
    ifstream file("test.txt", ios::in || ios::binary);
    int count = 0;
    string my;
    char p;
    while (true)
    {
        if (file.eof()) {
            cout << "已全部读完\n";
            break;
        }
        if (count == 1024) {
            q1.push(to_string(Index) + "\r\n" + my);
            count = 0;
            increaseIndex();
            my = "";
        }
        else {
            file.read(&p, 1);
            my = my + p;
            count++;
        }
    }
    if (!my.compare(""))
        q1.push(to_string(Index) + "\r\n" + my.substr(0, my.length() - 1));
    file.close();
}
//判断窗口大小,能不能继续发送分组
bool canSend() {
    return windowSize > q2.size();
}
//从数据分组中提取出序号
int getIndexByString(string s) {
    return atoi(s.substr(0, 2).c_str());//这里限制了index必须在100以内
}
//随机发生,用于模拟丢包
bool happenByPossibility(float f) {
    int ran = rand() % 100;
    if (ran > 100 * f) {
        return true;
    }
    return false;
}
//使用gbn发送数据
void sendMessageGBN() {
    RepeatChance = canRepeat;
    int recvSize = -1, acked, base;
    clock_t start, finish;
    char* ack = new char[maxDataSize];
    cout << q1.size()<<"个";
    sendto(clientSocket, to_string(q1.size()).c_str(), sizeof(to_string(q1.size())), 0, (sockaddr*)&addr, sizeof(addr));//先说明要传送多少分组
    while (q1.size() != 0 || q2.size() != 0) {
        start = clock();   
        if (Timer <= 0) {//超时了,得重传   
            cout << "超时";
            queue<string> tmp(q2);
            while (tmp.size() > 0) {                
                sendto(clientSocket, tmp.front().c_str(), tmp.front().length() + 1, 0, (sockaddr*)&addr, sizeof(addr));
                tmp.pop();
            }
            RepeatChance--;
            if (RepeatChance == 0) {
                cout << "\n接收方无响应\n";
                return;
            }
            Timer = TimerCount;
        }
        while(canSend()) {            
            if (q1.size() != 0) {//还没发完
                if (happenByPossibility(sendLossRate)) {
                    int nRet = sendto(clientSocket, q1.front().c_str(), q1.front().length() + 1, 0, (sockaddr*)&addr, sizeof(addr));
                    if (nRet == SOCKET_ERROR) {
                        cout << "sendto Error " << WSAGetLastError() << endl;
                        break;
                    }
                }                
                q2.push(q1.front());
                q1.pop();//发送新的分组
            }
            else {
                break;
            }
        }                
        recvSize = recvfrom(clientSocket, ack, maxDataSize, 0, (SOCKADDR*)&addr, &len);
        if (recvSize < 0) {
                cout << "未接到\n";                   
        }
        else {            
            RepeatChance = canRepeat;
            acked = getIndexByString(ack);
            cout << "已经确认" << acked;
            base = getIndexByString(q2.front());
            int i = base + q2.size() - orderCount;
            if (acked <= i) {
                acked += orderCount;
            }
            while (acked > getIndexByString(q2.front())) {
                q2.pop();
                Timer = TimerCount;
                if (q2.size() == 0) {
                    break;
                }
            }
        }
        Sleep(100);
        finish = clock();
        Timer -= double(finish - start) / CLOCKS_PER_SEC;
        cout << "\n剩余时间:" << Timer << endl;
    }
}
//使用sr发送数据
void sendMessageSR() {
    RepeatChance = canRepeat;
    int recvSize = -1, acked, base;
    map<int, bool> MAP;
    clock_t start, finish;
    char* ack = new char[1024];
    cout << q1.size() << "个";
    sendto(clientSocket, to_string(q1.size()).c_str(), sizeof(to_string(q1.size())), 0, (sockaddr*)&addr, sizeof(addr));//先说明要传送多少分组
    while (q1.size() != 0 || q2.size() != 0) {
        start = clock();
        if (Timer <= 0) {//超时了,得重传   
            cout << "超时";
            queue<string> tmp(q2);
            while (tmp.size() > 0) {
                sendto(clientSocket, tmp.front().c_str(), tmp.front().length() + 1, 0, (sockaddr*)&addr, sizeof(addr));
                tmp.pop();
            }
            RepeatChance--;
            if (RepeatChance == 0) {
                cout << "\n接收方无响应\n";
                return;
            }
            Timer = TimerCount;
        }
        while (canSend()) {
            if (q1.size() != 0) {//还没发完
                if (happenByPossibility(sendLossRate)) {
                    int nRet = sendto(clientSocket, q1.front().c_str(), q1.front().length() + 1, 0, (sockaddr*)&addr, sizeof(addr));
                    if (nRet == SOCKET_ERROR) {
                        cout << "sendto Error " << WSAGetLastError() << endl;
                        break;
                    }
                }
                q2.push(q1.front());
                MAP[getIndexByString(q1.front())] = false;
                q1.pop();//发送新的分组
            }
            else {//全部分组都发送过了,但不一定都被确认
                break;
            }
        }
        recvSize = recvfrom(clientSocket, ack, maxDataSize, 0, (SOCKADDR*)&addr, &len);
        if (recvSize < 0) {
            cout << "未接到\n";
        }
        else {
            RepeatChance = canRepeat;
            acked = getIndexByString(ack);
            cout << "已经确认" << acked;
            MAP[acked] = true;
            while (true)
            {
                if (q2.empty()) {
                    break;
                }
                base = getIndexByString(q2.front());
                if (!MAP[base]) {
                    break;
                }
                q2.pop();//已经被确认的出队列
            }
        }
        Sleep(100);
        finish = clock();
        Timer -= double(finish - start) / CLOCKS_PER_SEC;
        cout << "\n剩余时间:" << Timer << endl;
    }
}
//从数据分组中提取数据
char* getDataFromPackage(char* s) {
    const char* del = "\r\n";
    char* next;
    strtok_s(s, del, &next);
    return next + 2;
}
int main()
{
    InitSocket();
    string input;
    char* recvData = new char[1024], * clear;
    int recvSize = 0;
    while (true)
    {
        Sleep(5000);
        while ((recvSize = recvfrom(clientSocket, recvData, maxDataSize, 0, (SOCKADDR*)&addr, &len)) > 0)
        {
            cout << "abort" << endl;//防止将上一次传输重传的报文认为是新数据分组,影响下面的判断
        }
        cout << "\n请输入指令:\n";
        cin >> input;
        int nRet = sendto(clientSocket, input.c_str(), input.length() + 1, 0, (SOCKADDR*)&addr, sizeof(addr));
        if (nRet == SOCKET_ERROR) {
            cout << "sendto Error " << WSAGetLastError() << endl;
            break;
        }
        while ((recvSize = recvfrom(clientSocket, recvData, maxDataSize, 0, (SOCKADDR*)&addr, &len)) < 0) {
            Sleep(100);
        }        
        if (input.compare("-testgbn") == 0) {
            if (recvData[0] == 'O'&& recvData[1] == 'k') {//说明服务器可以开始传输文件了
                readFile();
                sendMessageGBN();
            }            
        }
        else if (input.compare("-testsr") == 0) {
            if (recvData[0] == 'O' && recvData[1] == 'k') {//说明服务器可以开始传输文件了
                readFile();
                sendMessageSR();
            }
        }
        else if (input.compare("-url")==0) {
            ofstream file("test.txt", ios::out || ios::binary || ios::trunc);
            int packageNum = -1, currentAckedIndex = -1;
            if (!file.fail()) {
                string my = recvData;
                //cout << my << "111\n";
                packageNum = atoi(my.substr(0, 2).c_str());
                cout << "\n共有" << packageNum << "个数据包\n";
                while (packageNum > 0) {
                    char* newData = new char[1024];
                    while ((recvSize = recvfrom(clientSocket, newData, maxDataSize, 0, (SOCKADDR*)&addr, &len)) < 0) {
                        Sleep(200);
                    }
                    if (getIndexByString(newData) == (currentAckedIndex + 1) % orderCount) {
                        char* data = getDataFromPackage(newData);
                        file.write(data, strlen(data) + 1);
                        currentAckedIndex++;
                        currentAckedIndex %= orderCount;
                        packageNum--;
                        if (happenByPossibility(ackLossRate)) {
                            int nRet = sendto(clientSocket, to_string((currentAckedIndex + 1) % orderCount).c_str(), sizeof(to_string((currentAckedIndex + 1) % orderCount)), 0, (SOCKADDR*)&addr, len);
                            if (nRet == SOCKET_ERROR) {
                                cout << "sendto Error " << WSAGetLastError() << endl;
                                break;
                            }
                        }
                        else {
                            cout << "丢弃ack" << (currentAckedIndex + 1) % orderCount << endl;
                        }
                    }

                }
                cout << "接收完毕";
            }            
            file.close();
        }
        else {
            cout << recvData<<endl;
            if (input.compare("-quit")==0) {
                exit(0);
            }
        }
    }
    

}


Servidor: 

#include <stdio.h>
#include "stdlib.h"
#include <tchar.h>
#include <Windows.h>
#include <process.h>
#include <string.h>
#include<mutex>									
#include <iostream>
#include <fstream>	//读写文件流
#include <string>
#include<queue>
#include <map>
using namespace std;
#pragma comment(lib,"Ws2_32.lib")
#define serverPort 888
#define clientPort 666
#define maxDataSize 1048
#define ackLossRate 0.2
#define windowSize 5
#define TimerCount 2
#define orderCount 12
#define sendLossRate 0.3
#define canRepeat 2
using namespace std;
int len=sizeof(SOCKADDR);
int Index = 0, RepeatChance = 2;
double Timer = TimerCount;
char* recvData = new char[1024];//可接收文件大小为1kB
SOCKET serverSocket;
SOCKADDR_IN serverSocketAddr,addr;
queue<string> q1;//发送缓存
queue<string> q2;//已发送但未被接收


BOOL InitSocket() {
    //加载套接字库(必须)
    WORD wVersionRequested;
    WSADATA wsaData;
    //套接字加载时错误提示
    int err;
    //版本 2.2
    wVersionRequested = MAKEWORD(2, 2);
    //加载 dll 文件 Scoket 库
    err = WSAStartup(wVersionRequested, &wsaData);
    if (err != 0) {
        //找不到 winsock.dll
        printf("加载 winsock 失败,错误代码为: %d\n", WSAGetLastError());
        return FALSE;
    }
    if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)
    {
        printf("不能找到正确的 winsock 版本\n");
        WSACleanup();
        return FALSE;
    }
    serverSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if (INVALID_SOCKET == serverSocket) {
        printf("创建套接字失败,错误代码为:%d\n", WSAGetLastError());
        return FALSE;
    }
    serverSocketAddr.sin_family = AF_INET;
    serverSocketAddr.sin_port = htons(serverPort);
    serverSocketAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");;
    if (bind(serverSocket, (SOCKADDR*)&serverSocketAddr, sizeof(SOCKADDR)) == SOCKET_ERROR) {
        printf("绑定套接字失败\n");
        return FALSE;
    }
    addr.sin_family = AF_INET;
    addr.sin_port = htons(clientPort);
    addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    int iMode = 1;//非阻塞
    ioctlsocket(serverSocket, FIONBIO, (u_long FAR*) & iMode);
    return TRUE;
}
int getIndexByString(string s) {
    return atoi(s.substr(0, 2).c_str());//这里限制了index必须在100以内
}
char* getDataFromPackage(char *s) {
    const char* del = "\r\n";
    char* next;
    strtok_s(s, del, &next);
    return next+2;
}
bool happenByPossibility(float f) {
    int ran = rand() % 100;
    if (ran > 100 * f) {
        return true;
    }
    return false;
}
void increaseIndex() {
    if (Index == orderCount - 1) {
        Index = 0;
    }
    else
        Index++;
}
bool canSend() {
    return windowSize > q2.size();
}
void readFile() {
    Index = 0;
    ifstream file("data.txt", ios::in || ios::binary);
    int count = 0;
    string my;
    char p;
    while (true)
    {
        if (file.eof()) {
            cout << "已全部读完\n";
            break;
        }
        if (count == 1024) {
            q1.push(to_string(Index) + "\r\n" + my);
            count = 0;
            increaseIndex();
            my = "";
        }
        else {
            file.read(&p, 1);
            my = my + p;
            count++;
        }
    }
    if (!my.compare(""))
        q1.push(to_string(Index) + "\r\n" + my.substr(0, my.length() - 1));
    file.close();
}
void sendMessageGBN() {
    RepeatChance = canRepeat;
    int recvSize = -1, acked, base;
    clock_t start, finish;
    char* ack = new char[maxDataSize ];
    cout << q1.size() << "个";
    sendto(serverSocket, to_string(q1.size()).c_str(), to_string(q1.size()).length()+1, 0, (sockaddr*)&addr, sizeof(addr));//先说明要传送多少分组
    while (q1.size() != 0 || q2.size() != 0) {
        start = clock();
        if (Timer <= 0) {//超时了,得重传   
            RepeatChance--;
            if (RepeatChance == 0) {
                cout << "\n接收方无响应\n";
                return;
            }
            cout << "超时";
            queue<string> tmp(q2);
            while (tmp.size() > 0) {
                sendto(serverSocket, tmp.front().c_str(), tmp.front().length() + 1, 0, (sockaddr*)&addr, sizeof(addr));
                tmp.pop();
            }            
            Timer = TimerCount;
        }
        while (canSend()) {
            if (q1.size() != 0) {//还没发完
                if (happenByPossibility(sendLossRate)) {
                    int nRet = sendto(serverSocket, q1.front().c_str(), q1.front().length() + 1, 0, (sockaddr*)&addr, sizeof(addr));
                    if (nRet == SOCKET_ERROR) {
                        cout << "sendto Error " << WSAGetLastError() << endl;
                        break;
                    }
                }
                q2.push(q1.front());
                q1.pop();//发送新的分组
            }
            else {
                break;
            }
        }
        recvSize = recvfrom(serverSocket, ack, maxDataSize, 0, (SOCKADDR*)&addr, &len);
        if (recvSize < 0) {
            cout << "未接到\n";
        }
        else {
            RepeatChance = canRepeat;
            acked = getIndexByString(ack);
            cout << "已经确认" << acked;
            base = getIndexByString(q2.front());
            int i = base + q2.size() - orderCount;
            if (acked <= i) {
                acked += orderCount;
            }
            while (acked > getIndexByString(q2.front())) {
                q2.pop();
                Timer = TimerCount;
                if (q2.size() == 0) {
                    break;
                }
            }
        }
        Sleep(100);
        finish = clock();
        Timer -= double(finish - start) / CLOCKS_PER_SEC;
        cout << "\n剩余时间:" << Timer << endl;
    }
}
//处理用户发送的请求
void solveRequest() {  
    int recvSize = -1;
    while (true)
    {
        if ((recvSize = recvfrom(serverSocket, recvData, 1024, 0, (SOCKADDR*)&addr, &len))<0){
            cout << ".";
            Sleep(200);
            continue;
        }
        cout << '!';
        if (strcmp(recvData, "-time")==0) {
            SYSTEMTIME st;
            GetLocalTime(&st);
            string time;
            time = to_string(st.wYear) + "-" + to_string(st.wMonth) + "-" + to_string(st.wDay) + "-" + to_string(st.wHour) + "-" + to_string(st.wMinute) + "-" + to_string(st.wSecond);\
            sendto(serverSocket, time.c_str(), sizeof(time), 0, (SOCKADDR*)&addr, len);
        }
        else if (strcmp(recvData, "-quit") == 0) {
            sendto(serverSocket, "goodbye", sizeof("goodbye"), 0, (SOCKADDR*)&addr, len);
        }
        else if (strcmp(recvData, "-testgbn") == 0) {
            
            ofstream file("data.txt", ios::out || ios::binary||ios::trunc);            
            int packageNum = -1, currentAckedIndex = -1;
            if (!file.fail()) {   
                sendto(serverSocket, "Ok", sizeof("Ok"), 0, (SOCKADDR*)&addr, len);
                while ((recvSize = recvfrom(serverSocket, recvData, maxDataSize, 0, (SOCKADDR*)&addr, &len)) < 0) {
                    cout << ".";
                    Sleep(200);                    
                }
                string my = recvData;               
                packageNum = atoi(my.substr(0, 2).c_str());
                cout <<"\n共有" << packageNum<<"个数据包\n";
            }
            while (packageNum > 0) {
                char* newData = new char[1024];
                while ((recvSize = recvfrom(serverSocket, newData, maxDataSize, 0, (SOCKADDR*)&addr, &len)) < 0) {                  
                    Sleep(200);
                }                
                if (getIndexByString(newData) == (currentAckedIndex + 1) % orderCount) {
                    char *data = getDataFromPackage(newData);                    
                    file.write(data, strlen(data)+1);
                    currentAckedIndex++;
                    currentAckedIndex %= orderCount;
                    packageNum--;
                    cout << "收到" << currentAckedIndex << endl;
                    if (happenByPossibility(ackLossRate)) {
                        int nRet = sendto(serverSocket, to_string((currentAckedIndex + 1) % orderCount).c_str(), sizeof(to_string((currentAckedIndex + 1) % orderCount)), 0, (SOCKADDR*)&addr, len);
                        if (nRet == SOCKET_ERROR) {
                            cout << "sendto Error " << WSAGetLastError() << endl;
                            break;
                        }
                    }   
                    else {
                        cout << "丢弃" << (currentAckedIndex + 1) % orderCount<<endl;
                    }
                }

            }
            cout << "接收完毕";
            file.close();
        }
        else if (strcmp(recvData, "-testsr") == 0) {
            ofstream file("data.txt", ios::out || ios::binary || ios::trunc);
            int packageNum = -1, base=0,baseOrder=0;
            string buff[windowSize]={""};
            if (!file.fail()) {
                sendto(serverSocket, "Ok", sizeof("Ok"), 0, (SOCKADDR*)&addr, len);
                while ((recvSize = recvfrom(serverSocket, recvData, maxDataSize, 0, (SOCKADDR*)&addr, &len)) < 0) {
                    cout << ".";
                    Sleep(200);
                }
                string my = recvData;
                packageNum = atoi(my.substr(0, 2).c_str());
                cout << "\n共有" << packageNum << "个数据包\n";
            }
            while (packageNum > 0) {
                char* newData = new char[1024];
                while ((recvSize = recvfrom(serverSocket, newData, maxDataSize, 0, (SOCKADDR*)&addr, &len)) < 0) {                    
                    Sleep(200);
                }                
                int orderRecv = getIndexByString(newData);
                char* data = getDataFromPackage(newData);
                cout <<"\n收到分组:"<< orderRecv << endl;
                cout << "最先未收到分组:" << base  << endl;                 
                if (baseOrder > orderCount-windowSize&&orderRecv<windowSize-1) {
                    buff[(orderRecv+orderCount) % windowSize] = data;
                }
                else if(baseOrder > orderRecv) {
                }
                else {
                    buff[orderRecv % windowSize] = data;
                }         
                if (happenByPossibility(ackLossRate)) {
                    int nRet = sendto(serverSocket, to_string(orderRecv).c_str(), sizeof(to_string(orderRecv)), 0, (SOCKADDR*)&addr, len);
                    if (nRet == SOCKET_ERROR) {
                        cout << "sendto Error " << WSAGetLastError() << endl;
                        break;
                    }
                }
                else {
                    cout << "丢弃ack" << orderRecv << endl;
                }
                while (buff[base].length()!=0)
                {
                    file.write(buff[base].c_str(), buff[base].length() + 1);
                    buff[base] = "";
                    base = ++base % windowSize;
                    baseOrder = ++baseOrder % orderCount;
                    packageNum--;
                }                
            }
            cout << "接收完毕";
            file.close();
        }
        else if (strcmp(recvData, "-url") == 0) {
            readFile();
            sendMessageGBN();
        }
        else {
            sendto(serverSocket, recvData, strlen(recvData)+1, 0, (SOCKADDR*)&addr, len);
        }

    }
}
int main()
{
    InitSocket();
    solveRequest();
    
}

Supongo que te gusta

Origin blog.csdn.net/qq_16198739/article/details/127341619
Recomendado
Clasificación