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("服务器开启监听。。。 \r\n"));//创建线程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()里初始化:

复制代码
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
}
复制代码

客户端具体实现部分:

复制代码
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("连接服务器成功!\r\n"));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 \r\n"));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("文件接收完毕!\r\n"));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);}}}
复制代码

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/352546.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python报错UnicodeDecodeError: ‘ascii’ codec can’t decode byte 0xe0 in position 0: ordinal not in range

Windows 7机器上安装Python2.7后&#xff0c;下载一些Package包进行setup时总是报错UnicodeDecodeError&#xff0c;如下&#xff1a; File "C:\Python27\lib\mimetypes.py", line 250, in enum_types ctype ctype.encode(default_encoding) # omit in 3.x! Unicode…

[MEGA DEAL]专家级Java捆绑包新手(96%)

在世界上最受欢迎的编程语言中从零变成英雄 嘿&#xff0c;怪胎&#xff0c; 本周&#xff0c;在我们的JCG Deals商店中 &#xff0c;我们提供了一个极端的报价 。 我们提供的专家Java捆绑版新手 仅售39美元&#xff0c;而不是原始价格1180美元 &#xff0c;是的&#xff0c…

对二分法思想的体会 及 结队编程情况汇报

算法课第二章作业 1. 对二分法思想的体会&#xff1a; 二分法是分治法的一种&#xff0c;当遇到大问题难以解决的时候&#xff0c;可以使用二分法将问题细化&#xff0c;提高效率&#xff0c;减小问题规模。例如二分搜索&#xff0c;有效率高的优点&#xff0c;但是这个优点的实…

python中对象的概念是什么_简述Python中的面向对象编程的概念

面向对象编程——Object Oriented Programming&#xff0c;简称OOP&#xff0c;是一种程序设计思想。OOP把对象作为程序的基本单元&#xff0c;一个对象包含了数据和操作数据的函数。 面向过程的程序设计把计算机程序视为一系列的命令集合&#xff0c;即一组函数的顺序执行。为…

python 出现 Handler': No module named win32api

在运行scrapy程序出现Handler: No module named win32api&#xff0c;出现错误的原因是安装的python后要下载相对应的win32api文档进行安装&#xff0c;安装后可以到Python27\Lib\site-packages看一下是否安装成功&#xff0c;若安装完成该文件夹底下就有相应文件。

输入输出

cin/cout 数据类型自动识别/使用简单&#xff0c;缺点是速度慢。若遇到比较大的数据规模&#xff0c;很大可能被卡。改掉这个习惯&#xff01; scanf()和getchar()函数是从输入流缓冲区中读取值的&#xff0c;而不是从键盘终端缓冲区读取。 读取字符时&#xff0c;scanf()以spa…

C++ Socket编程步骤

sockets&#xff08;套接字&#xff09;编程有三种&#xff0c;流式套接字&#xff08;SOCK_STREAM&#xff09;&#xff0c;数据报套接字&#xff08;SOCK_DGRAM&#xff09;&#xff0c;原始套接字&#xff08;SOCK_RAW&#xff09;&#xff1b;基于TCP的socket编程是采用的流…

python中的排序方法都有哪些_Python中的排序方法sort(),sorted(),argsort()等

Python list内置sort()方法用来排序&#xff0c;也可以用python内置的全局sorted()方法来对可迭代的序列排序生成新的序列。 1&#xff09;排序基础 简单的升序排序是非常容易的。只需要调用sorted()方法。它返回一个新的list&#xff0c;新的list的元素基于小于运算符(__lt__)…

javadoc maven_Maven Fluido Skin和Javadoc类图

javadoc maven我使用Maven网站已有一段时间了&#xff0c;对此我感到非常满意。 我不想在Maven 3之后更新我的项目&#xff0c;但是没关系&#xff0c;Maven 3带来了许多新奇的东西。 但是&#xff0c;有两件事使我感到烦恼&#xff1a;缺乏美观和现代的外观&#xff0c;以及浏…

Python的包管理工具

刚开始学习Python时&#xff0c;在看文档和别人的blog介绍安装包有的用easy_install, setuptools, 有的使用pip&#xff0c;distribute&#xff0c;那麽这几个工具有什么关系呢&#xff0c;看一下下面这个图就明白了 下面简单的介绍一下&#xff1a; Distribute是对标准库disu…

2018软工实践第六次作业-团队选题报告

组长博客地址&#xff1a;点击这里 选题报告内容 选题报告下载链接&#xff1a;点击下载本组评审表设计 评审表下载链接&#xff1a;点击下载评审表预览&#xff1a;NABCD 分析引用 NEED 需求 用户群体 主要针对人群&#xff1a;福州大学的广大师生群体以及食堂各个店铺用户数量…

关于vs2008上的socket链接错误问题

昨天想用socket做一个简单的windows程序, 先拿来了以前在vc6.0上做的一小段代码, 竟然发现在vs2008上不能运行.出现了好多链接错误, 研究了好半天也没有发现是怎么回事.>下来是代码和 错误信息. 正在链接...>1>tem.obj : error LNK2019: 无法解析的外部符号 __imp__cl…

python定义变量并赋值_Python动态声明变量赋值代码实例

这篇文章主要介绍了Python动态声明变量赋值代码实例,文中通过示例代码介绍的非常详细&#xff0c;对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 通过exec()、globals()和locals() # 通过exec() for i in range(1, 4): # 第一次循环 i1 时,会执行字符串中的…

应用JDK 9 @不推荐使用的增强功能

我在博客文章JDK 9 Deprecated Annotation Enhancements中讨论了针对Deprecated注释的当前建议的JDK 9增强 功能 。 在本文中&#xff0c;我将更详细地介绍这些次要增强功能的建议用法&#xff0c;并说明关键的Java SE API如何已经应用了这些Deprecated增强功能。 JEP 277主页…

win7下安装pip——Python的包管理工具

很多Python的工具包的安装&#xff0c;用一个pip install ** 就可以了&#xff0c;看得我这个晕啊。。。于是搞了好几个小时&#xff0c;终于明白了pip 和easy_install、distribute 一样&#xff0c;是安装Python工具包的便捷管理工具。这几个管理工具的关系在&#xff1a;http…

MySQL中left join、right join与inner join的区别

1、数据库 1.1、作者表 1.2、图书表 1.3、出版社表 2、left join left join(左联接) 返回包括左表中的所有记录和右表中联结字段相等的记录。 2.1、sql语句 select * from app01_publisher left join app01_book on app01_publisher.id app01_book.publish_id 2.2、查询结果 3…

python得读音_python3 - 文本读音器

本篇分享的是使用python3制作一个文本读音器&#xff0c;简单点就是把指定的文本文字转语音说出来&#xff1b;做这么个小工具主要是为了方便自己在平时看一些文章眼累的时候&#xff0c;可通过语音来帮助自己&#xff0c;当然如果你是小说迷&#xff0c;可以扩展成一个小说读音…

Linux下python升级步骤

首先下载源tar包 可利用linux自带下载工具wget下载&#xff0c;如下所示&#xff1a; 1 # wget http://www.python.org/ftp/python/3.3.0/Python-3.3.0.tgz 或自己去网上找&#xff0c;这里提供一个最新版的下载链接&#xff1a;http://xiazai.zol.com.cn/detail/33/320958.sht…

windows 下安装Simplejson方法

1.下载&#xff1a;http://pypi.python.org/pypi/simplejson/ 文件为压缩文件 2.解压&#xff1a;可以直接右键&#xff1a;解压文件.例如&#xff1a;D:/simplejson 3.开始---运行---输入命令&#xff1a;cmd 4.进入到目录&#xff08;如&#xff1a;D:/simplejson&#xff09…

Vue(二十八)el-cascader 动态加载 - 省市区组件

1.后台接口为点击加载下一级 &#xff0c;传省市区id <template><el-cascaderv-model"selectedOptions"placeholder"请选择省市区":options"cascaderData"active-item-change"handleItemChange":props"{value: id,label…