📄 server.c
字号:
//SFTPWinSever.cpp
#include"define.h"
#include<stdio.h>
#include<winsock2.h>
#pragma comment(lib,"ws2_32.lib")
//创建线程时传递的数据结构,内涵控制连接套接子和客户端地址信息
struct threadData
{
SOCKET tcps;
sockaddr_in clientaddr;
};
//全局函数声明
//ftp初始化,创建一个侦听套接字
int InitFTP(SOCKET *pListenSock);
int InitDataSocket(SOCKET *pDatatcps,SOCKADDR_IN *pClientAddr);
int ProcessCmd(SOCKET tcps,CmdPacket *pCmd,SOCKADDR_IN *pClientAddr);
int SendRspns(SOCKET tcps,RspnsPacket *prspns);
int RecvCmd(SOCKET tcps,char *pCmd);
int SendFileList(SOCKET datatcps);
int SendFileRecord(SOCKET datatcps,WIN32_FIND_DATA *pfd);
int SendFile(SOCKET datatcps,FILE *file);
int RecvFile(SOCKET datatcps,char *filename);
int FileExists(const char *filename);
//线程函数,参数包括相应控制连接的套接字
DWORD WINAPI ThreadFunc(LPVOID lpParam)
{
SOCKET tcps;
sockaddr_in clientaddr;
tcps=((threadData *)lpParam)->tcps;
clientaddr=((threadData *)lpParam)->clientaddr;
printf("socket id is %u.\n",tcps);
//发送回复报文给客户端,内含命令使用说明
printf("Serve client %s:%d\n",inet_ntoa(clientaddr.sin_addr),ntohs(clientaddr.sin_port));
RspnsPacket rspns={OK,
"connection ready!\n"
"type 'help' for assitant.\n"
};
SendRspns(tcps,&rspns);
//循环获取客户端命令报文并进行处理
for(;;)
{
CmdPacket cmd;
if(!RecvCmd(tcps,(char *)&cmd))
break;
if(!ProcessCmd(tcps,&cmd,&clientaddr))
break;
}
//线程结束前关闭控制连接套接字
closesocket(tcps);
delete lpParam;
return 0;
}
int main(int argc,char *argv[])
{
SOCKET tcps_listen;//ftp服务器控制连接侦听套接字
struct threadData *pThInfo;
if(!InitFTP(&tcps_listen))//ftp初始化
return 0;
printf("Mini FTP Sever listening on %d port...\n",CMD_PORT);
//循环接受客户端连接请求,并声成现程去处理
for(;;)
{
pThInfo=NULL;
pThInfo=new threadData;
if(pThInfo==NULL)
{
printf("malloc space failed!\n");
continue;
}
int len=sizeof(struct threadData);
//等待接受客户端控制连接请求
pThInfo->tcps=accept(tcps_listen,(SOCKADDR *)&pThInfo->clientaddr,&len);
//创建一个线程来处理相应客户端的请求
DWORD dwThreadId,dwThrdparam=1;
HANDLE hThread;
hThread=CreateThread(NULL,0,ThreadFunc,pThInfo,0,&dwThreadId);
//check the return value for success
if(hThread==NULL)
{
printf("CreateThread failed\n");
closesocket(pThInfo->tcps);
delete pThInfo;
}
}
return 0;
}
//ftp初始化,创建一个侦听套接字
int InitFTP(SOCKET *pListenSock)
{
//these steps are necessary to use winsock
//startup->socket->bind->listen
WORD wVersionRequested;
WSADATA wsaData;
int err;
SOCKET tcps_listen;
wVersionRequested=MAKEWORD(2,2);
err=WSAStartup(wVersionRequested,&wsaData);
if(err!=0)
{
printf("winsock初始化时发生错误!\n");
return 0;
}
if(LOBYTE(wsaData.wVersion)!=2||HIBYTE(wsaData.wVersion)!=2)
{
WSACleanup();
printf("无效winsock版本!\n");
return 0;
}
tcps_listen=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if(tcps_listen==INVALID_SOCKET)
{
WSACleanup();
printf("创建socket失败!\n");
return 0;
}
SOCKADDR_IN tcpaddr;
tcpaddr.sin_family=AF_INET;
tcpaddr.sin_port=htons(CMD_PORT);
tcpaddr.sin_addr.S_un.S_addr=htonl(INADDR_ANY);
err=bind(tcps_listen,(SOCKADDR *)&tcpaddr,sizeof(tcpaddr));
if(err!=0)
{
err=WSAGetLastError();
WSACleanup();
printf("socket绑定时发生错误!\n");
return 0;
}
err=listen(tcps_listen,3);
if(err!=0)
{
WSACleanup();
printf("socket监听时错误!\n");
return 0;
}
*pListenSock=tcps_listen;
return 1;
}
//建立数据连接
//pDatatcps 用于存储数据连接套接字
//pClientAddr 指向客户端的控制连接套接字地址,需使用其中的ip地址
//返回值 0表示失败 1正常
int InitDataSocket(SOCKET *pDatatcps,SOCKADDR_IN *pClientAddr)
{
SOCKET datatcps;
//创建socket
datatcps=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if(datatcps==INVALID_SOCKET)
{
printf("creating data socket failed!\n");
return 0;
}
SOCKADDR_IN tcpaddr;
memcpy(&tcpaddr,pClientAddr,sizeof(SOCKADDR_IN));
tcpaddr.sin_port=htons(DATA_PORT);//只修改端口值
//请求连接客户端
if(connect(datatcps,(SOCKADDR*)&tcpaddr,sizeof(tcpaddr))==SOCKET_ERROR)
{
printf("connecting to client failed!\n");
closesocket(datatcps);
return 0;
}
*pDatatcps=datatcps;
return 1;
}
//处理命令报文
//tcps 控制连接套接字
//pcmd 指向待处理命令保文
//pClientAddr 指向客户端控制连接套接字地址
//返回值 0表示有错或需要结束连接 1正常
int ProcessCmd(SOCKET tcps,CmdPacket *pCmd,SOCKADDR_IN *pClientAddr)
{
SOCKET datatcps;//数据连接套接字
RspnsPacket rspns;//回复报文
FILE *file;
//根据命令类型分派执行
switch(pCmd->cmdid)
{
case LS:
//首先建立数据连接
if(!InitDataSocket(&datatcps,pClientAddr))
return 0;
//发送文件列表信息
if(!SendFileList(datatcps))
return 0;
break;
case PWD:
rspns.rspnsid=OK;
//获取当前目录,并放至回复报文中
if(!GetCurrentDirectory(RSPNS_TEXT_SIZE,rspns.text))
strcpy(rspns.text,"can't get current dir!\n");
if(!SendRspns(tcps,&rspns)) return 0;
break;
case CD:
//设置当前目录,使用win32 API接口函数
if(SetCurrentDirectory(pCmd->param))
{
rspns.rspnsid=OK;
if(!GetCurrentDirectory(RSPNS_TEXT_SIZE,rspns.text))
strcpy(rspns.text,"CD succeed!But can't get current dir!\n");
}
else
{
strcpy(rspns.text,"can't change to that dir!");
}
if(!SendRspns(tcps,&rspns))//发送回复报文
return 0;
break;
case GET:
//处理下载文件请求
file=fopen(pCmd->param,"rb");//打开下载的文件
if(file)
{
rspns.rspnsid=OK;
sprintf(rspns.text,"get file %s\n", pCmd->param);
if(!SendRspns(tcps,&rspns))
{
fclose(file);
return 0;
}
else
{
//创建额外数据连接传送数据
if(!InitDataSocket(&datatcps,pClientAddr))
{
fclose(file);
return 0;
}
if(!SendFile(datatcps,file))
return 0;
fclose(file);
}
}
else//打开文件失败
{
rspns.rspnsid=ERR;
strcpy(rspns.text,"can't open file!\n");
if(!SendRspns(tcps,&rspns))
return 0;
}
break;
case PUT://处理上传文件请求
//首先发送回复报文
char filename[64];
strcpy(filename,pCmd->param);
//verify no file with same exits to make sure that nho file will bi overwritten
if(FileExists(filename))
{
rspns.rspnsid=ERR;
sprintf(rspns.text,"remote file named %s exits!\n",filename);
if(!SendRspns(tcps,&rspns))
return 0;
}
else
{
rspns.rspnsid=OK;
if(!SendRspns(tcps,&rspns))
return 0;
//另建一个数据连接来接收数据
if(!InitDataSocket(&datatcps,pClientAddr))
return 0;
if(!RecvFile(datatcps,filename))
return 0;
}
break;
case QUIT:
printf("Thanks for using! \nconnection turned off!\n");
rspns.rspnsid=OK;
strcpy(rspns.text,"Thanks for using!\n xiaOe6521@yahoo.com.cn\n hainanwei@stu.xjtu.edu.cn\n");
SendRspns(tcps,&rspns);
return 0;
}
return 1;
}
//发送回复报文
int SendRspns(SOCKET tcps,RspnsPacket *prspns)
{
if(send(tcps,(char *)prspns,sizeof(RspnsPacket),0)==SOCKET_ERROR)
{
printf("lost the connection to client!\n");
return 0;
}
return 1;
}
//接收命令报文
//tcps 控制连接套接字
//pCmd 用于存储返回的命令报文
//返回值 0表示有错或连接已经断开,1表示正常
int RecvCmd(SOCKET tcps,char *pCmd)
//used to receive command from client
{
int nRet;
int left=sizeof(CmdPacket);
//从控制连接中读取数据,大小为sizeof(CmdPacket)
while(left)
{
nRet=recv(tcps,pCmd,left,0);
if(nRet==SOCKET_ERROR)
{
printf("error occurs when receiving command from client!\n");
return 0;
}
if(!nRet)
{
printf("connection is closed by client!\n");
return 0;
}
left-=nRet;
pCmd+=nRet;
}
return 1;//成功获取命令报文
}
//发送一项文件信息
int SendFileRecord(SOCKET datatcps,WIN32_FIND_DATA *pfd)
//used to send response to client
{
char filerecord[MAX_PATH+32];
FILETIME ft;
FileTimeToLocalFileTime(&pfd->ftLastWriteTime,&ft);
SYSTEMTIME lastwtime;
FileTimeToSystemTime(&ft,&lastwtime);
char *dir=pfd->dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY?"<DIR>":"";
sprintf(filerecord,"%04d-%02d-%02d%02d:%02d %5s %10d %-20s\n",
lastwtime.wYear,
lastwtime.wMonth,
lastwtime.wDay,
lastwtime.wHour,
lastwtime.wMinute,
dir,
pfd->nFileSizeLow,
pfd->cFileName);
if(send(datatcps,filerecord,strlen(filerecord),0)==SOCKET_ERROR)
{
printf("Error occurs when sending file list!\n");
return 0;
}
return 1;
}
//发送文件列表信息
//datatcps 时局连接套接字
//返回值 0表示有值 1正常
int SendFileList(SOCKET datatcps)
{
HANDLE hff;
WIN32_FIND_DATA fd;
//搜索文件
hff=FindFirstFile("*",&fd);
if(hff==INVALID_HANDLE_VALUE)//发生错误
{
const char *errstr="can't list files!\n";
printf("list file error!\n");
if(send(datatcps,errstr,strlen(errstr),0)==SOCKET_ERROR)
{
printf("error occurs when senging file list!\n");
}
closesocket(datatcps);
return 0;
}
BOOL fMoreFiles=TRUE;
while(fMoreFiles)
{
//发送此项文件信息
if(!SendFileRecord(datatcps,&fd))
{
closesocket(datatcps);
return 0;
}
//搜索下一个文件
fMoreFiles=FindNextFile(hff,&fd);
}
closesocket(datatcps);
return 1;
}
//通过数据连接发送文件
int SendFile(SOCKET datatcps,FILE* file)
{
char buf[1024];
printf("sending file data..");
for(;;)
//从文件中循环读取数据并发送客户端
{
int r=fread(buf,1,1024,file);
if(send(datatcps,buf,r,0)==SOCKET_ERROR)
{
printf("lost thr connection to client!\n");
closesocket(datatcps);
return 0;
}
if(r<1024)//文件传送结束
break;
}
closesocket(datatcps);
printf("done\n");
return 1;
}
//接受文件
//datatcps 数据连接套接字,通过它来接收数据
//filename 用于存放数据的文件名
int RecvFile(SOCKET datatcps,char* filename)
{
char buf[1024];
FILE* file=fopen(filename,"wb");
if(!file)
{
printf("error occurs when open file to write!\n");
fclose(file);
closesocket(datatcps);
return 0;
}
//循环接受所有数据,并写往文件
printf("receiving file data...");
while(1)
{
int r=recv(datatcps,buf,1024,0);
if(r==SOCKET_ERROR)
{
printf("error occurs when receiving file from client!\n");
fclose(file);
closesocket(datatcps);
return 0;
}
if(!r)//数据传送结束
break;
fwrite(buf,1,r,file);
}
fclose(file);
closesocket(datatcps);
printf("done\n");
return 1;
}
//监测文件是否存在
int FileExists(const char* filename)
{
WIN32_FIND_DATA fd;
if(FindFirstFile(filename,&fd)==INVALID_HANDLE_VALUE)
return 0;
return 1;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -