//服务器的代码文件有 /* message.h source.h source.cpp server.h server.cpp */ //客户端的代码文件有 /* message.h 和服务器端一样 client.h client.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 10000 using namespace std; class Server { public: SOCKET sd; _int64 fileLength; char fileName[MAX_FILE_NAME_LENGTH]; bool InitSock(); //初始winsocket SOCKET 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 10000 class Client { public: _int64 nFileLength; char fileName[_MAX_FNAME+_MAX_EXT]; SOCKET sd; bool InitSock(); //初始化winsock u_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(); }