linux C FTP 实验报告Word格式.docx
《linux C FTP 实验报告Word格式.docx》由会员分享,可在线阅读,更多相关《linux C FTP 实验报告Word格式.docx(24页珍藏版)》请在冰点文库上搜索。
一、实验目的
按照教学计划,本课程是在高级语言程序设计、数据结构、计算机网络等课程之后开设的。
要求初步掌握TCP/IP协议的体系结构;
掌握网络编程开发流程;
掌握基本的网络程序的编写方法,培养分析问题和解决问题的能力。
二、实验内容与要求
实验内容:
本课程的实验是一个综合性设计实验:
基于linux的FTPServer+client,通过本实验主要检验学生对TCP/IP网络协议的了解,阅读RFC959,熟悉ftp协议;
进一步加强对C语言及linux系统调用的掌握,本实验涉及到:
linux系统、GCC、GDB、VI、linuxsocket网络编程、文件操作、流传输、进程控制与进程通信、存储管理、多线程技术等多方面专业知识的综合掌握情况。
实验要求:
1开发平台:
ubuntu11.04+vi+gcc
2、要求:
1)下载并认真阅读RFC959,了解FTP的具体内容、功能及标准;
2)实现FTP服务的基本功能,如获取目录内容、上传、下载、用户管理、文件管理、匿名登录等:
3)尽力实现扩展功能,如断点续传等。
三、主要仪器设备
1、已连接网络的计算机。
2、所使用的计算机安装了ubuntu版本的linux系统。
四、实验内容
服务器端
客户端
数据的上传、下载
Linux系统下,用文本编辑器编写ftp客户端与服务器端的C语言代码,另外几个包含的头文件。
下面是在ftp客户端和服务器功能实现中比较重要的代码。
Main主函数定义一些相关的变量等代码:
intmain(intargc,char**argv)
{
intsockfd;
intclientfd;
uint16_tport;
intret;
pid_tpid;
structsockaddr_inserver_addr;
if(2!
=argc){
printf("
usage:
commandlisten_port\n"
);
return-1;
}
port=atoi(argv[1]);
server_addr.sin_family=AF_INET;
server_addr.sin_addr.s_addr=INADDR_ANY;
server_addr.sin_port=htons(port);
sockfd=socket(PF_INET,SOCK_STREAM,0);
if(sockfd<
0)
{
perror("
opendatastreamsocketfailed!
\n"
}
ret=bind(sockfd,(structsockaddr*)&
server_addr,sizeof(server_addr));
if(ret<
0)
{
binddatasocketfailed!
ret=listen(sockfd,SOMAXCONN);
if(ret<
listeningdatastreamfailed!
正在等待客户端到链接...\n"
while
(1)
clientfd=accept(sockfd,NULL,NULL);
if(clientfd<
acceptdataconnectionerror!
pid=fork();
if(pid<
0){
forkerror!
if(0==pid){
//chidprocess
oneclientcome...\n"
serv_client(clientfd);
return0;
close(clientfd);
}
处理服务器的请求
inthandle_request(msg_head_ctrl_t*msg,intsockfd);
voidserv_client(intsockfd)
msg_head_ctrl_t*msg;
ssize_tsize;
;
uint32_tbody_len;
uint32_ttotal_len;
fd_setfs_client;
structtimevaltimeout;
等待服务器请求
while
(1){
FD_ZERO(&
fs_client);
FD_SET(sockfd,&
timeout.tv_sec=DEFAULT_TIME_OUT;
timeout.tv_usec=0;
ret=select(sockfd+1,&
fs_client,NULL,NULL,&
timeout);
if(0==ret){
//timeout
timeout....\n"
return;
if(-1==ret){
continue;
接收服务器的请求信息
size=recv(sockfd,&
body_len,sizeof(uint32_t),MSG_PEEK);
if(size<
recvmsgerror!
if(size==0){
clientclosetheconnection\n"
转换网络字节为本地字节
total_len=ntohl(body_len)+sizeof(msg_head_ctrl_t);
msg=malloc(total_len+1);
if(NULL==msg){
mallocerror!
memset(msg,0,total_len+1);
size=recv(sockfd,msg,total_len,0);
if(size!
=total_len){
recvmsgbodyfailed!
msg->
body_len=ntohl(msg->
body_len);
command=ntohl(msg->
command);
//printf("
len=%d,msg=%s\n"
msg->
body_len,msg->
msg_body);
如果服务器出现quit的时候就推出
if(COMMAND_QUIT==msg->
command){
clientclosedconnection!
close(sockfd);
处理下载请求
ret=handle_request(msg,sockfd);
if(SOCK_ERROR==ret){
return;
free(msg);
处理客户端的下载
inthandle_get(msg_head_ctrl_t*msg,intsockfd)
intfd;
boolexist;
msg_head_ctrl_t*ack_msg;
ssize_tread_bytes;
ssize_tsent_bytes;
检查所需下载的文件所否存在
exist=file_exist(msg->
msg_body);
%s,%d"
msg_body,exist);
if(false==exist){
File%sdoesn'
texist!
msg->
body_len=msg->
body_len;
body_len=htonl(msg->
command=htonl(COMMAND_NO_FILE);
ret=send(sockfd,msg,sizeof(msg_head_ctrl_t)+body_len,0);
if((sizeof(msg_head_ctrl_t)+body_len)!
=ret){
senderror,%s:
%d"
__FUNCTION__,__LINE__);
returnSOCK_ERROR;
returnFAILED;
传送下载数据
while(true){
read_bytes=read(fd,ack_msg->
msg_body,MAX_READ_BYTES);
if(read_bytes>
//printf("
len%d,%d\n"
read_bytes,ack_msg->
ack_msg->
body_len=htonl(read_bytes);
command=htonl(msg->
ret=SUCCESSFUL;
elseif(-1==read_bytes){
read_bytes=0;
body_len=0;
command=htonl(COMMAND_ERROR_FILE);
ret=FAILED;
elseif(0==read_bytes){//传送完退出
command=htonl(COMMAND_END_FILE);
sent_bytes=send(sockfd,ack_msg,read_bytes+sizeof(msg_head_ctrl_t),0);
if(sent_bytes!
=(read_bytes+sizeof(msg_head_ctrl_t))){
ret=SOCK_ERROR;
senddataerror!
%s:
break;
if(0==ack_msg->
body_len){
close(fd);
returnret;
处理显示服务端目录内容和打印服务端路径
inthandle_ls_pwd(msg_head_ctrl_t*msg,intsockfd)
FILE*file;
size_tread_bytes;
size_tret;
%s\n"
file=popen(msg->
msg_body,"
r"
if(NULL==file){
executecommandfailed!
%s\n"
ack_msg=malloc(sizeof(msg_head_ctrl_t)+MAX_READ_BYTES);
if(NULL==ack_msg){
outofmemory!
command=htonl(msg->
command);
read_bytes=fread(ack_msg->
msg_body,1,MAX_READ_BYTES,file);
if(ferror(file)){
ret=send(sockfd,ack_msg,read_bytes+sizeof(msg_head_ctrl_t),0);
if((read_bytes+sizeof(msg_head_ctrl_t))!
=ret){
sockerror!
if(feof(file)){
sendover!
pclose(file);
inthandle_request(msg_head_ctrl_t*msg,intsockfd)
{char*cmd;
switch(msg->
command){
caseCOMMAND_CD:
//处理cd命令
cmd=trim_all_space(msg->
msg_body+2);
//skip"
cd"
charatcer
ret=chdir(cmd);
%s,|%s|\n"
strerror(errno),cmd);
caseCOMMAND_LS:
caseCOMMAND_PWD:
ret=handle_ls_pwd(msg,sockfd);
caseCOMMAND_GET:
ret=handle_get(msg,sockfd);
caseCOMMAND_PUT:
default:
4.2.2、实现客户端功能的主要代码编写:
建立套接字
sockfd=socket(PF_INET,SOCK_STREAM,0);
if(sockfd<
datastreamsocketcreatefailed!
server.sin_family=AF_INET;
port=atoi(argv[2]);
server.sin_port=htons(port);
ret=inet_pton(AF_INET,argv[1],&
server.sin_addr.s_addr);
if(ret<
=0){
youripaddressisunvalide!
usage();
链接到服务端
ret=connect(sockfd,(structsockaddr*)&
server,sizeof(structsockaddr_in));
dataconnectionisfailed!
connecttoserversuccessfully!
clinet_process(sockfd);
//客户端进程函数调用
处理服务端信息
inthandle_server_ack(sockfd)
接受服务器端的请求
ret=recv(sockfd,&
body_len,sizeof(body_len),MSG_PEEK);
if(ret<
connectionnlost...\n"
exit(-1);
body_len=ntohl(body_len);
total_len=body_len+sizeof(msg_head_ctrl_t);
msg=malloc(total_len+1);
if(NULL==msg){
outofmemeory\n"
memset(msg,0,total_len+1);
ret=recv(sockfd,msg,total_len,MSG_WAITALL);
if((COMMAND_LS==msg->
command)||(COMMAND_PWD==msg->
command)){
\n%s\n"
elseif(COMMAND_GET==msg->
save_file_to_disk(msg->
把命令传送到服务端
intsend_command_to_server(intsockfd,char*user_input,command_type_ttype)
ssize_tret;
intbody_len;
inttotal_len;
body_len=strlen(user_input);
msg=malloc(total_len);
outofmemeory!
command=htonl(type);
body_len=htonl(body_len);
memcpy(msg->
msg_body,user_input,body_len);
ret=send(sockfd,msg,total_len,0);
total_len){
connectionlost...\n"
returnSUCCESSFUL;
在客户端中下载文件功能
intget_file_from_server(intsockfd,char*user_input,command_type_ttype)
intfd=-1;
uint32_tlen;
ret=send_command_to_server(sockfd,user_input,type);
if(ret!
=SUCCESSFUL){
msg=malloc(sizeof(msg_head_ctrl_t)+MAX_READ_BYTES+1);
timeout.tv_sec=DEFAULT_CLIENT_TIME_OUT;
select是处理多用户情况
fs_client,NULL,NULL,NULL);
memset(msg,0,sizeof(msg_head_ctrl_t)+MAX_READ_BYTES+1);
ret=recv(sockfd,&
len,sizeof(msg->
body_len),MSG_PE