基于套接字的局域网内文件传输软件
摘要
当今世界科学技术飞速发展,尤其以计算机通信网络为代表的互联网技术更是日新月异,令人眼花燎乱,目不睱接。在计算机与网络迅速发展的今天,借助于网络进行信息资源交流给人们带来了极大的方便。各种文件传输系统都已被广大用户接受。比如QQ、UC、Internet邮件等互联网中运用最为广泛的文件传输工具,但它们之间的文件传输往往对远程服务器有非常大的依赖性,没有彻底实现点对点安全的文件传输。甚至需要花费大量的金钱购买各种移动磁盘或者其他局域网内连接主机的硬件设备。而达到的效果却总是因为传输效率以及安全威胁而受到很大的限制。在这种形势下,开发一个功能简单而实用,并且具有可移植性的局域网内文件传输工具势在必行,信息之间交换技术使用也越来越广泛,比如资料的共享,信息之间的交互,以及文件之间的传输。本论文设计了一个基于linux环境在局域网里实现文件传输的软件,linux环境是如今很公司做软件开始所选着的环境,该软件实现了文件在局域网里的传输,方便了在局域网里内部进行交流,实现信息的同步,进一步提高工作的效率。
关键词:文件传输;套接字;linux网络编程;linux系统
Socket-based file transfer software in the LAN
Liangchunlong
(College of Information Science and Engineering,Jishou University,Jishou,Hunan 416000)
Abstract
In today's world of science and technology rapid development, particularly in the computer communications network of the Internet technology is changing, dizzying Liao chaos head Xia access. In the rapid development of today's computers and network, by means of a network exchange of information resources has brought great convenience to the people. A variety of file transfer system have been accepted by the majority of users. The most widely used file transfer tools such as QQ, UC, Internet Mail, Internet file transfer between them is often a very large dependence on the remote server, not the full realization of the peer-to-peer secure file transfer. Even need to spend a lot of money to buy a variety of removable disk or LAN connection to the host hardware devices. Would be achieved because the transmission efficiency, and security threats are always subject to considerable restrictions. Under such circumstances, the development of a function is simple and practical, and portability LAN file transfer tool is imperative, the information exchanged between the use of technology are increasingly being used, such as the sharing of information between the information interaction, and file transmission. Designed a linux-based environment, the LAN file transfer software, linux environment is now very company to do the software starts the selected environment, the software to achieve the transmission of files in the LAN to facilitate the internal LAN exchange, information synchronization, and further increase efficiency
Key words:File transfer; socket; linux network programming; the linux system
目录
第一章 绪论 •1
1.1文件传输的应用背景与概述••1
1.2 开发环境介绍…………1
.
第二章 基本原理
2.1 文件传输的原理............................................2
2.2 文件传输软件的功能实现......................2
2.2.1 socket函数介绍。。。。。。。2
2.2.2 Socket编程基础重要的数据结构…………6
2.2.3 Socket提供的系统调用或函数的详细讲解 …………6
2.2.4 使用到的主要函数介绍(bind,listen,accpet)………6
2.3 软件源代码…………7
2.3.1 发送端源代码………8
2.3.2 接收端源代码………9
第三章 文件传输软件的使用............10
3.1 接收端的使用……… 3.2 发送端的使用。。。
3.3 测试结果。。。
第四章 设计总结
.
.
.
参考文献••25
第一章 绪论
1.1 文件传输的应用背景与概述
在日常的网络应用中,文件传输已经成为继即时通讯之后第二大的网络基础应用,而局域网里的文件发送是最方便的文件传输手段。越来越多的网民或是商业用户都采用这种方式发送文件,目前许多即时通讯软件,例如qq,msn都局域网文件传输功能。现在在很多公司的开发环境面使用的都是基于LINUX内核的操作系统,很多服务器也是使用的UNIX的系统,该软件同样也能在unix环境下使用,本论文设计了一个基于linux环境在局域网里实现文件传输的软件,linux环境是如今很公司做软件开始所选着的环境,该软件实现了文件在局域网里的传输,方便了在局域网里内部进行交流,实现信息的同步,进一步提高工作的效率。
1.2 开发环境介绍
这次软件的开发环境是红帽5,红帽5是一款基于linux内核的操作系统,Linux是一种自由和开放源码的类Unix操作系统。Linux是一套免费使用和自由传播的类Unix操作系统,是一个基于POSIX和UNIX的多用户、多任务、支持多线程和多CPU的操作系统。它能运行主要的UNIX工具软件、应用程序和网络协议。它支持32位和64位硬件。Linux继承了Unix以网络为核心的设计思想,是一个性能稳定的多用户网络操作系统。它主要用于基于Intel x86系列CPU的计算机上。这个系统是由全世界各地的成千上万的程序员设计和实现的。其目的是建立不受任何商品化软件的版权制约的、全世界都能自由使用的Unix兼容产品。
第二章 基本原理
2.1文件传输的基本原理
本软件使用的是TCP/IP协议(Transmission Control Protocol/Internet Protocol),中译名为传输控制协议/因特网互联协议,又名网络通讯协议,是Internet最基本的协议、Internet国际互联网络的基础,由网络层的IP协议和传输层的TCP协议组成。TCP/IP 定义了电子设备如何连入因特网,以及数据如何在它们之间传输的标准。协议采用了4层的层级结构,每一层都呼叫它的下一层所提供的网络来完成自己的需求。通俗而言:TCP负责发现传输的问题,一有问题就发出信号,要求重新传输,直到所有数据安全正确地传输到目的地。而IP是给因特网的每一台电脑规定一个地址。系统的文件传输功能主要依赖于建立客户端与服务器之间点对点的的连接后实现。所以就得与TCP/IP协议协合。TCP/IP协议(Transmission Control Protocol/Internet Protocol)叫做传输控制/网际协议,又叫网络通讯协议,这个协议是Internet国际互联网络的基础。TCP/IP是网络中使用的基本通信协议。虽然从名字上看TCP/IP包括两个协议,传输控制协议(TCP)和网际协议(IP),但TCP/IP实际上是一组协议,只是TCP协议处于运输层,它能够确保文件准确的传送;而IP协议处于网络层,它标识了处于网络中任意主机的唯一身份。TCP协议和IP协议是保证数据完整传输的两个基本的重要协议。通常说TCP/IP是Internet协议族,而不单单是TCP和IP,采用TCP/IP详解的原因:
第一,局域网内主机之间的是依靠IP地址进行标识。本设计要实现文件及文件夹的传输就需要以IP地址为传送基础进行;
第二,新用户上线后需要向局域网内所有用户广播自己的主机信息使网内主机得到本机的IP地址等。需要用到与TCP/IP相对的UDP协议。
2.2文件传输软件功能的实现
该软件是基于套接字实现局域网的内部两台机器之间的通信,利用socket函数建立连接,
通过socket提供的系统调用完成文件传输功能。具体分析如下:假设由A向B传输文件test,A机器要做的准备工作有:A首先得准备好传输给B的我文件,然后利用socket与B建立通信,然后用open函数读取test的内容,将test的内容写到一个buffer中,然后把利用read函数通过socket将test内容传送到B机器。
B机器的准备工作有,建立一个socket,监听来自A的请求,同时建立一个buffer用来存储来自A机器的信息,然后利用open函数,把来自A机器的内容存储在一个文件中,完成上述操作就完成了由A到B的文件传输。
发送端/接收端模式:
socket() 获得一个socket文件描述符
Bind() 将指定socket绑定到某端口
Connect() 连接到远程某个端口
listen() 侦听等待远程连接
accept() 接受了一个远程连接
send(),recv() 发送或接收数据(TCP)
sendto(),recvfrom() 发送或接收数据(UDP)
close() 关闭socket描述符
inet_addr() 将IP地址字符串转换成网络字节序的4字节地址
2.2.1 socket函数介绍
创建一个套接口,af:一个地址描述。目前仅支持AF_INET格式,也就是说ARPA Internet地址格式。type:新套接口的类型描述。 protocol:套接口所用的协议。
socket()函数用于根据指定的地址族、数据类型和协议来分配一个套接口的描述字及其所用的资源。如果协议protocol未指定(等于0),则使用缺省的连接方式。 对于使用一给定地址族的某一特定套接口,只支持一种协议。但地址族可设为AF_UNSPEC(未指定),这样的话协议参数就要指定了。协议号特定于进行通讯的“通讯域”。支持下述类型描述: 类型 解释 SOCK_STREAM 提供有序的、可靠的、双向的和基于连接的字节流,使用带外数据传送机制,为Internet地址族使用TCP。 SOCK_DGRAM 支持无连接的、不可靠的和使用固定大小(通常很小)缓冲区的数据报服务,为Internet地址族使用UDP。 SOCK_STREAM类型的套接口为全双向的字节流。对于流类套接口,在接收或发送数据前必需处于已连接状态。用connect()调用建立与另一套接口的连接,连接成功后,即可用send()和recv()传送数据。当会话结束后,调用closesocket()。带外数据根据规定用send()和recv()来接收。 实现SOCK_STREAM类型套接口的通讯协议保证数据不会丢失也不会重复。如果终端协议有缓冲区空间,且数据不能在一定时间成功发送,则认为连接中断,其后续的调用也将以WSAETIMEOUT错误返回。 SOCK_DGRAM类型套接口允许使用sendto()和recvfrom()从任意端口发送或接收数据报。如果这样一个套接口用connect()与一个指定端口连接,则可用send()和recv()与该端口进行数据报的发送与接收。
2.2.2:Socket编程基础重要的数据结构:
Sockaddr结构socket的地址信息
struct sockaddr {
unsigned short sa_family; // address family, AF_xxx
char sa_data[14]; // 14 bytes of protocol address
};//总长度16字节;
sockaddr_in结构,存放Internet socket地址信息
struct sockaddr_in {
short int sin_family; // Address family
unsigned short int sin_port; // Port number
struct in_addr sin_addr; // Internet address
unsigned char sin_zero[8]; // Same size as struct sockaddr
};
struct in_addr {
uint32_t s_addr; // that's a 32-bit int (4 bytes)
};
2.2.3:Socket提供的系统调用函数的介绍 :
相关函数 accept,bind,connect,listen
表头文件 #include 定义函数 int socket(int domain,int type,int protocol); 函数说明 socket()用来建立一个套接字文件描述符,也就是向系统注册,通知系统建立一通信端口。Domain参数指定使用何种的地址类型,完整的定义在/usr/include/bits/socket.h内,底下是常见的协议: PF_UNIX/PF_LOCAL/AF_UNIX/AF_LOCAL UNIX 进程通信协议 PF_INET?AF_INET Ipv4网络协议 PF_INET6/AF_INET6 Ipv6 网络协议 PF_IPX/AF_IPX IPX-Novell协议 PF_NETLINK/AF_NETLINK 核心用户接口装置 PF_X25/AF_X25 ITU-T X.25/ISO-8208 协议 PF_AX25/AF_AX25 业余无线AX.25协议 PF_ATMPVC/AF_ATMPVC 存取原始ATM PVCs PF_APPLETALK/AF_APPLETALK appletalk(DDP)协议 PF_PACKET/AF_PACKET 初级封包接口 Type参数有下列几种数值: SOCK_STREAM 提供双向连续且可信赖的数据流,即TCP。支持OOB 机制,在所有数据传送前必须使用connect()来建立连线状态。 SOCK_DGRAM 使用不连续不可信赖的数据包连接 SOCK_SEQPACKET 提供连续可信赖的数据包连接 SOCK_RAW 提供原始网络协议存取 SOCK_RDM 提供可信赖的数据包连接 SOCK_PACKET 提供和网络驱动程序直接通信。 protocol用来指定socket所使用的传输协议编号,通常此参考不用管它,设为0即可。 返回值 成功则返回socket处理代码,失败返回-1。 2.3.4:使用到的主要函数介绍: bind(对socket定位) 相关函数 socket,accept,connect,listen 表头文件 #include 定义函数 int bind(int sockfd,struct sockaddr * my_addr,int addrlen); 函数说明 bind()用来设置给参数sockfd的socket一个名称。此名称由参数my_addr指向一sockaddr结构,对于不同的socket domain定义了一个通用的数据结构 struct sockaddr { unsigned short int sa_family; char sa_data[14]; }; sa_family 为调用socket()时的domain参数,即AF_xxxx值。 sa_data 最多使用14个字符长度。 此sockaddr结构会因使用不同的socket domain而有不同结构定义,例如使用AF_INET domain,其socketaddr结构定义便为 struct socketaddr_in { unsigned short int sin_family; uint16_t sin_port; struct in_addr sin_addr; unsigned char sin_zero[8]; }; struct in_addr { uint32_t s_addr; }; sin_family 即为sa_family sin_port 为使用的port编号 sin_addr.s_addr 为IP 地址 sin_zero 未使用。 参数 addrlen为sockaddr的结构长度。 返回值 成功则返回0,失败返回-1,错误原因存于errno中。 错误代码 EBADF 参数sockfd 非合法socket处理代码。 EACCESS 权限不足 ENOTSOCK 参数sockfd为一文件描述词,非socket。 范例 参考listen() listen(等待连接) 相关函数 socket,bind,accept,connect 表头文件 #include 定义函数 int listen(int s,int backlog); 函数说明 listen()用来等待参数s 的socket连线。参数backlog指定同时能处理的最大连接要求,如果连接数目达此上限则client端将收到ECONNREFUSED的错误。Listen()并未开始接收连线,只是设置socket为listen模式,真正接收client端连线的是accept()。通常listen()会在socket(),bind()之后调用,接着才调用accept()。 返回值 成功则返回0,失败返回-1,错误原因存于errno 附加说明 listen()只适用SOCK_STREAM或SOCK_SEQPACKET的socket类型。如果socket为AF_INET则参数backlog 最大值可设至128。 错误代码 EBADF 参数sockfd非合法socket处理代码 EACCESS 权限不足 EOPNOTSUPP 指定的socket并未支援listen模式。 accept(接受socket连接) 相关函数 socket,bind,listen,connect 表头文件 #include #include 定义函数 int accept(int s,struct sockaddr * addr,int * addrlen); 函数说明 accept()用来接受参数s的socket连接。参数s的socket必需先经bind()、listen()函数处理过,当有连接进来时accept()会返回一个新的socket处理代码,往后的数据传送与读取就是经由新的socket处理,而原来参数s的socket能继续使用accept()来接受新的连接要求。连接成功时,参数addr所指的结构会被系统填入远程主机的地址数据,参数addrlen为scokaddr的结构长度。关于结构sockaddr的定义请参考bind()。 返回值 成功则返回新的socket处理代码,失败返回-1,错误原因存于errno中。 错误代码 EBADF 参数s 非合法socket处理代码。 EFAULT 参数addr指针指向无法存取的内存空间。 ENOTSOCK 参数s为一文件描述词,非socket。 EOPNOTSUPP 指定的socket并非SOCK_STREAM。 EPERM 防火墙拒绝此连线。 ENOBUFS 系统的缓冲内存不足。 ENOMEM 核心内存不足 2.3 软件源代码: 2.3.1 发送端的源代码: #include #include #include #include #include #include #include #include #include #include #include #include #define portnumber 800 int main(int argc,char **argv) { int sockfd,fd; int read_count,temp,w_err; char buffer[4096]; struct sockaddr_in server_addr; if(argc!=3) { printf(\"Uagae:ip,filename\\n\"); exit(1); } if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1) fprintf(stderr,\"socket error\\n\ exit(1); { } bzero(&server_addr ,sizeof ( server_addr)); server_addr.sin_family=AF_INET; server_addr.sin_port=htons(portnumber); inet_pton(AF_INET, argv[1], &server_addr.sin_addr); if(connect(sockfd,(struct sockaddr *)(&server_addr),sizeof(struct sockaddr ))==-1) { fprintf(stderr,\"connect error\\n\ exit(1); } /*打开待传输的文件*/ fd=open(argv[2],O_RDONLY); if(fd==-1) { fprintf(stderr,\"open file failed\\n\"); exit(1); } /*将打开的文件里面的内容读入到缓冲区里面*/ temp=0; while(read_count!=0) { read_count=read(fd,buffer+temp,10); temp=temp+read_count; if(read_count==-1) { fprintf(stderr,\"read failed\\n\"); exit(1); } } /*将缓冲区里面的内容通过套接字传输给另外一台机器*/ w_err=write(sockfd,buffer,strlen(buffer)); if(w_err==-1) { fprintf(stderr,\"write to sockfd failde\\n\"); exit(1); } close(sockfd); return 0; } 2.3.2接收端的源代码: #include #include #include #include #include #include #include #include #include #include #include #define portnumber 800 int main(int argc,char **argv) { int err,sd,new_sd,s_bind,s_listen; int sin_size,nbytes,count,fd,w_temp,r_temp; char s_buffer[4096]; char name[10]=\"newfle\"; struct sockaddr_in server_addr,client_addr; sd=socket(AF_INET,SOCK_STREAM,0); if(sd==-1) { fprintf(stderr,\"socket error\\n\ exit(1); } /*填充addr结构体*/ bzero(&server_addr,sizeof(struct sockaddr_in)); server_addr.sin_family=AF_INET; server_addr.sin_addr.s_addr=htonl(INADDR_ANY); server_addr.sin_port=htons(portnumber); s_bind=bind(sd,(struct sockaddr *)(&server_addr),sizeof(struct sockaddr)); if(s_bind==-1) { fprintf(stderr,\"bind error:\\n\ exit(1); } s_listen=listen(sd,5); if(s_listen==-1) { fprintf(stderr,\"listen error:\\n\ close(sd); exit(1); } w_temp=0; r_temp=0; while(1) { sin_size=sizeof(struct sockaddr); new_sd=accept(sd,(struct sockaddr *)(&client_addr),&sin_size); if(new_sd==-1) { fprintf(stderr,\"accept error :\\n\ exit(1); } /*通过套接字将传输过来的数据读到缓冲区里面*/ while(nbytes!=0) { nbytes=read(new_sd,s_buffer+r_temp,10); r_temp=r_temp+nbytes; if(nbytes==-1) { fprintf(stderr,\"read error\\n\ exit(1); } /*打开一个文件接收传输过来的数据,将数据写入到文件里面,完成文件的传输*/ if(nbytes==0) { fd=open(name,O_WRONLY|O_CREAT|O_TRUNC,0666); if(fd<0) { fprintf(stderr,\"open failed\\n\ } count=write(fd,s_buffer,4096); if(count==-1){ fprintf(stderr,\"write error\\n\ exit(1); } } } close(new_sd); printf(\"recv a file\\n\"); } close(sd); return 0; } 第三章 文件传输软件的使用 3.1首先在终端运行recv文件,如图: 3.2然后在终端运行send文件同时输入接收方IP加上文件名字,如图: 3.3最后查看recv所在的终端,如图: 第四章 设计总结 本文对socket网络编程技术做了较为全面和深入的学习研究。在该软件的设计过程中,严格按照目前流行的制作规范和软件设计的开发流程进行设计开发。在设计系统方案时做了大量而详细的系统分析工作,其中包括:网络传输协议的选定、开发工具的选择等。而且对整个系统的采用的结构,实现的功能做了全面合理的规划。该软件在linux内核的操作系统下运行,操作简便、能够很好地满足文件传输的需求。此系统设计完成后,进行了较为全面系统的测试,包括局部(各模块和功能)测试和整体(各模块间的相互联系和非法操作)测试。测试结果证明,本课题设计出的软件是稳定的。 参考文献 1) 史蒂文,《UNIX环境高级编程》,人民邮电出版社,2006 2) 单立平,《Linux网络体系结构设计与TCP/IP协议栈》,电子工业出版社,2009 3) 谢希仁,《计算机网络第5版》,电子工业出版社,2010 4) 严蔚敏,《数据结构》,清华大学出版社,2006 5) 史蒂文,《UNIX网络编程》,人民邮电出版出版社,2006 6) 史蒂文,《TCP/IP网络详解》,人民邮电出版社,2006 7) 孔浩,陈猛《C指针编程之道》,人民邮电出版社,2008 8) 埃瑞克.S.理曼德,《UNIX编程艺术》,人民邮电出版社,2010 9) 汤子瀛《计算机操作系统》,西安电子科技大学出版社,2008 10) 谭浩强,《C语言程序设计》,清华大学出版社,1999 因篇幅问题不能全部显示,请点此查看更多更全内容