//服务器的代码文件有
/*
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();
}