Marked_copy 2019-01-30 10:47 采纳率: 0%
浏览 927

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;
}
  • 写回答

1条回答

  • 空白Acite 2019-02-06 03:50
    关注

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

    评论

报告相同问题?

悬赏问题

  • ¥20 ML307A在使用AT命令连接EMQX平台的MQTT时被拒绝
  • ¥20 腾讯企业邮箱邮件可以恢复么
  • ¥15 有人知道怎么将自己的迁移策略布到edgecloudsim上使用吗?
  • ¥15 错误 LNK2001 无法解析的外部符号
  • ¥50 安装pyaudiokits失败
  • ¥15 计组这些题应该咋做呀
  • ¥60 更换迈创SOL6M4AE卡的时候,驱动要重新装才能使用,怎么解决?
  • ¥15 让node服务器有自动加载文件的功能
  • ¥15 jmeter脚本回放有的是对的有的是错的
  • ¥15 r语言蛋白组学相关问题