C++利用socket的客户端和服务器之间传输文件
来源:互联网 发布:商品条码数据库下载 编辑:程序博客网 时间:2024/04/26 13:27
//服务器的代码文件有/*message.hsource.hsource.cppserver.hserver.cpp*///客户端的代码文件有/*message.h 和服务器端一样client.hclient.cpp*///message.h#pragma once#include<iostream>using namespace std;#define MAX_PACK_SIZE 10240 //数据包的长度#define MAX_FILE_NAME_LENGTH 256 //文件名的长度#define INVALID_MSG -1 //无效的消息#define MSG_FILE_LENGTH 1 //文件长度#define MSG_FILE_NAME 2 //文件名#define MSG_FILE 4 //文件内容#define MSG_READY 3 //准备好消息#define MSG_SEND_FILE 5 //发送文件#define MSG_DOWNLOAD_FILE 6 //下载文件#define MSG_COMPLETE 7 //完成信息class Message{public:struct MsgHead //头消息{int msgId; //消息标识MsgHead(int msg=INVALID_MSG):msgId(msg){};};struct MsgFileLength :public MsgHead{_int64 fileLength; //文件长度MsgFileLength():MsgHead(MSG_FILE_LENGTH){}};struct MsgFileName:public MsgHead{char fileName[MAX_FILE_NAME_LENGTH];MsgFileName():MsgHead(MSG_FILE_NAME){}};struct MsgFile:public MsgHead{MsgFile():MsgHead(MSG_FILE){}};struct MsgReady:public MsgHead //准备好消息{MsgReady():MsgHead(MSG_READY){}};struct MsgSendFile:public MsgHead //发送文件消息{MsgSendFile():MsgHead(MSG_SEND_FILE){}};struct MsgDownLoadFile:public MsgHead //下载文件消息{MsgDownLoadFile():MsgHead(MSG_DOWNLOAD_FILE){}}; struct MsgComplete:public MsgHead{MsgComplete():MsgHead(MSG_COMPLETE){}};};//source.h 获取指定文件加下的符合要求的文件#pragma once#include<iostream>#include<fstream>#include<vector>#include<io.h>#include<string>using namespace std;class Source{public:vector<string> catalogInfo;void GetFiles(string path,string ext,vector<string> &files);//获取文件};//server.h#pragma once#include<iostream>#include<WinSock2.h>#include"message.h"#pragma comment(lib,"Ws2_32.lib")#define PORT 10000using namespace std;class Server{public:SOCKET sd;_int64 fileLength;char fileName[MAX_FILE_NAME_LENGTH];bool InitSock(); //初始winsocketSOCKET BindListen(); //绑定监听套接字SOCKET AcceptConnection(SOCKET sd); //接收客户端bool ProcessConnection(SOCKET sd); //传送数据bool ReceiveFile(SOCKET sd); //接收文件内容bool RecvFileName(SOCKET sd); //接收文件名bool GetAndSendFileLength(SOCKET sd); //获取文件长度bool SendFileName(SOCKET sd); //发送文件名bool SendFile(SOCKET sd); //发送文件void CloseSocket(); //关闭套接字};//source.cpp#pragma once#include<iostream>#include<vector>#include<io.h>#include<string>#include"source.h"using namespace std;void Source::GetFiles(string path,string ext,vector<string> &files){long hFile=0; //文件句柄 _finddata_t fileInfo; //文件信息string pathName;if((hFile=_findfirst(pathName.assign(path).append("\\*").c_str(),&fileInfo))!=-1) //判断路径是否有效并获取第一个文件{do{if(fileInfo.attrib & _A_SUBDIR) //如果是子文件夹{if(strcmp(fileInfo.name,".")!=0 && strcmp(fileInfo.name,"..")!=0) {GetFiles(pathName.assign(path).append("\\").append(fileInfo.name),ext,files); }}else{string filePath;filePath=pathName.assign(path).append("\\").append(fileInfo.name);char fileDrive[_MAX_DRIVE];char fileDir[_MAX_DIR];char fileName[_MAX_FNAME];char fileExt[_MAX_EXT];_splitpath(filePath.c_str(),fileDrive,fileDir,fileName,fileExt); //分解路径获取磁盘区路径文件名后缀if(strcmp(fileExt,ext.c_str())==0){files.push_back(filePath);}}}while(_findnext(hFile,&fileInfo)==0);_findclose(hFile);}}//server.cpp#pragma once#include<iostream>#include<string>#include<fstream>#include<WinSock2.h>#include"message.h"#include"server.h"#include"source.h"using namespace std;int main(){Server server;if(!server.InitSock()) //初始化失败{cout<<"初始化失败"<<endl;}server.sd=server.BindListen();if(server.sd==INVALID_SOCKET){return -1;}SOCKET sdListen=server.AcceptConnection(server.sd);if(sdListen==INVALID_SOCKET){return -1;}while(server.ProcessConnection(sdListen)){}server.CloseSocket();return 0;}bool Server::InitSock() //初始化winsocket{WSADATA wsData;WORD wr=MAKEWORD(2,2);if(WSAStartup(wr,&wsData)==0){return true;}return false;}SOCKET Server::BindListen() //绑定套接字{SOCKET sd=socket(AF_INET,SOCK_STREAM,0);if(sd==INVALID_SOCKET){cout<<"创建套接字失败"<<WSAGetLastError()<<endl;return INVALID_SOCKET;}sockaddr_in sListen;sListen.sin_family=AF_INET;sListen.sin_addr.s_addr=htonl(INADDR_ANY);sListen.sin_port=htons(PORT);int nSize;nSize=sizeof(sockaddr_in);if(bind(sd,(sockaddr*)&sListen,nSize)==SOCKET_ERROR){closesocket(sd);cout<<"绑定失败"<<WSAGetLastError()<<endl;return INVALID_SOCKET;}if(listen(sd,10)==SOCKET_ERROR){closesocket(sd);cout<<"监听失败"<<WSAGetLastError()<<endl;return INVALID_SOCKET;}return sd;}SOCKET Server::AcceptConnection(SOCKET sd) //接收客户端{sockaddr_in saRemote;int nSize=sizeof(sockaddr_in);SOCKET sdListen=accept(sd,(sockaddr*)&saRemote,&nSize);if(sdListen==INVALID_SOCKET){cout<<"接收客户端失败"<<WSAGetLastError()<<endl;return INVALID_SOCKET;}return sdListen;}bool Server::ReceiveFile(SOCKET sd){ char buff[MAX_PACK_SIZE]; FILE *pFile;pFile=fopen(fileName,"a+b");_int64 i=0; while(i+1<fileLength){int nRecv=recv(sd,buff,MAX_PACK_SIZE,0); if(nRecv==SOCKET_ERROR){ return false;}fwrite(buff,sizeof(char),nRecv,pFile);i+=nRecv; memset(buff,0,sizeof(char)*MAX_PACK_SIZE);}fclose(pFile);return true;}void Server::CloseSocket(){closesocket(sd);WSACleanup();}bool Server::ProcessConnection(SOCKET sd){//----------------------------------------------//可以将下面代码看做设置系统缓冲区int nRecvBuf=1024000;//设置为1000K setsockopt(sd,SOL_SOCKET,SO_RCVBUF,(const char*)&nRecvBuf,sizeof(int)); //发送缓冲区 int nSendBuf=1024000;//设置为1000K setsockopt(sd,SOL_SOCKET,SO_SNDBUF,(const char*)&nSendBuf,sizeof(int));//-------------------------------------------------------------char buff[MAX_PACK_SIZE];Message::MsgHead *msgHead;if(recv(sd,buff,MAX_PACK_SIZE,0)==SOCKET_ERROR){cout<<"接收失败"<<WSAGetLastError()<<endl;return false;}msgHead=(Message::MsgHead *)&buff;switch(msgHead->msgId){case MSG_SEND_FILE: //客户端向服务器发送文件cout<<"客户端请求向服务器发送文件"<<endl;break;case MSG_DOWNLOAD_FILE: //客户端从服务器下载文件{cout<<"客户端请求从服务器下载文件"<<endl;Source source; //用来获取指定文件加下的后缀为jpg文件string sPath="E:\\图片";string sExt=".jpg";source.GetFiles(sPath,sExt,source.catalogInfo);int nSize;nSize=source.catalogInfo.size();cout<<"搜集到"<<nSize<<"个文件"<<endl; char buff[MAX_PACK_SIZE];for(int i=0;i<nSize;i++) //将目录信息发送到客户端{strcpy(buff,source.catalogInfo[i].c_str());//cout<<source.catalogInfo[i]<<endl;if(send(sd,buff,MAX_PACK_SIZE,0)==SOCKET_ERROR){cout<<"发送目录信息失败"<<WSAGetLastError()<<endl;return false;}Sleep(10); //睡眠10ms让接收端将信息取走}Message::MsgComplete msgComplete;if(send(sd,(char *)&msgComplete,sizeof(Message::MsgComplete),0)==SOCKET_ERROR){cout<<"发送完成信息失败"<<WSAGetLastError()<<endl;return false;}Sleep(10);if(!RecvFileName(sd)){return false;}Sleep(10);if(!GetAndSendFileLength(sd)){return false;}Sleep(10);if(!SendFileName(sd)){return false;}Sleep(10);if(!SendFile(sd)){return false;}}break;case MSG_FILE_NAME: //发送的文件名{Message::MsgFileName *msgFileName; msgFileName=(Message::MsgFileName*)msgHead; strcpy(fileName,msgFileName->fileName); cout<<"收到发送来的文件名"<<fileName<<endl;}break;case MSG_FILE_LENGTH: //发送的文件长度{Message::MsgFileLength *msgFileLength;msgFileLength=(Message::MsgFileLength *)msgHead;fileLength=msgFileLength->fileLength;cout<<"接收到文件的长度为"<<fileLength<<endl;}break;case MSG_FILE: //发送的文件内容{cout<<"开始接收文件"<<endl;if(!ReceiveFile(sd)){cout<<"接收文件失败"<<endl;return false;}}break;default:cout<<"非标准消息"<<endl;return false;}return true;}bool Server::RecvFileName(SOCKET sd){//memset(fileName,0,sizeof(char)*MAX_FILE_NAME_LENGTH); //清空char buff[MAX_PACK_SIZE];Message::MsgFileName *msgFileName;if(recv(sd,buff,MAX_PACK_SIZE,0)==SOCKET_ERROR){cout<<"接收文件名失败"<<WSAGetLastError()<<endl;return false;}msgFileName=(Message::MsgFileName *)buff;strcpy(fileName,msgFileName->fileName);cout<<"接收的文件名为"<<fileName<<endl;return true;}bool Server::GetAndSendFileLength(SOCKET sd) //获取客户端要下载的文件长度{Message::MsgFileLength msgFileLength;FILE *pFile;pFile=fopen(fileName,"r+b");if(pFile==NULL){cout<<"打开文件失败"<<endl;return false;}fseek(pFile,0,SEEK_END); fileLength=_ftelli64(pFile);fclose(pFile);msgFileLength.fileLength=fileLength;if(send(sd,(char*)&msgFileLength,sizeof(Message::MsgFileLength),0)==SOCKET_ERROR){cout<<"发送文件长度失败"<<WSAGetLastError()<<endl;return false;}return true;}bool Server::SendFileName(SOCKET sd) //向客户端发送文件名{Message::MsgFileName msgFileName;char fileDrive[_MAX_DRIVE];char fileDir[_MAX_DIR];char Name[_MAX_FNAME];char fileExt[_MAX_EXT];_splitpath(fileName,fileDrive,fileDir,Name,fileExt);strcat(Name,fileExt);strcpy(msgFileName.fileName,Name);cout<<"要发送的文件名为"<<Name<<endl;if(send(sd,(char *)&msgFileName,sizeof(Message::MsgFileName),0)==SOCKET_ERROR){cout<<"发送文件名出错"<<WSAGetLastError()<<endl;return false;}return true;}bool Server::SendFile(SOCKET sd) //向客户端发送文件{cout<<"进入到发送文件内容"<<endl;cout<<"要发送的文件为"<<fileName<<endl;FILE *pFile;pFile=fopen(fileName,"r+b");fseek(pFile,0,SEEK_SET); //定位到文件首位置_int64 i=0;char buff[MAX_PACK_SIZE];cout<<"要发送的文件长度为"<<fileLength<<endl;while(i<fileLength){int nSize;if(i+MAX_PACK_SIZE>fileLength){nSize=(int)(fileLength-i);}else{nSize=MAX_PACK_SIZE-1;}fread(buff,sizeof(char),nSize,pFile);int nSend;nSend=send(sd,buff,nSize,0);if(nSend==SOCKET_ERROR){cout<<"发送失败"<<WSAGetLastError()<<endl;return false;}i+=nSend;fseek(pFile,-(nSize-nSend),SEEK_CUR); //定位到实际已发送到的位置memset(buff,0,sizeof(char)*MAX_PACK_SIZE); //将buff清空}fclose(pFile);return true;}//client.h#pragma once#include<iostream>#include<fstream>#include<vector>#include<WinSock2.h>#pragma comment(lib,"Ws2_32.lib")using namespace std;#define SERVER_IP "127.0.0.1"#define PORT 10000class Client{public:_int64 nFileLength;char fileName[_MAX_FNAME+_MAX_EXT];SOCKET sd;bool InitSock(); //初始化winsocku_long ResolveAdress(char *serverIp); //解析服务器地址SOCKET ConnectServer(u_long serverIp,int port);//连接服务器bool ProcessConnection(SOCKET sd); //客户端服务器交互void CloseSocket(); //释放套接字bool SendFileLength(SOCKET sd,char *filePath); //发送文件长度bool SendFile(SOCKET sd,char *filePath); //发送文件bool RecvCatalogInfo(SOCKET sd); //接收目录信息bool SendDownLoadFileName(SOCKET sd); //发送要下载的文件名bool ReceiveFileLength(SOCKET sd); //接收文件长度bool ReceiveFileName(SOCKET sd); //接收文件名bool ReceiveFile(SOCKET sd); //接收文件//void DoWork(); //主体函数};//client.cpp#define _CRT_SECURE_NO_WARNINGS#pragma once#include<iostream>#include<vector>#include<WinSock2.h>#include"client.h"#include"message.h"using namespace std;int main(){Client client;if(!client.InitSock()){cout<<"初始socket失败"<<endl;return -1;}SOCKET saRemote=client.ConnectServer(client.ResolveAdress(SERVER_IP),PORT);if(saRemote==INVALID_SOCKET){cout<<"连接服务器失败"<<endl;return -1;}if(!client.ProcessConnection(saRemote)){return -1;}client.CloseSocket();return 0;}bool Client::InitSock() //初始socket{WSADATA wsData;WORD wr=MAKEWORD(2,2);if(WSAStartup(wr,&wsData)==0){return true;}return false;}u_long Client::ResolveAdress(char *serverIp) //解析IP地址{u_long nAddr=inet_addr(serverIp);if(nAddr==INADDR_NONE) //表明serverIp使用的是主机名形式{hostent *ent=gethostbyname(serverIp);if(ent==NULL){cout<<"获取主机名出错"<<WSAGetLastError()<<endl;}else{nAddr=*((u_long *)ent->h_addr_list[0]);}}if(nAddr==INADDR_NONE){cout<<"解析主机地址失败"<<endl;}return nAddr;}SOCKET Client::ConnectServer(u_long serverIp,int port) //连接服务器{sd=socket(AF_INET,SOCK_STREAM,0);if(sd==INVALID_SOCKET){cout<<"床架套接字失败"<<endl;return INVALID_SOCKET;}sockaddr_in saServer;saServer.sin_family=AF_INET;saServer.sin_addr.S_un.S_addr=serverIp;saServer.sin_port=htons(port);if(connect(sd,(sockaddr*)&saServer,sizeof(sockaddr_in))==SOCKET_ERROR){cout<<"连接服务器失败"<<WSAGetLastError()<<endl;closesocket(sd);return INVALID_SOCKET;}return sd;}bool Client::ProcessConnection(SOCKET sd) //进行通信{//-------------------------------------------------//可以将下面代码看做设置系统缓冲区int nRecvBuf=1024000;//设置为1000K setsockopt(sd,SOL_SOCKET,SO_RCVBUF,(const char*)&nRecvBuf,sizeof(int)); //发送缓冲区 int nSendBuf=1024000;//设置为1000K setsockopt(sd,SOL_SOCKET,SO_SNDBUF,(const char*)&nSendBuf,sizeof(int));//---------------------------------------------------------while(true){cout<<"(1)向服务器传送文件"<<endl;cout<<"(2)从服务器下载文件"<<endl;cout<<"(3)退出业务"<<endl;int n;loop:cin>>n;switch(n){case 1:{//向服务器发送传送文件消息Message::MsgSendFile msgSendFile;if(send(sd,(char *)&msgSendFile,sizeof(Message::MsgSendFile),0)==SOCKET_ERROR){cout<<"发送消息失败"<<endl;return false;}Sleep(10); //睡眠10ms保证对方将发送的消息取走char filePath[MAX_FILE_NAME_LENGTH];cout<<"请输入文件路径如:F:/a/b.jpg"<<endl;cin>>filePath;char fileDrive[_MAX_DRIVE];char fileDir[_MAX_DIR];char fileName[_MAX_FNAME];char fileExt[_MAX_EXT];_splitpath(filePath,fileDrive,fileDir,fileName,fileExt); //将文件路径解析Message::MsgFileName msgFileName;strcat(fileName,fileExt);strcpy(msgFileName.fileName,fileName);if(send(sd,(char *)&msgFileName,sizeof(Message::MsgFileName),0)==SOCKET_ERROR) //发送文件名{cout<<"发送文件名出错"<<WSAGetLastError()<<endl;}Sleep(10); if(!SendFileLength(sd,filePath)) //发送文件长度{cout<<"发送文件长度出错"<<endl;return false;}Sleep(10);if(!SendFile(sd,filePath)) //发送文件{cout<<"发送文件出错"<<endl;return false;}}break;case 2:{Message::MsgDownLoadFile msgDownLoadFile;if(send(sd,(char *)&msgDownLoadFile,sizeof(Message::MsgDownLoadFile),0)==SOCKET_ERROR){cout<<"发送下载文件消息失败"<<WSAGetLastError()<<endl;return false;}if(!RecvCatalogInfo(sd)){return false;}if(!SendDownLoadFileName(sd)){return false;}if(!ReceiveFileLength(sd)){return false;}if(!ReceiveFileName(sd)){return false;}if(!ReceiveFile(sd)){return false;}}break;case 3:break;default:cout<<"你输入的不符合要求,重新输入"<<endl;goto loop;}}return true;}bool Client::SendFileLength(SOCKET sd,char *filePath){FILE *pFile;pFile=fopen(filePath,"r+b");fseek(pFile,0,SEEK_END);nFileLength=_ftelli64(pFile);Message::MsgFileLength msgFileLength;msgFileLength.fileLength=nFileLength;fclose(pFile);if(send(sd,(char *)&msgFileLength,sizeof(Message::MsgFileLength),0)==SOCKET_ERROR){return false;}return true;}bool Client::SendFile(SOCKET sd,char *filePath) //发送文件{cout<<"进入到发送文件内容"<<endl;Message::MsgFile msgFile;if(send(sd,(char *)&msgFile,sizeof(Message::MsgFile),0)==SOCKET_ERROR){ cout<<"发送文件消息出错"<<WSAGetLastError()<<endl;return false;}Sleep(10);FILE *pFile;pFile=fopen(filePath,"r+b");fseek(pFile,0,SEEK_SET); //定位到文件首位置_int64 i=0;char buff[MAX_PACK_SIZE];while(i<nFileLength){int nSize;if(i+MAX_PACK_SIZE>nFileLength){nSize=(int)(nFileLength-i);}else{nSize=MAX_PACK_SIZE-1;}fread(buff,sizeof(char),nSize,pFile);int nSend;nSend=send(sd,buff,nSize,0);if(nSend==SOCKET_ERROR){cout<<"发送失败"<<endl;return false;}i+=nSend;fseek(pFile,-(nSize-nSend),SEEK_CUR); //定位到实际已发送到的位置memset(buff,0,sizeof(char)*MAX_PACK_SIZE); //将buff清空}fclose(pFile);return true;}bool Client::RecvCatalogInfo(SOCKET sd) //接收目录信息{int flag=1; //接收目录信息成功标志char buff[MAX_PACK_SIZE];Message::MsgHead *msgHead; while(true){if(recv(sd,buff,MAX_PACK_SIZE,0)==SOCKET_ERROR){cout<<"接收目录信息失败"<<WSAGetLastError()<<endl;flag=0;break;}msgHead=(Message::MsgHead *)buff;if(msgHead->msgId==MSG_COMPLETE) //判断消息是否是标准消息{cout<<"目录信息发送完成"<<endl;break;}else{cout<<buff<<endl; //发送来的是目录信息,即文件名}}if(flag==0){return false;}return true;}bool Client::SendDownLoadFileName(SOCKET sd) //发送下载的文件名{cout<<"请输入你要下载的文件名"<<endl;char fileName[_MAX_FNAME+_MAX_EXT];cin>>fileName;Message::MsgFileName msgFileName;strcpy(msgFileName.fileName,fileName);if(send(sd,(char *)&msgFileName,MAX_PACK_SIZE,0)==SOCKET_ERROR){cout<<"发送下载文件名出错"<<WSAGetLastError()<<endl;return false;}return true;}bool Client::ReceiveFileLength(SOCKET sd) //接收下载的文件长度{char buff[MAX_PACK_SIZE];Message::MsgFileLength *msgFileLength;if(recv(sd,buff,MAX_PACK_SIZE,0)==SOCKET_ERROR){cout<<"接收文件长度失败"<<WSAGetLastError()<<endl;return false;}msgFileLength=(Message::MsgFileLength *)buff;nFileLength=msgFileLength->fileLength;cout<<"接收到文件长度"<<nFileLength<<endl;return true;}bool Client::ReceiveFileName(SOCKET sd) //接收下载的文件名{char buff[MAX_PACK_SIZE];memset(fileName,0,sizeof(char)*(_MAX_FNAME+_MAX_EXT));Message::MsgFileName *msgFileName;if(recv(sd,buff,MAX_PACK_SIZE,0)==SOCKET_ERROR){cout<<"接收文件名出错"<<endl;return false;}msgFileName=(Message::MsgFileName *)buff;strcpy(fileName,msgFileName->fileName);cout<<"接收到文件名"<<fileName<<endl;return true;}bool Client::ReceiveFile(SOCKET sd) //接收文件内容{ char buff[MAX_PACK_SIZE]; FILE *pFile; pFile=fopen(fileName,"a+b"); _int64 i=0; while(i+1<nFileLength) {int nRecv=recv(sd,buff,MAX_PACK_SIZE,0); if(nRecv==SOCKET_ERROR){ return false;}fwrite(buff,sizeof(char),nRecv,pFile);i+=nRecv; memset(buff,0,sizeof(char)*MAX_PACK_SIZE);}fclose(pFile);return true;}void Client::CloseSocket() //关闭套接字{closesocket(sd);WSACleanup();}
0 0
- C++利用socket的客户端和服务器之间传输文件
- java用socket客户端和服务器之间通信,传输文件经典例子(详细分析)
- C# 利用Socket类实现客户端和服务器之间的通信,可在本机之间实现信息交互
- socket服务器、客户端传输
- Socket异步服务器,可以监控客户端的状态,功能有,文字测试,服务端向客户端传输屏幕录像(UDP传输)、监控客户端屏幕(UDP传输),抖动用户窗体、发送文件给用户、扫描客户的C盘目录。
- 利用socket实现服务器和客户端的远程桌面
- 用Scp传输本地和linux服务器之间的文件
- Java Socket服务器端和客户端之间传输对象
- Java Socket客户端服务器之间的文件传输
- 服务端和Android客户端利用Socket传输JSON数据
- 利用Socket在不用服务器间传输文件
- Android:客户端和服务器之间传输数据加密
- Android:客户端和服务器之间传输数据加密
- Android:客户端和服务器之间传输数据加密
- 服务器与客户端之间的远程图片传输
- json在服务器与客户端之间传输的一篇文章
- 利用java socket传输文件
- java 利用socket传输文件
- C语言 打印菱形(可变行数)
- MySQL中函数CONCAT及GROUP_CONCAT
- poj 2230 Watchcow(欧拉回路)
- 后缀数组代码理解加注释
- 算法分析与设计-动态规划0
- C++利用socket的客户端和服务器之间传输文件
- Spring Data JPA使用JpaRepository自动装配报No qualifying bean of type错误
- 51nod 1065 最小正子段和(前缀和)
- C++ hdu 2026 首字母大写
- 判断一棵二叉树是否是另一棵二叉树的子树
- 【NOIP 模拟题】[T1]return(模拟)
- 19、Jquery入门
- 51nod 1267 4个数和为0
- Spring Data JPA配置出现Not a managed type错误