当前位置:首页 > 芯闻号 > 充电吧
[导读]c++ 使用socket实现C/S端文件的下载传输首先是服务器端,大致说下流程:服务器创建线程去处理应答accept(),当接受到客户端连接请求时,首先获取要发送的指定的文件数据总大小给客户端,接着就

c++ 使用socket实现C/S端文件的下载传输
首先是服务器端,大致说下流程:服务器创建线程去处理应答accept(),当接受到客户端连接请求时,首先获取要发送的指定的文件数据总大小给客户端,接着就是循环读取要发送的文件数据流向客户端发送文件数据,每次都判断循环读取到的数据实际大小,当实际读取到的数据总大小为0时,表示文件发送结束。下面是服务器server端实现:

声明部分:


public:
    afx_msg void OnBnClickedButton1();
public:
    BOOL InitSocket();    //初始化并创建套接字

    static DWORD WINAPI ThreadProc(LPVOID lpParameter);    //创建线程去执行服务器accept()
实现部分:


void CSendFileServerDlg::OnBnClickedButton1()
{
    // TODO: 在此添加控件通知处理程序代码
    if (InitSocket())
    {
        GetDlgItem(IDC_EDIT1)->SetWindowText(_T("服务器开启监听。。。 rn"));

        //创建线程
        HANDLE hThread = CreateThread(NULL,0,ThreadProc,NULL,0,NULL);
        //关闭该接收线程句柄,释放引用计数
        CloseHandle(hThread);
    }
}

BOOL CSendFileServerDlg::InitSocket()
{
    //加载套接字库
    WORD wVersionRequested;
    WSADATA wsaData;
    int err;
    wVersionRequested = MAKEWORD( 1, 1 );
    err = WSAStartup( wVersionRequested, &wsaData );
    if ( err != 0 )
    {
        return FALSE;
    }

    if ( LOBYTE( wsaData.wVersion ) != 1 || HIBYTE( wsaData.wVersion ) != 1 )
    {
            WSACleanup( );
            return FALSE;
    }

    //创建套接字
    //SOCKET m_socket=socket(AF_INET,SOCK_STREAM,0);
    m_socket=socket(AF_INET,SOCK_STREAM,0);
    if (m_socket == INVALID_SOCKET)
    {
        AfxMessageBox(_T("套接字创建失败!"));
        return FALSE;
    }

    SOCKADDR_IN addrSrv;
    addrSrv.sin_addr.S_un.S_addr=htonl(INADDR_ANY);
    addrSrv.sin_family=AF_INET;
    addrSrv.sin_port=htons(8099);

    err = bind(m_socket,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));    //绑定本地端口
    if (err==SOCKET_ERROR)
    {
        closesocket(m_socket);
        AfxMessageBox(_T("绑定失败!"));
        return FALSE;
    }
    listen(m_socket,5);//开启监听

    return TRUE;

}

DWORD WINAPI CSendFileServerDlg::ThreadProc(LPVOID lpParameter)
{
    SOCKADDR_IN addrClient;
    int len = sizeof(SOCKADDR);

    while (true)
    {
        SOCKET sockConn=accept(m_socket,(SOCKADDR*)&addrClient,&len);

        CString filename = _T("E:\test.zip");
        HANDLE hFile;
        unsigned long long file_size = 0;

        char Buffer[1024];
        DWORD dwNumberOfBytesRead;

        hFile = CreateFile(filename,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
        file_size = GetFileSize(hFile,NULL);
        send(sockConn,(char*)&file_size,sizeof(unsigned long long)+1,NULL);

        do
        {
            ::ReadFile(hFile,Buffer,sizeof(Buffer),&dwNumberOfBytesRead,NULL);
            ::send(sockConn,Buffer,dwNumberOfBytesRead,0);
        } while (dwNumberOfBytesRead);


        CloseHandle(hFile);
    }

    return 0;
}
如代码所述  每次发送单位是unsigned char[1024]大小(程序是char 应该为unsigned char[1024])所以就不存在网络字节序问题也不用考虑大端小端什么的。

服务器端暂时不支持多客户端并发访问,后续可能会加上。。。

-------------------------------------------

下面是客户端,同样也大致说下客户端流程,客户端增加手动填写Ip地址和端口号功能(端口号暂为8099)。以及下载传输文件数据进度条的显示,和下面简单的一些状态显示。客观端由填写的IP地址进行连接服务器操作,如果客户端连接服务器成功的话直接就会获取服务器端发送的要发送的文件数据的总大小,如果获取文件总大小>0 则会循环往指定的路径写数据啦。此处循环写文件结束标志,我是用每次实际写的累加如果累计值等于从服务器端获取的文件总大小的话表示下载文件数据成功,结束循环。大致是这样一个过程。代码实现:

客户端声明部分:

?public:
    afx_msg void OnBnClickedButton1();
 
    BOOL InitSocket();
    void ConnectServer();
    void ConnectRecvFileData(DWORD ip,int port);
 
private:
    CProgressCtrl *m_progress; //进度条

 进度条在OnInitDialog()里初始化:

按 Ctrl+C 复制代码
BOOL CRecvFileClientDlg::OnInitDialog()
{
    CDialog::OnInitDialog();

    // 将“关于...”菜单项添加到系统菜单中。

    // IDM_ABOUTBOX 必须在系统命令范围内。
    ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
    ASSERT(IDM_ABOUTBOX < 0xF000);

    CMenu* pSysMenu = GetSystemMenu(FALSE);
    if (pSysMenu != NULL)
    {
        CString strAboutMenu;
        strAboutMenu.LoadString(IDS_ABOUTBOX);
        if (!strAboutMenu.IsEmpty())
        {
            pSysMenu->AppendMenu(MF_SEPARATOR);
            pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
        }
    }

    // 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动
    //  执行此操作
    SetIcon(m_hIcon, TRUE);            // 设置大图标
    SetIcon(m_hIcon, FALSE);        // 设置小图标

    // TODO: 在此添加额外的初始化代码

    m_progress = (CProgressCtrl*)GetDlgItem(IDC_PROGRESS1);
    m_progress->SetPos(0);

    return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
}
按 Ctrl+C 复制代码
客户端具体实现部分:

按 Ctrl+C 复制代码
void CRecvFileClientDlg::OnBnClickedButton1()
{
    // TODO: 在此添加控件通知处理程序代码
    ConnectServer();
   
}


BOOL CRecvFileClientDlg::InitSocket()
{
    //加载套接字库
    WORD wVersionRequested;
    WSADATA wsaData;
    int err;
    wVersionRequested = MAKEWORD( 1, 1 );
    err = WSAStartup( wVersionRequested, &wsaData );
    if ( err != 0 )
    {
        return FALSE;
    }

    if ( LOBYTE( wsaData.wVersion ) != 1 || HIBYTE( wsaData.wVersion ) != 1 )
    {
        WSACleanup( );
        return FALSE;
    }

    return TRUE;

}

void CRecvFileClientDlg::ConnectRecvFileData(DWORD ip,int port)
{
   
    unsigned long long file_size=0;
    SOCKET sockClient = socket(AF_INET,SOCK_STREAM,0);
    SOCKADDR_IN addrSrv;
    addrSrv.sin_addr.S_un.S_addr=htonl(ip);
    addrSrv.sin_port=ntohs(port);
    addrSrv.sin_family = AF_INET;
    //connect(sockClient,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));
    //recv(sockClient,(char*)&file_size,sizeof(unsigned long long)+1,NULL);

    if (!connect(sockClient,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR)))
    {
        GetDlgItem(IDC_SHOWINFO)->SetWindowText(_T(""));
        GetDlgItem(IDC_SHOWINFO)->SetWindowText(_T("连接服务器成功!rn"));

       

        recv(sockClient,(char*)&file_size,sizeof(unsigned long long)+1,NULL);

        unsigned short maxvalue = file_size;    //此处不太稳妥 当数据很大时可能会出现异常
        m_progress->SetRange(0,maxvalue);

        if (file_size>0)
        {
            GetDlgItem(IDC_SHOWINFO)->SetWindowText(_T(""));
            GetDlgItem(IDC_SHOWINFO)->SetWindowText(_T("文件下载到本地 d:\test.zip rn"));

            DWORD dwNumberOfBytesRecv=0;
            DWORD dwCountOfBytesRecv=0;
            char Buffer[1024];
            CString filename = _T("d:\test.zip");
            HANDLE hFile;
            hFile = CreateFile(filename,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);

            do
            {
                m_progress->SetPos(dwCountOfBytesRecv);//更新进度条

                dwNumberOfBytesRecv = ::recv(sockClient,Buffer,sizeof(Buffer),0);
                ::WriteFile(hFile,Buffer,dwNumberOfBytesRecv,&dwNumberOfBytesRecv,NULL);
                dwCountOfBytesRecv += dwNumberOfBytesRecv;               
            } while (file_size - dwCountOfBytesRecv);


            CloseHandle(hFile);
           
            GetDlgItem(IDC_SHOWINFO)->SetWindowText(_T(""));
            GetDlgItem(IDC_SHOWINFO)->SetWindowText(_T("文件接收完毕!rn"));
            AfxMessageBox(_T("文件接收完毕!"));//醒目可以注释
        }else
        {
            AfxMessageBox(_T("获取文件总大小失败!"));
        }
    }else
    {
        AfxMessageBox(_T("连接服务器失败、请确认IP地址或端口号!"));
    }
   
   

    closesocket(sockClient);//关闭套接字


}

void CRecvFileClientDlg::ConnectServer()
{
    if (InitSocket())
    {
        DWORD strIp =NULL;
        CString strPort = _T("");

        ((CIPAddressCtrl*)GetDlgItem(IDC_IP))->GetAddress(strIp);
        GetDlgItem(IDC_PORT)->GetWindowText(strPort);

        if (strIp==NULL||strPort=="")
        {
            AfxMessageBox(_T("Ip地址或Port端口号不能为空!"));

        }else
        {
            int port = atoi(strPort.GetBuffer(1));
            ConnectRecvFileData(strIp,port);
           
        }
       
    }
   

}

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

9月2日消息,不造车的华为或将催生出更大的独角兽公司,随着阿维塔和赛力斯的入局,华为引望愈发显得引人瞩目。

关键字: 阿维塔 塞力斯 华为

加利福尼亚州圣克拉拉县2024年8月30日 /美通社/ -- 数字化转型技术解决方案公司Trianz今天宣布,该公司与Amazon Web Services (AWS)签订了...

关键字: AWS AN BSP 数字化

伦敦2024年8月29日 /美通社/ -- 英国汽车技术公司SODA.Auto推出其旗舰产品SODA V,这是全球首款涵盖汽车工程师从创意到认证的所有需求的工具,可用于创建软件定义汽车。 SODA V工具的开发耗时1.5...

关键字: 汽车 人工智能 智能驱动 BSP

北京2024年8月28日 /美通社/ -- 越来越多用户希望企业业务能7×24不间断运行,同时企业却面临越来越多业务中断的风险,如企业系统复杂性的增加,频繁的功能更新和发布等。如何确保业务连续性,提升韧性,成...

关键字: 亚马逊 解密 控制平面 BSP

8月30日消息,据媒体报道,腾讯和网易近期正在缩减他们对日本游戏市场的投资。

关键字: 腾讯 编码器 CPU

8月28日消息,今天上午,2024中国国际大数据产业博览会开幕式在贵阳举行,华为董事、质量流程IT总裁陶景文发表了演讲。

关键字: 华为 12nm EDA 半导体

8月28日消息,在2024中国国际大数据产业博览会上,华为常务董事、华为云CEO张平安发表演讲称,数字世界的话语权最终是由生态的繁荣决定的。

关键字: 华为 12nm 手机 卫星通信

要点: 有效应对环境变化,经营业绩稳中有升 落实提质增效举措,毛利润率延续升势 战略布局成效显著,战新业务引领增长 以科技创新为引领,提升企业核心竞争力 坚持高质量发展策略,塑强核心竞争优势...

关键字: 通信 BSP 电信运营商 数字经济

北京2024年8月27日 /美通社/ -- 8月21日,由中央广播电视总台与中国电影电视技术学会联合牵头组建的NVI技术创新联盟在BIRTV2024超高清全产业链发展研讨会上宣布正式成立。 活动现场 NVI技术创新联...

关键字: VI 传输协议 音频 BSP

北京2024年8月27日 /美通社/ -- 在8月23日举办的2024年长三角生态绿色一体化发展示范区联合招商会上,软通动力信息技术(集团)股份有限公司(以下简称"软通动力")与长三角投资(上海)有限...

关键字: BSP 信息技术
关闭
关闭