当前位置:首页 > > 充电吧
[导读]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);
           
        }
       
    }
   

}

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

LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: 驱动电源

在工业自动化蓬勃发展的当下,工业电机作为核心动力设备,其驱动电源的性能直接关系到整个系统的稳定性和可靠性。其中,反电动势抑制与过流保护是驱动电源设计中至关重要的两个环节,集成化方案的设计成为提升电机驱动性能的关键。

关键字: 工业电机 驱动电源

LED 驱动电源作为 LED 照明系统的 “心脏”,其稳定性直接决定了整个照明设备的使用寿命。然而,在实际应用中,LED 驱动电源易损坏的问题却十分常见,不仅增加了维护成本,还影响了用户体验。要解决这一问题,需从设计、生...

关键字: 驱动电源 照明系统 散热

根据LED驱动电源的公式,电感内电流波动大小和电感值成反比,输出纹波和输出电容值成反比。所以加大电感值和输出电容值可以减小纹波。

关键字: LED 设计 驱动电源

电动汽车(EV)作为新能源汽车的重要代表,正逐渐成为全球汽车产业的重要发展方向。电动汽车的核心技术之一是电机驱动控制系统,而绝缘栅双极型晶体管(IGBT)作为电机驱动系统中的关键元件,其性能直接影响到电动汽车的动力性能和...

关键字: 电动汽车 新能源 驱动电源

在现代城市建设中,街道及停车场照明作为基础设施的重要组成部分,其质量和效率直接关系到城市的公共安全、居民生活质量和能源利用效率。随着科技的进步,高亮度白光发光二极管(LED)因其独特的优势逐渐取代传统光源,成为大功率区域...

关键字: 发光二极管 驱动电源 LED

LED通用照明设计工程师会遇到许多挑战,如功率密度、功率因数校正(PFC)、空间受限和可靠性等。

关键字: LED 驱动电源 功率因数校正

在LED照明技术日益普及的今天,LED驱动电源的电磁干扰(EMI)问题成为了一个不可忽视的挑战。电磁干扰不仅会影响LED灯具的正常工作,还可能对周围电子设备造成不利影响,甚至引发系统故障。因此,采取有效的硬件措施来解决L...

关键字: LED照明技术 电磁干扰 驱动电源

开关电源具有效率高的特性,而且开关电源的变压器体积比串联稳压型电源的要小得多,电源电路比较整洁,整机重量也有所下降,所以,现在的LED驱动电源

关键字: LED 驱动电源 开关电源

LED驱动电源是把电源供应转换为特定的电压电流以驱动LED发光的电压转换器,通常情况下:LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: LED 隧道灯 驱动电源
关闭