课程设计任务书
学生姓名:专业班级:
指导教师:工作单位:信息工程学院
题目:文件传输协议的设计与实现
初始条件:
Windows XP
C++,SOCKET
要求完成的主要任务:(包括课程设计工作量及其技术要求,以及说明书撰写等具体要求)
1.掌握TCP/IP 网络应用程序基本的设计方法;
2.用socket 编程接口编写两个程序,分别为客户程序(client.c)和服务器程序(server.c);
3.撰写课程设计说明书。装订后的课程设计说明书不少于10面(含封面、任务书、目录、正文、参考文献、成绩评定表、封底)。
时间安排:
6月18日查阅资料、方案论证
6月19日方案设计、调试
6月20日撰写课程设计说明书
6月21日答辩
指导教师签名:年月日
系主任(或责任教师)签名:年月日
运行正确的程序::
1.服务器源代码:
#include
#include
#include
using namespace std;
#pragma comment(lib, "wsock32.lib")
#define PORT 4523
char buf_send[1024];
char buf_rec[1024];
SOCKET sockSrv;
//socket初始化
DWORD CreateSocket()
{
WSADATA WSAData;//WSADATA结构被用来保存函数WSAStartup返回的Windows Sockets初始化信息if(WSAStartup(MAKEWORD(2,2),&WSAData)!=0)//WSAStartup完成winsock的初始化
{printf("socket initialize failed!\n");
return (-1);
}
sockSrv=socket(AF_INET,SOCK_STREAM,0);//定义为面向连接的,返回值送给sockSrv
if(sockSrv==SOCKET_ERROR)
{
printf("socket create failed ! \n");
WSACleanup();//中止Windows Sockets DLL的使用
return(-1);
}
SOCKADDR_IN addrSrv;//TCP/IP使用SOCKADDR_IN 定义地址
addrSrv.sin_addr.S_un.S_addr=htonl(INADDR_ANY);//计算机IP地址
addrSrv.sin_port=htons(PORT);//协议端口号
addrSrv.sin_family=AF_INET;//地址所属协议簇
//绑定端口
if(bind(sockSrv,(struct sockaddr FAR *)&addrSrv,sizeof(addrSrv))==SOCKET_ERROR)
{
printf("Bind Error");
return(-1);
}
return (1);
}
/*MAX_PATH是C语言运行时库中通过#define指令定义的一个宏常量,它定义了编译器所支持的最长全路径名的长度。
在VC++6.0中,_MAX_PATH的值为260。
*/
int SendFileRecord(SOCKET datatcps,WIN32_FIND_DATA *pfd)//用于回复给客户端
{
char filerecord[MAX_PATH+32];
FILETIME ft;
FileTimeToLocalFileTime(&pfd->ftLastWriteTime,&ft);//将一个FILETIME结构转换成本地时间SYSTEMTIME lastwtime;//系统时间
FileTimeToSystemTime(&ft,&lastwtime);//根据一个FILETIME结构的内容,装载一个SYSTEMTIME 结构
char *dir=pfd->dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY?"
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;
}
//发送主机文件目录
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";
cout<<"list file error!"< if(send(datatcps,errstr,strlen(errstr),0)==SOCKET_ERROR) { cout<<"error occurs when sending file list!"< } closesocket(datatcps); return 0; } BOOL fMoreFiles=TRUE;//BOOL型,返回值为大于0的整数时为TRUE,返回值为0时候,为FALSE,返回值为-1时为ERROR。 while(fMoreFiles) { //发送此项文件信息 if(!SendFileRecord(datatcps,&fd))//发送失败 { closesocket(datatcps); return 0; } //搜索下一个文件 fMoreFiles=FindNextFile(hff,&fd); } closesocket(datatcps); return 1; } //发送数据 int SendFile(SOCKET datatcps,FILE* file)//发送文件 { printf("sending file data.."); for(;;) //从文件中循环读取数据并发送客户端 { int r=fread(buf_send,1,1024,file); if(send(datatcps,buf_send,r,0)==SOCKET_ERROR) { printf("lost the connection to client!\n"); closesocket(datatcps); return 0; } if(r<1024)//文件传送结束 break; } closesocket(datatcps); printf("done\n"); return 1; } DWORD ProcessCmd() { if(listen(sockSrv,5)<0)//监听信号 { cout<<"Listen error!"< return(-1); } cout<<"Listening for the request……"< SOCKADDR_IN addrclient;//定义用于返回客户机端地址的结构 int len=(sizeof(SOCKADDR_IN)); while(1) { SOCKET sockconn=accept(sockSrv,(SOCKADDR*)&addrclient,&len);//接受请求,产生新的套接字 if(sockconn==INVALID_SOCKET) continue; else cout<<"connecting from client"< while(true) { char filename[20]; memset(buf_rec,0,1024); memset(buf_send,0,1024); if(recv(sockconn,buf_rec,1024,0)<=0) { break; } cout< if(strncmp(buf_rec,"dir",3)!=0&&strncmp(buf_rec,"get",3)!=0&&strncmp(buf_rec,"put",3)!= 0) continue;//有一个请求正确执行下面语句 if(strncmp(buf_rec,"dir",3)==0) { strcpy(buf_send,"dir-ing\n"); send(sockconn,buf_send,1024,0); SendFileList(sockconn);//发送当前所有文件名 }//dir if (strncmp(buf_rec,"get",3)==0) { strcpy(filename,buf_rec+4); cout< FILE *file; //处理下载文件请求 file=fopen(filename,"rb");//打开下载的文件 if(file) { sprintf(buf_send,"get file %s\n",filename); if(!send(sockconn,buf_send,1024,0)) {fclose(file); return 0;} else {//创建额外数据连接传送数据 if(!SendFile(sockconn,file)) return 0; fclose(file);} }//file else//打开文件失败 { strcpy(buf_send,"can't open file!\n"); if(send(sockconn,buf_send,1024,0)) return 0; } }//get 处理客户端的下载请求 if(strncmp(buf_rec,"put",3)==0) { FILE *fd; int count; strcpy(filename,buf_rec+4); fd=fopen(filename,"wb"); if(fd==NULL) { printf("open file %s for weite failed!\n",filename); continue; } sprintf(buf_send,"put file %s",filename); if(!send(sockconn,buf_send,1024,0)) { fclose(fd); return 0; } while((count=recv(sockconn,buf_rec,1024,0))>0) fwrite(buf_rec,sizeof(char),count,fd); fclose(fd); continue; }//put 处理客户端的上传请求 } } } int main() { CreateSocket(); ProcessCmd(); return(1); } 2. 客户端程序源代码: #include #include #include using namespace std;//使用名称空间std #pragma comment(lib, "wsock32.lib")//将WinLib.lib库加入到工程中进行编译 #define PORT 4523//定义端口号为4523 char send_str[1024]; char rec_str[1024]; char IP[20]; char filename[20]; SOCKET sockClient; SOCKADDR_IN addrServer;//定义表示地址的结构体addrServer,用来表示本地地址 //创建套接字 DWORD CreateSock() { //本地信息 addrServer.sin_family=AF_INET;//地址所属协议簇 //AF表示ADDRESS FAMILY 地址族 // htons的功能:将一个无符号短整型数值转换为网络字节序 addrServer.sin_port=htons(PORT);//协议端口号 WSADATA WSAData;//WSADATA结构被用来保存函数WSAStartup返回的Windows Sockets初始化信息WORD wVersionRequsdted; int err; wVersionRequsdted=MAKEWORD(2,2); err=WSAStartup(wVersionRequsdted,&WSAData); if(err!=0){ printf("sock init fail!\n"); return(-1); } cout<<"please input the IP of host:"; scanf("%s",&IP); addrServer.sin_addr.s_addr=inet_addr(IP);//计算机IP地址 return(1); } DWORD ConnectServer() //连接服务器 { sockClient=socket(AF_INET,SOCK_STREAM,0);//创建套接字,SOCK_STREAM为面向连接型 if(sockClient==SOCKET_ERROR) { printf("sock create fail! \n"); WSACleanup();//中止Windows Sockets DLL的使用. return(-1); } if(connect(sockClient,(struct sockaddr *)&addrServer,sizeof(addrServer))==SOCKET_ERROR)//如果请求建立连接错误 { printf("Connect fail \n"); memset(IP,0,20); return(-1); } return(1); } void help() { cout<<"help List:"< cout<<"dir………………………………directory list "< cout<<"get………………………………download files"< cout<<"put………………………………upload files "< cout<<"quit………………………………exit !"< } //list读取服务器列表 void list(SOCKET sock) { int nRead; while(true) { nRead=recv(sock,rec_str,1024,0);//从一个套接口接收数据 if(nRead==SOCKET_ERROR) { cout<<"read response error!"< exit(1); } if(nRead==0)//数据读取结束 break; //显示数据 rec_str[nRead]='\0'; printf("%s",rec_str); } } int SendFile(SOCKET datatcps,FILE* file)//SOCKET datatcps定义变量数据连接套接字 { cout<<"sending file data.."< for(;;) { int r=fread(send_str,1,1024,file);//从一个流中读数据 if(send(datatcps,send_str,r,0)==SOCKET_ERROR) { printf("lost the connection to client!\n"); closesocket(datatcps); return 0; } if(r<1024)//文件传送结束 break; } closesocket(datatcps);//关闭接口 printf("done\n"); return(1); } int Cprocess() { int count; char order[10]; char param[20]; char command[30]; FILE *fd; FILE *fd2; command[0]='\0'; CreateSock(); ConnectServer(); cout<<"please input order :"< memset(order,0,10);//初始化为0 memset(param,0,20);//初始化为0 memset(command,0,30);//初始化为0 memset(rec_str,0,1024);//初始化为0 memset(send_str,0,1024);//初始化为0 cin>>order; strcat(command,order); if(strncmp(order,"get",3)==0||strncmp(order,"put",3)==0)//输入请求,有一个输入要求正确,输入目标文件名 { cin>>param; strcat(command," "); strcat(command,param); } cout< strcpy(send_str,command); if(send(sockClient,send_str,sizeof(send_str),0)<0) { cout<<"send data error!"< closesocket(sockClient); WSACleanup(); return 0; } recv(sockClient,rec_str,1024,0);//接受链接数据,放入rec_str cout< if(strncmp(command,"quit",4)==0) { closesocket(sockClient); WSACleanup(); return 0; }//quit if(strncmp(rec_str,"dir",3)==0) { list(sockClient); }//dir if(strncmp(rec_str,"get",3)==0) { fd=fopen(param,"wb");//使用二进制方式创建并打开名为param的文件 if(fd==NULL) //打开失败 { printf("open file %s for weite failed!\n",param); return 0; } while((count=recv(sockClient,rec_str,1024,0))>0)//接收文件,放入rec_str { fwrite(rec_str,sizeof(char),count,fd);} fclose(fd); }//get if(strncmp(rec_str,"put",3)==0) { strcpy(filename,rec_str+9);//复制需发送的文件名称,赋给filename fd2=fopen(filename,"rb"); if(fd2)//假如读文件成功 { if(!SendFile(sockClient,fd2))//假如发送失败 { printf("send failed!"); return 0; } fclose(fd2); } else//打开文件失败 { strcpy(send_str,"can't open file!\n"); if(send(sockClient,send_str,1024,0)) return 0; } }//put closesocket(sockClient); WSACleanup(); return Cprocess(); } int main() { help(); Cprocess(); return 0; } 3.程序运行结果 一.正确功能实现 1.运行客户端,输入服务器正确IP地址,连接成功后,输入dir查看服务器 所在文件夹中的文件 2.用put命令发送文件p.txt,发送完毕,查看服务器所在文件夹,发现p.txt 存在 3.使用put命令 使用前,服务器所在文件如下 对话框中输入put p.txt 4.使用get命令 使用前,客户端所在文件夹文件如下图 在对话框中输入 get g.exe 再看文件夹,发现出现g.exe 以上三步完成后,看服务器端窗口显示 二.运行错误测试 1.运行客户端,输入错误的IP地址。输入请求后,显示框直接关闭 2.发送客户端文件夹中不存在的文件(c.txt)时,客户端显示框直接关闭,服 务器端显示为 3.下载服务器文件夹文件时,服务器端直接关闭,客户端显示框如下 4.输入错误指令时,客户端显示如下,显示后,无法输入任何文字 服务器显示如下