Linux下基于socket的文件传输程序设计 课程设计.docx
《Linux下基于socket的文件传输程序设计 课程设计.docx》由会员分享,可在线阅读,更多相关《Linux下基于socket的文件传输程序设计 课程设计.docx(37页珍藏版)》请在冰豆网上搜索。
Linux下基于socket的文件传输程序设计课程设计
课程设计报告
课程设计题目:
Linux下基于socket的文件传输程序设计
学院:
信
专业班级:
1
年级:
大
姓名:
学号:
2
完成时间:
201年1月2日
成绩:
指导教师:
课程设计指导教师评定成绩表
项目
分值
优秀
(100>x≥90)
良好
(90>x≥80)
中等
(80>x≥70)
及格
(70>x≥60)
不及格(x<60)
评分
参考标准
参考标准
参考标准
参考标准
参考标准
学习态度
15
学习态度认真,科学作风严谨,严格保证设计时间并按任务书中规定的进度开展各项工作
学习态度比较认真,科学作风良好,能按期圆满完成任务书规定的任务
学习态度尚好,遵守组织纪律,基本保证设计时间,按期完成各项工作
学习态度尚可,能遵守组织纪律,能按期完成任务
学习马虎,纪律涣散,工作作风不严谨,不能保证设计时间和进度
技术水平与实际能力
25
设计合理、理论分析与计算正确,实验数据准确,有很强的实际动手能力、经济分析能力和计算机应用能力,文献查阅能力强、引用合理、调查调研非常合理、可信
设计合理、理论分析与计算正确,实验数据比较准确,有较强的实际动手能力、经济分析能力和计算机应用能力,文献引用、调查调研比较合理、可信
设计合理,理论分析与计算基本正确,实验数据比较准确,有一定的实际动手能力,主要文献引用、调查调研比较可信
设计基本合理,理论分析与计算无大错,实验数据无大错
设计不合理,理论分析与计算有原则错误,实验数据不可靠,实际动手能力差,文献引用、调查调研有较大的问题
创新
10
有重大改进或独特见解,有一定实用价值
有较大改进或新颖的见解,实用性尚可
有一定改进或新的见解
有一定见解
观念陈旧
论文(计算书、图纸)撰写质量
50
结构严谨,逻辑性强,层次清晰,语言准确,文字流畅,完全符合规范化要求,书写工整或用计算机打印成文;图纸非常工整、清晰
结构合理,符合逻辑,文章层次分明,语言准确,文字流畅,符合规范化要求,书写工整或用计算机打印成文;图纸工整、清晰
结构合理,层次较为分明,文理通顺,基本达到规范化要求,书写比较工整;图纸比较工整、清晰
结构基本合理,逻辑基本清楚,文字尚通顺,勉强达到规范化要求;图纸比较工整
内容空泛,结构混乱,文字表达不清,错别字较多,达不到规范化要求;图纸不工整或不清晰
指导教师评定成绩:
指导教师签名:
年月日
课程设计指导教师评定成绩表
项目
分值
优秀
(100>x≥90)
良好
(90>x≥80)
中等
(80>x≥70)
及格
(70>x≥60)
不及格(x<60)
评分
参考标准
参考标准
参考标准
参考标准
参考标准
学习态度
15
学习态度认真,科学作风严谨,严格保证设计时间并按任务书中规定的进度开展各项工作
学习态度比较认真,科学作风良好,能按期圆满完成任务书规定的任务
学习态度尚好,遵守组织纪律,基本保证设计时间,按期完成各项工作
学习态度尚可,能遵守组织纪律,能按期完成任务
学习马虎,纪律涣散,工作作风不严谨,不能保证设计时间和进度
技术水平与实际能力
25
设计合理、理论分析与计算正确,实验数据准确,有很强的实际动手能力、经济分析能力和计算机应用能力,文献查阅能力强、引用合理、调查调研非常合理、可信
设计合理、理论分析与计算正确,实验数据比较准确,有较强的实际动手能力、经济分析能力和计算机应用能力,文献引用、调查调研比较合理、可信
设计合理,理论分析与计算基本正确,实验数据比较准确,有一定的实际动手能力,主要文献引用、调查调研比较可信
设计基本合理,理论分析与计算无大错,实验数据无大错
设计不合理,理论分析与计算有原则错误,实验数据不可靠,实际动手能力差,文献引用、调查调研有较大的问题
创新
10
有重大改进或独特见解,有一定实用价值
有较大改进或新颖的见解,实用性尚可
有一定改进或新的见解
有一定见解
观念陈旧
论文(计算书、图纸)撰写质量
50
结构严谨,逻辑性强,层次清晰,语言准确,文字流畅,完全符合规范化要求,书写工整或用计算机打印成文;图纸非常工整、清晰
结构合理,符合逻辑,文章层次分明,语言准确,文字流畅,符合规范化要求,书写工整或用计算机打印成文;图纸工整、清晰
结构合理,层次较为分明,文理通顺,基本达到规范化要求,书写比较工整;图纸比较工整、清晰
结构基本合理,逻辑基本清楚,文字尚通顺,勉强达到规范化要求;图纸比较工整
内容空泛,结构混乱,文字表达不清,错别字较多,达不到规范化要求;图纸不工整或不清晰
指导教师评定成绩:
指导教师签名:
年月日
摘要
线程(thread)技术早在60年代就被提出,但真正应用线程到操作系统中去,是在80年代中期。
为什么有了进程的概念后,还要再引入线程呢?
使用多线程到底有哪些好处?
使用多线程的理由之一是和进程相比,它是一种非常"节俭"的多任务操作方式。
在Linux系统下,启动一个新的进程必须分配独立的地址空间,建立众多的数据表来维护它的代码段、堆栈段和数据段。
而运行于一个进程中的多个线程,它们之间使用相同的地址空间,共享大部分数据,启动一个线程所花费的空间远远小于进程所花费的空间,而且,线程间彼此切换所需的时间也远远小于进程间所需要的时间。
使用多线程的理由之二是线程间方便的通信机制。
对不同进程来说,它们具有独立的数据空间,要进行数据的传递只能通过通信的方式进行,这种方式费时且很不方便。
由于同一进程下的线程之间共享数据空间,所以一个线程的数据可以直接为其它线程所用,这样快且方便。
在计算机中,凡是提供服务的一方我们称为服务端(Server),而接受服务的另一方我们称作客户端(Client)。
不过客户端及伺服端的关系不见得一定建立在两台分开的机器上,提供服务的伺服端及接受服务的客户端也有可能都在同一台机器上,这样在同一台机器上就同时扮演伺服端及客户端。
线程间方便的通信机制可以使得在我们在服务端和客户端方便的进行通信传输与各种操作,可以通过运用多线程机制方便实现上传、下载文件;增加、删除用户;以及在服务端进行文件的管理。
关键字:
多线程、socket通信、服务器和客户端
·1需求分析
这次课程设计的要求是在以Linux为内核的操作系统下,实现多线程文件传输系统功能模块。
系统模块分为服务器和客户端两部分,客户端实现对文件的上传、下载和查看服务器默认路径下的文件列表;服务器可以对文件进行管理操作,包括创建、删除和重命名等。
多线程文件传输是一种一对多或者多对多的关系,一般是一个服务器对应着多个客户端。
客户端通过socket连接服务器,服务器要为客户端创建一个单独进程(线程)监听每个客户端的请求。
创建好连接之后文件就可以通过流的形式传输。
linux内核中为我们提供了两种不同形式的读写流,包括read()、write()和send()、recv()。
客户机对文件的查看指令也是通过流传递给服务器,服务器根据请求类型返回不同相应流。
根据socket原理和特点绘画出链接流程图,将客户机与服务器的相互通信划分为不同的模块,每个模块负责独立的功能项。
服务器输入指令管理目录下的文件,createfilename是创建文件命令,renameoldnamenewname是删除文命令,deletefilename是删除文件命令,同时监听着客户端的请求;客户端向服务器发送上传、下载和查看请求,从而得到不同的相应,包括将文件下载到当前路径下,从当前路径下上传文件给服务器,列出服务器的文件列表。
·2socket通信原理
国际标准化组织(ISO)在1978年提出开放系统互连参考模型(OSI:
opensysteminterconnectionreferencemode),该模型是设计和描述网络通信的基本框架。
OSI采用分层的额结构化技术将通信网络分为7层,从低到高为物理层、数据链路层、网络层、传输层、会话层、表示层、应用层。
TCP/IP参考模型是由美国国防部创建,且发展至今最成功的通信协议模型,与OSI模型对应,它将网络功能分为4层,包括网络接口层、网络层、传输层和应用层,每一层都有对应的协议。
在传输层的主要协议是TCP协议和UDP协议。
socket连接就是基于TCP协议。
TCP是一种可靠地数据传输协议。
socket是一种套接口,它把网络地址和端口号信息放在一个结构体中,也就是套接字地址结构。
结构图如下:
通用套接口地址数据结构定义在头文件中,形式如下:
structsockaddr
{
uint8_tsa_len;
sa_family_tsa_family;
charsa_data[14];
};
IPv4套接口地址数据结构以socketaddr_in命名,定义在头文件中,形式如下:
structsocketaddr_in
{
unit8_tsin_len;
sa_family_tsin_family;
in_port_tsin_port;
structin_addrsin_addr;
unsignedcharsin_zero[8];
}
下图是TCP套接口通信工作流程图:
通信工作的大致流程:
1)服务器先用socket()函数来建立一个套接口,用这个套接口完成通信的监听及数据的收发。
2)服务器用bind()函数来绑定一个端口号和ip地址,是套接口与指定的端口号和ip关联。
3)服务器调用linsten()函数,是服务器的端口和Ip处于监听状态,等待网络中某一个客户机的连接请求。
4)客户机用socket()函数建立一个套接口,设定远程ip和端口
5)客户机调用connect()函数连接远程计算机指定的端口。
6)服务器调用accept()函数来接受远程计算机的连接请求,建立起与客户机之间的通信连接。
7)建立连接之后,客户机用write()函数(或send())想socket中写入数据。
也可以用read()函数(或recv()函数)赌气服务器发送来的数据。
8)服务器用read()函数(或recv()函数)来读取客户机发来的数据,也可以用write()函数(或send()函数)来发送数据。
9)完成通信以后,使用close()函数关闭socket连接。
·3详细设计过程
·3.1服务器端创建监听与文件管理
服务器负责的功能模块主要有两部分,一是对连接进来客户端所有线程的管理和服务器目录下的文件管理;二是创建线程来单独监听客户端的动作。
为了便于管理,我们创建两个user.txt和client.txt两个文档来分别负责服务器的连接和客户端的连接。
user.txt中存放了服务器名和密码。
client.txt存放了连接客户端名字和密码。
我们首先对服务器的创建有个监测,即在启动时先核实服务器的所有者username和密码password,将输入的用户、密码与user.txt中的用户密码比较,匹配成功则同意启动,否则return-1表失败。
接着创建一个socket套接口,绑定Ip设置客户端的最大连接数为10,然后创建一个sever线程来实现对服务器本身监听动作。
主体代码见最后
接下来创建线程完成对客户端的监听
监听等待连接:
while
(1)
{
sockdata=accept(sockfd,(structsockaddr*)0,(int*)0);
…………….
我们定义结构体:
structclient_t
{
pthread_ttid;
intconn_fd;
intused;
charname[20];
}p_client[10];
来存放每个客户端的socket信息、线程标识、使用号、连接号和客户名。
创建线程实现单独监听:
p_client[i].conn_fd=sockdata;
p_client[i].used=i;
strcpy(p_client[i].name,client_name);pthread_create(&p_client[i].tid,NULL,&client_conn,&p_client[i])
接下来是线程client_conn()的功能
监听客户端的功能完成。
·3.2客户端连接与文件传输
在客户端这边我们同样适用了检测机制,运行客户机时要将用户名、密码以及ip地址和端口号作为参数输进来,先建立与服务器的连接,然后将用户名和密码发送到服务端检测,如果检测失败则接收到一条拒绝信息,连接断开,如果检测成功则接收到一条确认信息,双方通信开始。
主体代码见最后:
·4结果演示
创建,改名,与删除
客服端响应并连接服务器
上传
下载
具体代码如下:
服务器:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#defineMAXBUF256
/*-------startoffileListfunctions----------*/
intfileSize(charfileName[]);
//文件信息
typedefstructfileinfo{
charname[256];
charfullName[1024];
intsize;
time_tmod_time;
chartype[10];
}fileinfo;
//文件列表
typedefstructfilelist
{
fileinfofile;
structfilelist*nextfile;
}fileList;
//functiongetfilelist
//输入目录名
//输出目录下的文件列表头指针
fileList*getFileList(charname[1024])
{
fileList*head=NULL;
fileList*cur=NULL;
charname_temp[1024];
//目录
DIR*dir;
//目录环境
structdirent*dir_env;
//文件描述
structstatstat_file;
//初始化head
head=(fileList*)malloc(sizeof(fileList));
head->nextfile=NULL;
//打开目录
dir=opendir(name);
while(dir_env=readdir(dir))//读文件描述表
{
//排除.和..
if(strcmp(dir_env->d_name,".")==0||strcmp(dir_env->d_name,"..")==0)
continue;
//把文件全名保存到新变量
strcpy(name_temp,name);
strcat(name_temp,dir_env->d_name);
stat(name_temp,&stat_file);//获取文件描述信息
//将文件信息存放到链表中
//产生临时节点
cur=(fileList*)malloc(sizeof(fileList));
//cur赋值
//文件名,fullName=cur_dir+"name";
strcpy(cur->file.name,dir_env->d_name);
strcpy(cur->file.fullName,name_temp);
//文件大小
//文件类型
if(S_ISDIR(stat_file.st_mode))
{
cur->file.size=0;
strcpy(cur->file.type,"mulu");
strcat(cur->file.fullName,"/");
}else
{
cur->file.size=stat_file.st_size;
strcpy(cur->file.type,"file");
}
//修改日期
cur->file.mod_time=ctime(&stat_file.st_mtime);
//将临时节点插入head中
if(head->nextfile==NULL)
{
head->nextfile=cur;
cur->nextfile=NULL;
}else
{
cur->nextfile=head->nextfile;
head->nextfile=cur;
}
}
returnhead;
}
//showAllNode
//输入:
目录
//输出:
次目录下所有的文件,和所有目录之下的文件
voidshowAllNode(fileList*head)
{
fileList*temp;
//数组索引
inti=0,j=0;
//如果head为空,直接返回
fileList*headArray[1024];
if(head==NULL)
return;
//输出当前目录
printf("%s",head->file.fullName);
printf("\n");
//输出head中的文件
temp=head->nextfile;
charfileListString[MAXBUF];
FILE*file;
char_temp[30];
strcpy(_temp,"temp.txt");
file=fopen(_temp,"w");
if(file==NULL){
printf("Thefileiscreatedfailed!
");
exit
(1);
}
while(temp)
{
//判断是否为文件,是文件显示文件
//若为目录,将目录名放入队列,求队列目录
if(strcmp(temp->file.type,"file")==0)
{
bzero(fileListString,MAXBUF);
printf("file:
%s",temp->file.fullName);
strcat(fileListString,temp->file.fullName);
strcat(fileListString,"\n");
while((strlen(fileListString))>0)
{
intwrite_length=fwrite(fileListString,sizeof(char),strlen(fileListString),file);
if(write_length{
printf("FileWriteintoFailed\n");
break;
}
bzero(fileListString,MAXBUF);
}
}else{
if(i>=1024)
{
printf("therearetoomanydirecotry\n");
return;
}
//头节点初始化
headArray[i]=getFileList(temp->file.fullName);
//头节点名称
strcpy(headArray[i]->file.fullName,temp->file.fullName);
i++;
}
temp=temp->nextfile;
}
fclose(file);
//对目录队列中目录使用递归,直到结束
for(j=0;j
showAllNode(headArray[j]);
return;
}
//showList
//输入:
列表头
//输出:
显示列表,返回void
voidshowList(fileList*head)
{
//判断head是否为空,若为空直接返回
if(head==NULL)return;
//若不为空则显示它的内容
while(head)
{
printf("%s\n",head->file.fullName);
head=head->nextfile;
}
return;
}
/*----------endoffileListfunctions-----------*/
voidmain()
{
intopt=1;
while(opt!
=0){
printf("Pleasechooseyourchoicebellow:
\n");
printf("1:
Managethefiles.\n");
printf("2:
Connecttheclients.\n");
charwindow[2];
scanf("%s",window);
if((strncmp(window,"1",1))==0){
printf("Pleaseinputyourchoicebellow:
\n");
printf("1:
Createanewfile.\n");
printf("2:
Deleteafile.\n");
printf("3:
Renameaknownfile.\n");
charchoice[2];
scanf("%s",choice);
if((strncmp(choice,"1",1))==0){
printf("Pleaseinputthenewfilename:
");
charfilename[20];
scanf("%s",filename);
FILE*file;
file=fopen(filename,"w");
if(file==NULL){
printf("Thefilecreatedfailed!
\n");
}
else{
printf("Thefilehascreatedsuccessfully.\n");
}
continue;
}
else