Socket programming based on c++ simulates GBN, SR process

Target:

Create two processes, one process simulates the user, and the other simulates the server. The user can send files to the server through GBN and SR, and the server can also send files to the user.

principle:

GBN means go back N steps. When packet loss occurs and times out, the sender directly retransmits all content within the sliding window. ACK adopts the cumulative confirmation mode, that is, when an ack with sequence number N reaches the sender, the sender can conveniently consider it The receiver has received all packets with sequence numbers less than N.

SR is selective retransmission. The receiver can cache a certain amount of out-of-order packets and respond to the sender with the corresponding ack. When the earliest unconfirmed data packet arrives, the receiver can receive several packets in sequence until it encounters an unacknowledged packet. grouping. The words are lacking and the words do not convey the meaning. The explanation of GBN and SR is unclear, so please understand it yourself.

Implementation ideas:

GBN:

First look at the sender. I originally wanted to use a fixed-length array as the cache, but the window size is not certain, and the code to implement sliding is more complicated, so after thinking about it, I used a queue. The sender reads the file to be transmitted, groups it first, and stores the packets in sequence in queue q1 (used to store packets to be sent). When sending, the sent packets enter queue q2 (the user stores sent but not confirmed packet), and receive the ack from the receiver at the same time. If the sequence number of ack is greater than the sequence number of the head group of q2, the head of the team will be dequeued, and the above comparison process will be repeated until the sequence number of the head of the team is less than or equal to the sequence number of ack (ack's The sequence number is the sequence number expected to be received and has not been confirmed).

Secondly, look at the receiver. The logic of the receiver is relatively simple, so the receiver of GBN only needs to maintain a receive buffer of size one, and packets arriving out of order can be directly discarded. When receiving a packet, the receiver compares its sequence number with the sequence number it expects to receive. If they are equal, the packet is passed to the upper application (this is just a simulation, I only write it to a file), and the sequence number it expects to receive is increased by 1. Send ack; wait, no matter, discard the packet.

SR:

It still looks at the sender first, which is similar to GBN, except that each packet within the sliding window has an independent timer for retransmission when a timeout occurs. To be lazy, I only used one timer, which is the one for the first unacknowledged packet sent. Now that I think about it, it actually doesn't match my queue method, because if the queue does not pop up elements, I can only access the head and tail of the queue, but I cannot access the timers of other groups. I also encountered the same problem on the receiving side. For example, packets with sequence numbers 1, 3, and 4 arrive. If we draw a diagram of the receiver's reception buffer at this time, we will most likely leave a gap between 1 and 3. However, at the code level we cannot It is as simple as a paper demonstration. First, if we use an array as the receiving buffer, how do we determine the array index of the group? And how to identify whether the packet has been received or not. The only difference between them that need to be stored in the cache is the sequence number. With my Chinese proficiency that has not improved since I graduated from high school, I really can't express the problem clearly. You can find the problem by simulating the process of storing each group into the cache array on paper.

Code:

Note that here I named the file to be transferred on the client side as test.txt, and on the server side as data.txt. These files should be created in the current folder in advance, otherwise a file opening error will occur.

The running environment is vs2022, and C++ related extensions have been downloaded.

Client:

#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);
            }
        }
    }
    

}


Server: 

#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();
    
}

Guess you like

Origin blog.csdn.net/qq_16198739/article/details/127341619