C++ 关于tcp协议,使用recv、send如何提高下载速度

最近在写一个文件传输工具,具体是将一个内网计算机上的文件读取到内存中,然后再发送到公网服务器,公网服务器收到后再转发到内网的另一台计算机,经过测试内网ReadFile一次最多读取8388608字节(8MB)的文件数据,公网最多接收到198667字节(194KB)的数据,下载速度最多300k/s,如何提高,下面是代码

内网
DWORD _stdcall fileUpThread(LPVOID lParam)
{
    SOCKET sock = *(SOCKET*)lParam;
    SendMsg sendMsg;
    sendMsg.m_head.msg = { CMD_FILEUPSTART, NULL, NULL, NULL };
    send(sock, (char*)&sendMsg, sizeof(SendMsg), NULL); 

    HANDLE hUpFile = INVALID_HANDLE_VALUE;
    DWORD dwBytes;
    double dbUpFileSize, dbTotalFileSize;
    BYTE* sendBuffer = new BYTE[MAXBUFSIZE];
    wcout.imbue(locale("chs"));
    wcout << L"请输入文件路径:" << endl;
    wcin >> sendMsg.m_head.file.cScrFile;
    //获取上传文件
    hUpFile = CreateFile(sendMsg.m_head.file.cScrFile, GENERIC_READ, FILE_SHARE_READ, NULL,
        OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0
    );
    if (hUpFile == INVALID_HANDLE_VALUE)
        dbUpFileSize = 0;
    else
        dbUpFileSize = GetFileSize(hUpFile, NULL);

    sendMsg.m_head.file.iSize = dbUpFileSize;
    dbTotalFileSize = dbUpFileSize;
    //发送文件
    if (send(sock, (char*)&sendMsg, sizeof(sendMsg), 0) <= 0 || dbUpFileSize <= 0)
    {
        shutdown(sock, 0x02);
        closesocket(sock);
        return 1;
    }

    int nRet = 0;
    DWORD total = 0;
    DWORD record = 0;
    //循环发送文件数据
    while (dbUpFileSize > 0)
    {
        if (!ReadFile(hUpFile, sendBuffer, MAXBUFSIZE, &dwBytes, NULL))
            break;
        nRet = send(sock, (char*)sendBuffer, dwBytes, 0);
        if (nRet <= 0)
            break;

        dbUpFileSize -= nRet;
        total = 100 - ((dbUpFileSize / dbTotalFileSize) * 100);
        if (total != record)
        {
            if (0 == total % 10 && total != 0)
            {
                record = total;
                cout << total << "%" << endl;
            }
        }
    }   
    delete[] sendBuffer;
    CloseHandle(hUpFile);
    wcout << "文件上传完毕" << endl;
    /*shutdown(sock, 0x2);
    closesocket(sock);*/
}
内网
DWORD _stdcall fileDownThread(LPVOID lParam)
{
    SOCKET sock = *(SOCKET*)lParam;


    SendMsg sendMsg;    
    if (recv(sock, (char*)&sendMsg, sizeof(sendMsg), 0) <= 0)
    {
        shutdown(sock, 0x02);
        closesocket(sock);
        return 0;
    }
    HANDLE hDownFile = INVALID_HANDLE_VALUE;
    double dbDownFileSize, dbTotalFileSize;
    DWORD dwBufSize, dwBytes;
    BYTE* recvBuffer=new BYTE[MAXBUFSIZE];
    //为下载的数据创建文件
    wchar_t filePath[260];
    wcout.imbue(locale("chs"));
    wcout << TEXT("请输入文件创建路径:") << endl;
    wcin >> filePath;
    hDownFile = CreateFile(filePath, GENERIC_WRITE, FILE_SHARE_WRITE, NULL,
                           CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
    if (hDownFile == INVALID_HANDLE_VALUE)
    {
        dbDownFileSize = 0;
        PRINT(TEXT("文件下载-"), TEXT("创建文件失败"));
        return 0;
    }
    else
    {
        dbDownFileSize = sendMsg.m_head.file.iSize;
        PRINT(TEXT("文件下载-"), TEXT("创建文件成功"));
    }
    dbTotalFileSize = dbDownFileSize;
    int nRet = 0;
    DWORD total = 0;
    DWORD record = 0;
    //循环接收文件数据
    while (1)
    {
        nRet = recv(sock, (char*)recvBuffer, MAXBUFSIZE, 0);
        if (nRet <= 0)
            break;
        dbDownFileSize -= nRet;
        total = 100 - ((dbDownFileSize / dbTotalFileSize) * 100);
        if (total != record)
        {
            if (0 == total % 10 && total != 0)
            {
                record = total;
                cout << total << "%" << endl;
            }
        }
        WriteFile(hDownFile, recvBuffer, nRet, &dwBytes, NULL);
    }

    CloseHandle(hDownFile);
    delete[] recvBuffer;
    wcout.imbue(locale("chs"));
    wcout << TEXT("文件下载完毕:") << endl;
    //shutdown(sock, 0x02);
    //closesocket(sock);
    return 1;
}
公网数据转发
DWORD WINAPI TransmitData(LPVOID lParam)//在两个SOCKET中进行数据转发
{
    SOCKINFO socks = *((SOCKINFO*)lParam);
    SOCKET ClientSock = socks.ClientSock;
    SOCKET ServerSock = socks.ServerSock;
    char RecvBuf[MAXBUFSIZE] = { 0 };
    fd_set Fd_Read;
    int ret, nRecv;
    while (1)
    {
        FD_ZERO(&Fd_Read);
        FD_SET(ClientSock, &Fd_Read);
        FD_SET(ServerSock, &Fd_Read);
        ret = select(0, &Fd_Read, NULL, NULL, NULL);
        if (ret <= 0)
            goto error;
        if (FD_ISSET(ClientSock, &Fd_Read))
        {
            nRecv = recv(ClientSock, RecvBuf, sizeof(RecvBuf), 0);
            if (nRecv <= 0)
                goto error;
            ret = DataSend(ServerSock, RecvBuf, nRecv);
            if (ret == 0 || ret != nRecv)
                goto error;
        }
        if (FD_ISSET(ServerSock, &Fd_Read))
        {
            nRecv = recv(ServerSock, RecvBuf, sizeof(RecvBuf), 0);
            if (nRecv <= 0)
                goto error;
            ret = DataSend(ClientSock, RecvBuf, nRecv);
            if (ret == 0 || ret != nRecv)
                goto error;
        }
    }
error:
    closesocket(ClientSock);
    closesocket(ServerSock);
    return 0;
}
c++

1个回答

最好在从本地到服务器和从服务器到本地的过程上做文章。在确认网速没问题的情况下,可以试一试多线程数据传输,可以大幅提升速度。具体就是把文件分为几个小块,每个文件块使用单独的线程传输,服务端接受后再拼成原文件

Marked_copy
Marked_copy 多线程数据传输要考虑这个文件块的顺序问题,我还想问下阻塞模式和非阻塞模式在接收数据速度方面是不是有差异
大约一年之前 回复
Csdn user default icon
上传中...
上传图片
插入图片
抄袭、复制答案,以达到刷声望分或其他目的的行为,在CSDN问答是严格禁止的,一经发现立刻封号。是时候展现真正的技术了!
立即提问