当前位置:文档之家› Linux下基于socket的文件传输程序设计 课程设计

Linux下基于socket的文件传输程序设计 课程设计

Linux下基于socket的文件传输程序设计 课程设计
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 原理和特点绘画出链接流程图,将客户机与服务器的相互通信划分为不同的模块,每个模块负责独立的功能项。服务器输入指令管理目录下的文件,create filename 是创建文件命令,rename oldname newname 是删除文命令,delete filename 是删除文件命令,同时监听着客户端的请求;客户端向服务器发送上传、下载和查看请求,从而得到不同的相应,包括将文件下载到当前路径下,从当前路径下上传文件给服务器,列出服务器的文件列表。

·2 socket 通信原理

国际标准化组织(ISO)在1978年提出开放系统互连参考模型(OSI:open system interconnection reference mode),该模型是设计和描述网络通信的基本框架。OSI 采用分层的额结构化技术将通信网络分为7层,从低到高为物理层、数据链路层、网络层、传输层、会话层、表示层、应用层。

TCP/IP 参考模型是由美国国防部创建,且发展至今最成功的通信协议模型,与OSI 模型对应,它将网络功能分为4层,包括网络接口层、网络层、传输层和应用层,每一层都有对应的协议。在传输层的主要协议是TCP 协议和UDP 协议。 socket 连接就是基于TCP 协议。TCP 是一种可靠地数据传输协议。 socket 是一种套接口,它把网络地址和端口号信息放在一个结构体中,也就是套接字地址结构。 结构图如下:

套接口与ip 、端口号的关系

套接口

168.222.222.222

9999

222.222.222.222 9999

Ip 地址

端口号

通用套接口地址数据结构定义在头文件中,形式如下: struct sockaddr {

uint8_t sa_len;

sa_family_t sa_family; char sa_data[14]; };

IPv4套接口地址数据结构以socketaddr_in 命名,定义在头文件中,形式如下: struct socketaddr_in {

unit8_t sin_len;

sa_family_t sin_family; in_port_t sin_port;

struct in_addr sin_addr; unsigned char sin_zero[8]; }

下图是TCP 套接口通信工作流程图:

结束连接通知

应答信号

服务请求

三次握手过程

挂起,直到有客户机的连接请

Socket ()

客户机进程 服务器进程 Bind ()

Listen ()

Accept ()

Recv ()

Send ()

Connect () Send ()

Recv ()

Close ()

Socket ()

Recv ()

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,(struct sockaddr*)0,(int*)0);

…………….

我们定义结构体:

struct client_t

{

pthread_t tid;

int conn_fd;

int used;

char name[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

#define MAXBUF 256

/*-------start of fileList functions----------*/ int fileSize(char fileName[]);

//文件信息

typedef struct fileinfo{

char name[256];

char fullName[1024];

int size;

time_t mod_time;

char type[10];

}fileinfo;

//文件列表

typedef struct filelist

{

fileinfo file;

struct filelist* nextfile;

}fileList;

//function getfilelist

//输入目录名

//输出目录下的文件列表头指针

fileList * getFileList(char name[1024])

{

fileList *head=NULL;

fileList *cur=NULL;

char name_temp[1024];

//目录

DIR * dir;

//目录环境

struct dirent *dir_env;

//文件描述

struct stat stat_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->https://www.doczj.com/doc/ee6628499.html,,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;

}

}

return head;

}

//showAllNode

//输入:目录

//输出:次目录下所有的文件,和所有目录之下的文件void showAllNode(fileList *head)

{

fileList * temp;

//数组索引

int i=0,j=0;

//如果head为空,直接返回

fileList * headArray[1024];

if(head == NULL)

return ;

//输出当前目录

printf("%s ",head->file.fullName);

printf("\n");

//输出head中的文件

temp =head->nextfile;

char fileListString[MAXBUF];

FILE *file;

char _temp[30];

strcpy(_temp,"temp.txt");

file=fopen(_temp,"w");

if(file==NULL){

printf("The file is created failed!");

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)

{

int write_length = fwrite(fileListString, sizeof(char), strlen(fileListString), file);

if (write_length < strlen(fileListString))

{

printf("File Write into Failed\n");

break;

}

bzero(fileListString, MAXBUF);

}

}else{

if(i>=1024)

{

printf("there are too many direcotry\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

void showList(fileList * head)

{

//判断head 是否为空,若为空直接返回

if(head == NULL)return;

//若不为空则显示它的内容

while(head)

{

printf("%s\n",head->file.fullName);

head = head->nextfile;

}

return ;

}

/*----------end of fileList functions-----------*/

void main()

{

int opt=1;

while(opt!=0){

printf("Please choose your choice bellow:\n");

printf("1:Manage the files.\n");

printf("2:Connect the clients.\n");

char window[2];

scanf("%s",window);

if((strncmp(window,"1",1))==0){

printf("Please input your choice bellow:\n");

printf("1: Create a new file.\n");

printf("2: Delete a file.\n");

printf("3: Rename a known file.\n");

char choice[2];

scanf("%s",choice);

if((strncmp(choice,"1",1))==0){

printf("Please input the new file name:");

char filename[20];

scanf("%s",filename);

FILE *file;

file=fopen(filename,"w");

if(file==NULL){

printf("The file created failed!\n");

}

else{

printf("The file has created successfully.\n");

}

continue;

}

else if((strncmp(choice,"2",1))==0){

printf("Please input the file name with the file path you want to delete:\n");

char filename[20];

scanf("%s",filename);

remove(filename);

printf("The file has been deleted successfully.\n");

continue;

}

else{

printf("Please input the file name you want to rename:\n");

char _old[20];

scanf("%s",_old);

printf("Please input the new file name:\n");

char _new[20];

scanf("%s",_new);

int result = rename( _old, _new );

if( result != 0 )

printf( "Could not rename '%s'\n", _old );

else

printf( "File '%s' renamed to '%s'\n", _old, _new );

continue;

}

}

else{

int ssock;

int clen;

struct sockaddr_in client_addr,server_addr;

char buf[MAXBUF];

if((ssock=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP))<0){ perror("socket error:");

exit(1);

}

printf("Run the server successfully.\nAnd now waiting the client comming...\n");

memset(&server_addr,0,sizeof(server_addr));

server_addr.sin_family=AF_INET;

server_addr.sin_addr.s_addr=inet_addr("127.0.0.1");

server_addr.sin_port=htons(6669);

if(bind(ssock,(struct sockaddr *)&server_addr,sizeof(server_addr))<0){

perror("bind error:");

exit(1);

}

int window=1;

while(window!=0){

clen=sizeof(client_addr);

recvfrom(ssock,(void *)buf,MAXBUF,0,(struct sockaddr*)&client_addr,&clen);

printf("%s\n",buf);

if((strncmp(buf, "0", 1)) == 0)

{

if((strncmp(buf, "0yy", 7)) == 0)

{

strcpy(buf,"yes");

printf("It's username and right.\n");

}

else

{

strcpy(buf,"no");

printf("It's username but wrong.\n");

}

sendto(ssock,(void *)buf,MAXBUF,0,(struct sockaddr*)&client_addr ,sizeof(client_addr));

}

else if((strncmp(buf, "1", 1)) == 0)

{

if((strncmp(buf, "1123", 4)) == 0)

{

strcpy(buf,"yes");

sendto(ssock,(void *)buf,MAXBUF,0,(struct sockaddr*)&client_addr ,sizeof(client_addr));

printf("It's password and right.\n");

recvfrom(ssock,(void *)buf,MAXBUF,0,(struct sockaddr*)&client_addr,&clen);

if((strncmp(buf, "upload", 5)) == 0){

printf("The client is going to upload file...\n");

recvfrom(ssock,(void *)buf,MAXBUF,0,(struct sockaddr*)&client_addr,&clen);//get filename

printf("The filename of the file uploaded by user is:%s\n",buf);

FILE *file;

char temp[30];

strcpy(temp,"recieve/");

strcat(temp,buf);

file=fopen(temp,"w");

if(file==NULL){

printf("The file is created failed!");

exit(1);

}

bzero(buf, MAXBUF);

recvfrom(ssock,(void *)buf,MAXBUF,0,(struct sockaddr*)&client_addr,&clen);

while (strlen(buf) > 0)

{

int write_length = fwrite(buf, sizeof(char), strlen(buf), file);

if (write_length < strlen(buf))

{

printf("File Write into Failed\n");

break;

}

bzero(buf, MAXBUF);

}

fclose(file);

printf("Recieve file already success.\n");

}

else{

printf("The client wants to download file.\n");

printf("Send the filelist to the client...\n");

//filelist

fileList *mylist;

//显示的目录

char name[1024]="recieve/";

//取得目录下文件

//头指针传递的目录或者文件名

mylist =getFileList(name);

strcpy(mylist->file.fullName,name);

//显示目录下文件

//showList(mylist);

//显示目录下所有文件

showAllNode(mylist);

//send fileList

FILE *file;

char temp[30];

strcpy(temp,"temp.txt");

file=fopen(temp,"r");

if(file==NULL){

printf("The file cannot open!");

exit(1);

}

else{

printf("\nThe fileListString open successfully!\n");

bzero(buf,MAXBUF);

int lengsize = 0;

while((lengsize = fread(buf,1,MAXBUF,file)) > 0)

{

printf("lengsize = %d\n",lengsize);

sendto(ssock,(void

*)buf,MAXBUF,0,(struct sockaddr*)&client_addr,sizeof(server_addr));

printf("%s\n",buf);

bzero(buf, MAXBUF);

}

printf("The fileListString has been sent to the client already.\n");

}

fclose(file);

bzero(buf, MAXBUF);

recvfrom(ssock,(void *)buf,MAXBUF,0,(struct sockaddr*)&client_addr,&clen);

printf("The client choosen file: %s\n",buf);

strcpy(temp,"recieve/");

strcat(temp,buf);

file=fopen(temp,"r");

if(file==NULL){

printf("The file is created failed!");

exit(1);

}

else{

printf("The file open successfully!\n");

printf("The file is downloading to the client now...\n");

bzero(buf,MAXBUF);

int lengsize = 0;

while((lengsize = fread(buf,1,MAXBUF,file)) > 0)

{

printf("lengsize = %d\n",lengsize);

sendto(ssock,(void

*)buf,MAXBUF,0,(struct sockaddr*)&client_addr,sizeof(server_addr));

bzero(buf, MAXBUF);

}

printf("The file has been downloaded already.\n");

}

fclose(file);

exit(1);//还可以显示此时的文件目录信息,检查是否完成了上传

}

close(ssock);

window=0;

}

else

{

strcpy(buf,"no");

sendto(ssock,(void *)buf,MAXBUF,0,(struct sockaddr*)&client_addr ,sizeof(client_addr));

printf("It's password but wrong.\n");

}

}

}

}

}

}

客服端:

#include

#include

#include

#include

#include

#include

#include

#include

#include

#define PORT 6669

#define MAXBUF 256

int check_passwd(int sockfd);

int tra_file(int sockfd);

void main ( int argc, char *argv[])

{

char username[20];

char password[20];

char temp[21];

char window;

printf("Please input your selections bellow:\n");

printf("1:Login the server with your username and password\n");

printf("2:Registe a newly user now.\n");

printf("0:Exit the system.\n");

window=getchar();

while(window>0){

if(window=='1'){

int key=0;

printf("Please input your username:");

scanf("%s",username);

printf("%s\n",username);

int ssock;

int clen;

struct sockaddr_in client_addr,server_addr;

char buf[MAXBUF];

if((ssock = socket(AF_INET,SOCK_DGRAM,0))<0){

perror("socket error:你暂时不能登录服务器server,请稍后再登录...\n");

exit(1);

}

else{

while(key==0){

memset(&server_addr,0,sizeof(server_addr));

server_addr.sin_family =AF_INET;

server_addr.sin_addr.s_addr=inet_addr("127.0.0.1");

server_addr.sin_port=htons(PORT);

strcpy(temp,"0");

strcat(temp,username);

strcpy(buf,temp);

sendto(ssock,(void *)buf,MAXBUF,0,(struct sockaddr*)&server_addr,sizeof(server_addr));

相关主题
文本预览
相关文档 最新文档