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
原创粉丝点击