您的位置:首页 > 理论基础 > 计算机网络

Linux 基于TCP/IP的文件传输系统

2011-10-08 05:54 986 查看
一、 设计目的

通过Linux C编程,设计一个基于TCP/IP的文件传输系统,实现网络文件的收发。

二、 设计环境

VMware WorkStation 6.0.2+Fedora 10

三、 设计方案

(1)文件读写

任意文件都可以二进制的方式进行读写,为了实现任意文件类型的传输,在读写文件的过程中,必须采用二进制的读写方式。

(2)传输协议

为了保证数据的正确性,文件传输需要采用一种可靠的传输协议。UDP协议实现比较简单,但UDP面向无连接,传输过程中,会出现丢包的情况,导致数据发送失败。故采用面向连接的TCP/IP协议,防止传输过程中的数据丢失的情况。

(3)大文件的传输

对于比较大的文件,应该进行分包操作,以防止占用过多的内存,导致文件发送失败。

四、 设计流程

如图1所示,服务器程序作为文件的发送方。首先,服务器端输入要发送的文件。然后,创建一个流式套接字(SOCK_STREAM),进行绑定。绑定成功后,执行监听,当有客户发送连接请求,执行Accept(),接收来自客户端的请求。

连接建立后,首先服务器向客服端发送的文件的文件名及扩展名等信息。信息发送完毕,服务器方将待发送的数据读入缓冲区,通过套接字将数据发送出去。发送完成后退出,并显示发送完成的信息。



图1 服务器流程图

如图2所示,客户端程序完成文件的接收操作。首先,创建一个流式套接字。套接字创建成功后,对该套接字进行绑定。绑定成功后,向服务器方发送连接请求。连接成功后,首先,接收服务器发送的文件信息。接收成功后,开始数据的接收。文件接收完毕,显示文件已接收完成。



图2 客户端流程图

五、 设计测试

为了验证设计的正确性,在Fedora 10平台上对可执行文件进行了回环测试。测试了.txt,.doc,.jpg,.pdf四种类型的文件,测试源文件如图3所示。



图3 测试源文件

(1).txt文件测试

如图4所示,服务器端执行./fileserver命令,程序提示输入需要发送的文件。输入1.txt,此时服务器进入监听状态,等待客户端的连接。

在客户端执行./fileclient 127.0.0.1,建立连接。此时,服务器端开始发送文件。并显示读取的文件大小为50 Bytes,小于缓冲区(4096 Bytes)大小,发送一次就可以了,不需要分包操作。发送完成,服务器端显示发送完成,客户端显示接收到来至服务器的文件。



图4 .txt文件测试

(2).doc文件测试

如图5所示,服务器端执行./fileserver命令,程序提示输入需要发送的文件。输入test.doc,此时服务器进入监听状态,等待客户端的连接。

在客户端执行./fileclient 127.0.0.1,建立连接。此时,服务器端开始发送文件。并显示读取的文件大小为19.5 KByte,大于缓冲区(4096 Bytes)大小,需要分包发送,图示进行了5次分包,前4次包的大小为4096 Bytes,最后一次为3584 Bytes。发送完成,服务器端显示发送完成,客户端显示接收到来至服务器的文件。



图5 .doc文件测试

(3).pdf文件测试

如图6所示,服务器端执行./fileserver命令,程序提示输入需要发送的文件。输入test.pdf,此时服务器进入监听状态,等待客户端的连接。

在客户端执行./fileclient 127.0.0.1,建立连接。此时,服务器端开始发送文件。并显示读取的文件大小为23.8 KByte,大于缓冲区(4096 Bytes)大小,需要分包发送,图示进行了6次分包,前5次包的大小为4096 Bytes,最后一次为3993 Bytes。发送完成,服务器端显示发送完成,客户端显示接收到来至服务器的文件。



图6 .pdf文件测试

(4).jpg文件测试

如图7所示,服务器端执行./fileserver命令,程序提示输入需要发送的文件。输入test.jpg,此时服务器进入监听状态,等待客户端的连接。

在客户端执行./fileclient 127.0.0.1,建立连接。此时,服务器端开始发送文件。并显示读取的文件大小为7.11 KByte,大于缓冲区(4096 Bytes)大小,需要分包发送,图示进行了2次分包,第1次包的大小为4096 Bytes,第2次为3189 Bytes。发送完成,服务器端显示发送完成,客户端显示接收到来至服务器的文件。



图7 .jpg文件测试

接收到的文件如图8所示,实验证实文件接收准确无误,没有发生丢包的情况,由于采取了分包的操作,能够传送较大的文件。



图8 接收文件夹

六、 结论

实验证实,该网络文件系统由于采用二进制读写方式,从而能发送任意类型的文件。由于采用了分包操作,能发送比较大的文件。采用TCP/IP协议进行传输,从而保证了文件传输的可靠性。

【代码清单】

common.h

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <netinet/in.h>

#define PORT 6000
#define LISTENQ 20
#define BUFFSIZE 4096
#define FILE_NAME_MAX_SIZE 512


fileclient.c

#include "common.h"

int main(int argc, char **argv[])
{
int clientfd;

if(argc!=2)
{
fprintf(stderr,"Usage:./fileclient <IP_Address>\n");
exit(1);
}
struct sockaddr_in clientaddr;
bzero(&clientaddr,sizeof(clientaddr));

clientaddr.sin_family=AF_INET;
clientaddr.sin_addr.s_addr=htons(INADDR_ANY);
clientaddr.sin_port=htons(0);

clientfd=socket(AF_INET,SOCK_STREAM,0);

if(clientfd<0)
{
perror("socket");
exit(1);
}

if(bind(clientfd,(struct sockaddr*)&clientaddr,sizeof(clientaddr))<0)
{
perror("bind");
exit(1);
}

struct sockaddr_in svraddr;
bzero(&svraddr,sizeof(svraddr));
if(inet_aton(argv[1],&svraddr.sin_addr)==0)
{
perror("inet_aton");
exit(1);
}
svraddr.sin_family=AF_INET;
svraddr.sin_port=htons(PORT);

socklen_t svraddrlen=sizeof(svraddr);
if(connect(clientfd,(struct sockaddr*)&svraddr,svraddrlen)<0)
{
perror("connect");
exit(1);
}

//recv file imformation
char buff[BUFFSIZE];
char filename[FILE_NAME_MAX_SIZE];
int count;
bzero(buff,BUFFSIZE);

count=recv(clientfd,buff,BUFFSIZE,0);
if(count<0)
{
perror("recv");
exit(1);
}
strncpy(filename,buff,strlen(buff)>FILE_NAME_MAX_SIZE?FILE_NAME_MAX_SIZE:strlen(buff));

printf("Preparing recv file : %s from %s \n",filename,argv[1]);

//recv file
FILE *fd=fopen(filename,"wb+");
if(NULL==fd)
{
perror("open");
exit(1);
}
bzero(buff,BUFFSIZE);

int length=0;
while(length=recv(clientfd,buff,BUFFSIZE,0))
{
if(length<0)
{
perror("recv");
exit(1);
}
int writelen=fwrite(buff,sizeof(char),length,fd);
if(writelen<length)
{
perror("write");
exit(1);
}
bzero(buff,BUFFSIZE);
}
printf("Receieved file:%s from %s finished!\n",filename,argv[1]);
fclose(fd);
close(clientfd);
return 0;
}


fileserver.c

#include "common.h"

int main(int argc, char **argv[])
{
//Input the file name
char filename[FILE_NAME_MAX_SIZE];
bzero(filename,FILE_NAME_MAX_SIZE);
printf("Please input the file name you wana to send:");
scanf("%s",&filename);
getchar();

//Create socket
int sockfd,connfd;
struct sockaddr_in svraddr,clientaddr;
bzero(&svraddr,sizeof(svraddr));

svraddr.sin_family=AF_INET;
svraddr.sin_addr.s_addr=htonl(INADDR_ANY);
svraddr.sin_port=htons(PORT);

sockfd=socket(AF_INET,SOCK_STREAM,0);
if(sockfd<0)
{
perror("socket");
exit(1);
}

//bind
if(bind(sockfd,(struct sockaddr*)&svraddr,sizeof(svraddr))<0)
{
perror("bind");
exit(1);
}

//listen
if(listen(sockfd,LISTENQ)<0)
{
perror("listen");
exit(1);
}

while(1)
{
socklen_t length=sizeof(clientaddr);

//accept
connfd=accept(sockfd,(struct sockaddr*)&clientaddr,&length);
if(connfd<0)
{
perror("connect");
exit(1);
}

//send file imformation
char buff[BUFFSIZE];
int count;
bzero(buff,BUFFSIZE);
strncpy(buff,filename,strlen(filename)>FILE_NAME_MAX_SIZE?FILE_NAME_MAX_SIZE:strlen(filename));
count=send(connfd,buff,BUFFSIZE,0);
if(count<0)
{
perror("Send file imformation");
exit(1);
}

//read file
FILE *fd=fopen(filename,"rb");
if(fd==NULL)
{
printf("File :%s not found!\n",filename);
}
else
{
bzero(buff,BUFFSIZE);
int file_block_length=0;
while((file_block_length=fread(buff,sizeof(char),BUFFSIZE,fd))>0)
{
printf("file_block_length:%d\n",file_block_length);
if(send(connfd,buff,file_block_length,0)<0)
{
perror("Send");
exit(1);
}
bzero(buff,BUFFSIZE);
}
fclose(fd);
printf("Transfer file finished !\n");
}
close(connfd);
}
close(sockfd);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: