2024-10-15 09:18 采纳率: 75%
浏览 10

Windows下socket通信传输速率该怎么实现

我用C++实现一个小的demo,windows下socket通信(TCP/IP),现在我想测试他俩之间的传输速率,像iperf3那样。现在遇到了一点问题,我不知道这个数据该怎么定义,是需要特定格式吗?收发功能需要特殊方法吗?下面是我的代码,直接生成了300M的数据,看看一秒呢服务端能接收到多少,想请假一下这个做法是否正确
Client

#include<iostream>
#include<winsock2.h>
#include<ws2tcpip.h>
#include<string>
#include<chrono>
#include <vector>
#include <random>
#pragma comment(lib,"ws2_32.lib")
std::vector<char> generateLargeData(size_t dataSize)
{
    std::vector<char> data(dataSize);
    std::default_random_engine generator;
    std::uniform_int_distribution<int> distribution(0, 255);

    for (size_t i = 0; i < dataSize; ++i) {
        data[i] = static_cast<char>(distribution(generator));
    }

    return data;
}
int ClientSpeed() {
    WSADATA wsaData;
    SOCKET clientSocket;
    sockaddr_in serverAddr;
    WORD sockVersion = MAKEWORD(2, 2);


    //初始化WSAStartup 函数
    if (WSAStartup(sockVersion, &wsaData) != 0) {
        std::cerr << "WSAStartup() error!" << std::endl;
        return 1;
    }

    clientSocket = socket(AF_INET, SOCK_STREAM, 0);
   

    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(8888);
    if (inet_pton(AF_INET, "127.0.0.1", &serverAddr.sin_addr) <= 0) {
        std::cerr << "Invalid address/Address not supported." << std::endl;
        closesocket(clientSocket);
        WSACleanup();
        return 1;
    }

    if (connect(clientSocket, (sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {
        std::cerr << "Connect failed: " << WSAGetLastError() << std::endl;
        closesocket(clientSocket);
        WSACleanup();
        return 1;
    }
    std::cout << "Client Connected to server!" << std::endl;

    // 生成大量数据
    auto largeData = generateLargeData(300 * 1024 * 1024); 

    size_t totalBytesSent = 0;
    auto start = std::chrono::high_resolution_clock::now();
    auto end = start;

    // 循环发送数据,直到一秒钟结束
    while (std::chrono::duration_cast<std::chrono::seconds>(end - start).count() < 1) {
        int bytesSent = send(clientSocket, largeData.data() + totalBytesSent, largeData.size() - totalBytesSent, 0);
        if (bytesSent > 0) {
            totalBytesSent += bytesSent;
        }
        else {
            // 处理错误情况
            std::cerr << "Send failed: " << WSAGetLastError() << std::endl;
            break;
        }
        end = std::chrono::high_resolution_clock::now();
    }

    double speedMBps = totalBytesSent / 1024.0 / 1024.0; // 计算总发送速度,单位为MB/s

    // 输出结果
    std::cout << "Total data sent in one second: " << totalBytesSent << " bytes." << std::endl;
    std::cout << "Speed: " << speedMBps << " MB/s" << std::endl;

    // 清理
    closesocket(clientSocket);
    WSACleanup();

    return 0;
}

Server


#include<iostream>
#include<WinSock2.h>
#include <ws2tcpip.h> // 包括 inet_ntop
using namespace std;
#pragma comment(lib,"ws2_32.lib")

int   Server()
{
    //初始化WSA
    WORD sockVersion = MAKEWORD(2, 2);
    WSADATA wsaData;//用于存放 socket 的初始化信息

    //int WSAStartup(WORD wVersionRequested, LPWSADATA lpWSAData);
    if (WSAStartup(sockVersion, &wsaData) != 0)
    {
        cout << "WSAStartup() error!" << endl;
        return 0;
    }

    //创建套接字  
    SOCKET slisten = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (slisten == INVALID_SOCKET)
    {
        cout << "socket error !" << endl;
        return 0;
    }

    //绑定IP和端口
    sockaddr_in sin;//ipv4的指定方法是使用struct sockaddr_in类型的变量 ipv6  使用struct sockaddr_in6
    sin.sin_family = AF_INET;
    sin.sin_port = htons(8888);//设置端口。htons将主机的unsigned short int转换为网络字节顺序 网络要用大端序如果本身是大端序则不会有改变 
    sin.sin_addr.S_un.S_addr = INADDR_ANY;//IP地址设置成INADDR_ANY, 服务器能后接受来自任何本地的连接请求
    //bind函数把一个地址族中的特定地址赋给scket。
    if (bind(slisten, (LPSOCKADDR)&sin, sizeof(sin)) == SOCKET_ERROR)
    {
        printf("bind error !");
    }

    //开始监听listen函数的这个参数控制的是在服务器尚未accept之前,能够排队等待的连接请求的数量
    if (listen(slisten, 10) == SOCKET_ERROR)
    {
        cout << "listen error !" << endl;
        return -1;
    }

    
    sockaddr_in remoteAddr;//sockaddr_in常用于socket定义和赋值,sockaddr用于函数参数
    int nAddrlen = sizeof(remoteAddr);
    while (true)
    {
        //循环接收数据 listen Socket负责接纳新的连接请求,而client Socket则负责处理具体的数据交换
        SOCKET sclient;
        cout << "TCP等待连接。。。" << endl;
        sclient = accept(slisten, (sockaddr*)&remoteAddr, &nAddrlen);
        if (sclient == INVALID_SOCKET)
        {
            cout << "accept error !" << endl;
            continue;
        }
        char str[INET_ADDRSTRLEN]; // INET_ADDRSTRLEN是为IPv4地址定义的长度
        inet_ntop(AF_INET, &(remoteAddr.sin_addr), str, INET_ADDRSTRLEN);
        cout << "接收到一个连接:" << str << endl;
        while (true) { // 为当前连接持续处理数据
            char revData[256];
            int ret = recv(sclient, revData, 255, 0);
            if (ret > 0) {
                revData[ret] = 0x00; // 确保字符串以null终结
                
                const char* sendData = "你好,TCP客户端";
                    send(sclient, sendData, strlen(sendData), 0);
            }
            else if (ret < 0) {    
                cout << "没有接收到数据" << endl;
                closesocket(sclient);
                break; 

            }
            else  {
                cout << "数据接收完成" << endl;
                closesocket(sclient);
                break;
            }
        }
        
    }
    closesocket(slisten);
    WSACleanup();
    system("pause");
    //return 0;
}
  • 写回答

1条回答 默认 最新

  • 檀越@新空间 2024-10-15 09:22
    关注

    上午好☀️☀️☀️️
    本答案参考ChatGPT-3.5

    你的问题是在尝试将接收功能封装到客户端中,并通过c++代码来测试TCP/IP连接的传输速率。以下是解决此问题的一些步骤:

    首先,你需要在源代码中对发送数据的部分进行一些改进。你可能希望添加更多的错误处理机制,以防止代码崩溃。

    然后,你可以考虑将客户端作为一个文件发送给服务器。这样,当服务器接收到文件时,它就会从磁盘上读取该文件的内容,并将其与服务器发送的数据进行比较。这可以有效地测量传输速率。

    以下是一个简单的示例,说明如何实现这个功能:

    #include <iostream>
    #include <fstream>
    #include <time>
    
    void writeFile(const std::string& data) {
        std::ofstream out("data.txt");
        out << data;
    }
    
    int main() {
        try {
            writeFile("Hello from client!");
            long startTime = time(nullptr);
            long endTime = time(nullptr);
    
            std::cout << "File written in " << (endTime - startTime) << " seconds." << std::endl;
    
            std::this_thread::sleep_for(std::chrono::seconds(1));
    
            std::cout << "Client wrote the file!" << std::endl;
    
            long networkTime = time(nullptr);
            long totalTime = endTime - startTime;
            double downloadRateKBps = (double)totalTime * 1024 / 86400;
    
            std::cout << "Download rate is " << downloadRateKBps << " KBps." << std::endl;
    
            return 0;
        } catch (const std::exception& e) {
            std::cerr << "Error writing to file: " << e.what() << std::endl;
            return -1;
        }
    }
    

    这个程序会尝试向名为"data.txt"的文件写入一行数据,并记录开始和结束的时间。然后,它会计算这段时间内下载的数据量(以字节为单位),并将结果乘以每秒上传的字节数(以千位数为单位)。

    请注意,这个程序只是一个基本的示例,实际的系统可能会有更复杂的网络环境和错误处理机制,因此你可能需要根据实际情况对其进行修改。

    评论

报告相同问题?

问题事件

  • 创建了问题 10月15日