TCP/IP编程实现远程文件传输

 在TCP/IP网络结构中,为了保证网络安全,网络人员往往需要在路由器上添加防火墙,禁止非法用户用ftp等安全危害较大的TCP/IP协议访问主机。而有时系统维护人员需要用ftp将一些文件从中心机房主机传到前端网点主机上,比如应用程序的替换升级。如果每次传输文件时都要打开防火墙,未免显得有些繁琐,要是在自己的应用程序中增加一个专门的文件传输模块,那将是十分愉快的事情。 
  
  UNIX网络程序设计一般都采用套接字(socket)系统调用。针对目前十分流行的客户/服务器模式,其程序编写步骤如下: 
  1.Socket系统调用 
  为了进行网络I/O,服务器和客户机两端的UNIX进程要做的第一件事是调用socket()系统调用,建立软插座,指明合适的通讯协议。格式为: 
  #include<sys/types.h> 
  #include<sys/socket.h> 
  int socket(int family,int type,int protocol) 
  其中:(1)family指明套节字族,其值包括: 
  AF_UNIX   (UNIX内部协议族) 
  AF_INET   (Iternet协议) 
  AF_NS (XeroxNs协议,TCP/IP编程取该值) 
  AF_IMPLINK  (IMP链接层) 
  (2)type 指明套接字类型,取值有: 
  SOCK_STREAM     (流套接字) 
  SOCK_DGRAM     (数据报套接字) 
  SOCK_RAW      (原始套接字) 
  SOCK_SEQPACKET   (定序分组套接字) 
  一般情况下,前两个参数的组合就可以决定所使用的协议,这时第三个参数被置为0,如果第一个参数为AF_INET,第二个参数选SOCK_STREAM,则使用的协议为TCP;第二个参数选SOCK_DGRAM,则使用的协议为UDP;当第二个参数选SOCK_RAW时,使用的协议为IP。值得指出的是并不是所有的族和类型的组合都是合法的,具体请查阅相关资料。该系统调用若成功则返回一个类似文件描述符,成为套节字描述字,可以像文件描述符那样用read和write对其进行I/O操作。当一个进程使用完该软插座时,需用close(<描述符>关闭(具体见后面内容)。 
  2.服务器端Bind系统调用 
  软插座创建时并没有与任何地址相关联,必须用bind()系统调用为其建立地址联系。其格式为: 
  #include<sys/types.h> 
  #include<sys/socket.h> 
  int bind(int socketfd,struct sockaddr_in *localaddr,sizeof(localaddr)); 
  其中:(1)第一个参数socketfd是前步socket()系统调用返回的套节字描述符。 
  (2)第二个参数被捆向本地地址的一种结构,该结构在sys/netinet/in.h中定义: 
  struct sockaddr_in{ 
   short sin_family;/*socket()系统调用的协议族如AF_INET*/ 
   u_short sin_port;/*网络字节次序形式的端口号码*/ 
   struct in_addr sin_addr;/*网络字节次序形式的网络地址*/ 
   char sin_zero[8]; 
  } 
  一台机器上的每个网络程序使用一个各自独立的端口号码,例如:telnet程序使用端口号23,而ftp文件传输程序使用端口号21。我们在设计应用程序时,端口号码可以由getservbyname()函数从/etc/services库文件中获取,也可以由htons (int portnum)函数将任意正整数转换为网络字节次序形式来得到,有些版本的UNIX操作系统则规定1024以下的端口号码只可被超级用户使用,普通用户程序使用的端口号码只限于1025到32767之间。网络地址可以由gethostbyname(char*hostname)函数得到(该函数和getservbyname()一样都以网络字节次序形式返回所有在他们结构中的数据),参数hostname为/etc/hosts文件中某一网络地址所对应的机器名。该函数返回一个类型为hostent的结构指针,hostent结构在netdb.h中定义: 
  struct hostent{ 
   char *h_name; 
   char **h_aliases; 
   int h_addrtype; 
   int h_length;  /*地址长度*/ 
   char **h_addr_list; 
   #define h_addr h_addr_list[0];/*地址*/ 
  } 
  (3)第三个参数为第二个结构参数的长度,如果调用成功,bind返回0,否则将返回-1并设置errno。 
  3.服务器端系统调用listen,使服务器愿意接受连接 
  格式:int listen(int socketfd,int backlong) 
  它通常在socket和bind调用后在accept调用前执行。第二个参数指明在等待服务器执行accept调用时系统可以排队多少个连接要求。此参数常指定为5,也是目前允许的最大值。 
  4.服务器调用accept,以等待客户机调用connect进行连接。格式如下: 
  int newsocket=(int socketfd,struct sockaddr_in *peer,int*addrlen); 
  该调用取得队列上的第一个连接请求并建立一个具有与sockfd相同特性的套节字。如果没有等待的连接请求,此调用阻塞调用者直到一连接请求到达。连接成功后,该调用将用对端的地址结构和地址长度填充参数peer和addlen,如果对客户端的地址信息不感兴趣,这两个参数用0代替。 
  5.客户端调用connect()与服务器建立连接。格式为: 
  connect(int socketfd,struct sockaddr_in *servsddr,int addrlen) 
  客户端取得套接字描述符后,用该调用建立与服务器的连接,参数socketfd为socket()系统调用返回的套节字描述符,第二和第三个参数是指向目的地址的结构及以字节计量的目的地址的长度(这里目的地址应为服务器地址)。调用成功返回0,否则将返回-1并设置errno。 
  6.通过软插座发送数据 
  一旦建立连接,就可以用系统调用read和write像普通文件那样向网络上发送和接受数据。Read接受三个参数:一个是套节字描述符;一个为数据将被填入的缓冲区,还有一个整数指明要读的字节数,它返回实际读入的字节数,出错时返回-1,遇到文件尾则返回0。Write也接受三个参数:一个是套节字描述符;一个为指向需要发送数据的缓冲区,还有一个整数指明要写入文件的字节个数,它返回实际写入的字节数,出错时返回-1。当然,也可以调用send和recv来对套节字进行读写,其调用与基本的read和write系统调用相似,只是多了一个发送方式参数。 
  7.退出程序时,应按正常方式关闭套节字。格式如下: 
  int close(socketfd) 
  前面介绍了UNIX客户/服务器模式网络编程的基本思路和步骤。值得指出的是socket编程所涉及的系统调用不属于基本系统调用范围,其函数原形在libsocket.a文件中,因此,在用cc命令对原程序进行编译时需要带-lsocket选项。 
  现在,我们可以针对文章开头提出的问题着手进行编程了。在图示的网络结构中,为使中心机房的服务器能和网点上的客户机进行通信,需在服务器端添加通过路由器1112到客户机的路由,两台客户机也必须添加通过路由器2221到服务器的路由。在服务器的/etc/hosts文件中应该包含下面内容: 
  1.1.1.1  server 
  2.2.2.2  cli1 
  2.2.2.3  cli2 
  客户机的/etc/hosts文件中应该有本机地址信息和服务器的地址信息,如cli1客户机的/etc/hosts文件: 
  2.2.2.2  cli1 
  1.1.1.1  server 
  网络环境搭建好后,我们可以在服务器端编写fwq.c程序,负责接受客户机的连接请求,并将从源文件中读取的数据发送到客户机。客户机程序khj.c向服务器发送连接请求,接收从服务器端发来的数据,并将接收到的数据写入目标文件。源程序如下: 

/*服务器源程序fwq.c*/ 
#include<stdio.h> 
#include<sys/types.h> 
#include<sys/fcntl.h> 
#include<sys/socket.h> 
#include<sys/netinet/in.h> 
#include<netdb.h> 
#include<errno.h> 
main() 

  char c,buf[1024],file[30]; 
  int fromlen,source; 
  register int k,s,ns; 
  struct sockaddr_in sin; 
  struct hostent *hp; 
  system(″clear″); 
  printf(″\n″); 
    
  printf(″\n\n\t\t输入要传输的文件名:″); 
  scanf(″%s″,file); 
  if ((source=open(file,O_RDONLY))<0){ 
   perror(″源文件打开出错″); 
   exit(1); 
  } 
  printf(″\n\t\t在传送文件,稍候…″); 
  hp=gethostbyname(″server″); 
  if (hp==NULL){ 
   perror(″返回主机地址信息错!!!″); 
   exit(2); 
  } 
  s=socket(AF_INET,SOCK_STREAM,0); 
  if(s<0){ 
   perror(″获取SOCKET号失败!!!″); 
   exit(3); 
  } 
  sin.sin_family=AF_INET; 
  sin.sin_port=htons(1500);/*使用端口1500*/ 
  bcopy(hp->h_addr,&sin.sin_addr,hp->h_length); 
  if(bind(s,&sin,sizeof(sin))<0){ 
   perror(″不能将服务器地址捆绑到SOCKET号上!!!″); 
   colse(s); 
   exit(4); 
  } 
  if(listen(s,5)<0{ 
   perror(″sever:listen″); 
   exit(5); 
  } 
while(1){ 
  if((ns=accept(s,&sin,&fromlen))<0){ 
   perror(″sever:accept″); 
   exit(6); 
  } 
  lseek(source,OL,0);/*每次接受客户机连接,应将用于读的源文件指针移到文件头*/ 
  write(ns,file,sizeof(file)); /*发送文件名*/ 
  while((k=read(source,buf,sizeof(buf)))>0) 
   write(ns,buf,k); 
  printf(″\n\n\t\t传输完毕!!!\n″); 
  close(ns); 

  close(source); 
  exit(0); 
  /*客户机源程序khj.c*/ 
  #include<stdio.h> 
  #include<sys/types.h> 
  #include<sys/fcntl.h> 
  #include<sys/socket.h> 
  #include<sys/netinet/in.h> 
  #include<netdb.h> 
  #include<errno.h> 
  #include <string.h> 
  main() 
  { 
   char buf[1024],file[30]; 
   char *strs=″\n\n\t\t正在接收文件″; 
   int target; 
   register int k,s; 
   struct sockaddr_in sin; 
   struct hostent *hp; 
   system(″clear″); 
   printf(″\n″); 
     
   hp=gethostbyname(″server″); 
   if(hp==NULL){ 
          perror(″返回服务器地址信息错!!!″); 
    exit(1); 
   } 
   s=socket(AF_INET,SOCK_STREAM,0); 
   if(s<0){ 
    perror(″获取SOCKET号失败!!!″); 
    exit(2); 
   } 
   sin.sin_family=AF_INET; 
   sin.sin_port=htons(1500);/*端口号需与服务器程序使用的一致*/ 
   bcopy(hp->h_addr,&sin.sin_addr,hp->h_length); 
   printf(″\n\n\t\t正在与服务器连接…″); 
   if(connect(s,&sin,sizeof(sin),0)<0){ 
    perror(″不能与服务器连接!!!″); 
    exit(3); 
   } 
   while((k=read(s,file,sizeof(file)))<=0/*接收文件名*/ 
   if((target=open(file,o_WRONLY|O_CREAT|O_TRUNC,0644))<0){ 
    perror(″不能打开目标文件!!″); 
    exit(4); 
  } 
  strcat(strs,file); 
  strcat(strs,″,稍候…″); 
  write(1,strs,strlen(strs)); 
  while((k=read(s,buf,sizeof(buf)))>0) 
   write(tatget,buf,k); 
  printf(″\n\n\t\t接收文件成功!!!\n″); 
  close(s); 
  close(target); 
  } 

  上述程序在Sco Unix System v3.2及Sco TCP/IP Rumtime环境下调试通过。

时间: 2024-10-07 04:48:57

TCP/IP编程实现远程文件传输的相关文章

java socket编程如何测量文件传输速度?

问题描述 java socket编程如何测量文件传输速度? 作业需要,分别写了一个基于tcp和udp的传输文件的程序,想测试两者同时传输时各自的传输速度 请问有什么方法可以实现? 解决方案 发送时发送一个记录客户端时间的包,同时记录好这个包的大小 .服务端在收到这个包后,拆包.取出客户端时间和自己的服务端时间时行差值计算. 然后,接下去就好做了 解决方案二: 类似问题的,http://bbs.csdn.net/topics/391036058,建议参考一下看看 解决方案三: 在发送数据的时候获取

Linux ftp 远程文件传输

  ftp 命令 是标准的文件传输协议的用户接口,ftp 是在TCP/IP 网络上的计算机之间传输文件的简单有效的方法.它允许用户传输ASCII 文件和二进制文件.在ftp 会话过程中,用户可以通过使用ftp 客户程序连接到另一台计算机上.从此,用户可以在目录中上下移动.列出目录内容.把文件从远程机拷贝到本地机上.把文件从本地机传输到远程系统中.需要注意的是,如果用户没有那个文件的存取权限,就不能从远程系统中获得文件或向远程系统传输文件为.了使用ftp 来传输文件,用户必须知道远程计算机上的合法

TCP/IP编程 - 1) 基础知识

1. What Is a Socket?(什么是套接字)   A socket is an abstraction through which an application may send and receive data, in muchthe same way as an open-file handle allows an application to read and write data to stablestorage.   简单来说,套接字就是网络数据传输用的软件设备.   举个

详解 Linux 下 SSH 远程文件传输命令 scp

相信各位VPSer在使用VPS时会经常在不同VPS间互相备份数据或者转移数据,大部分情况下VPS上都已经安装了Nginx或者类似的web server,直接将要传输的文件放到web server的目录,然后在目标机器上执行:wgethttp://www.vpser.net/testfile.zip 就行了.当VPS上没有安装web server和ftp server的时候或感觉上面的方法比较麻烦,那么用scp命令就会排上用场. 一.scp是什么? scp是secure copy的简写,用于在Li

标准C实现基于TCP/IP协议的文件传输

TCP/IP编程实现远程文件传输在LUNIX中一般都采用套接字(socket)系统调用. 采用客户/服务器模式,其程序编写步骤如下: 1.Socket系统调用  为了进行网络I/O,服务器和客户机两端的UNIX进程要做的第一件事是调用socket()系统调用,建立软插座,指明合适的通讯协议.格式为:  1 2 3 #include >sys/types.h> #include >sys/socket.h>    int socket(int family,int type,int 

TCP/IP协议 详解

Transmission Control Protocol/Internet Protocol的简写,中译名为传输控制协议/因特网互联协议,又名网络通讯协议,是Internet最基本的协议.Internet国际互联网络的基础,由网络层的IP协议和传输层的TCP协议组成.TCP/IP 定义了电子设备如何连入因特网,以及数据如何在它们之间传输的标准.协议采用了4层的层级结构,每一层都呼叫它的下一层所提供的网络来完成自己的需求.通俗而言:TCP负责发现传输的问题,一有问题就发出信号,要求重新传输,直到

Linux网络编程之socket文件传输示例_C 语言

本文所述示例程序是基于Linux平台的socket网络编程,实现文件传输功能.该示例是基于TCP流协议实现的socket网络文件传输程序.采用C语言编写.最终能够实现传输任何格式文件的文件传输程序. 具体实现代码如下: Server端代码如下: /************************************************************************* > File Name: Server.c > Author: SongLee ***********

FTP非交互方式文件传输

FTP(FileTransferProtocol)是文件传输协议,通过它可以从计算机传输或传输到计算机文件.FTP命令可以交互方式使用,也可以非交互方式使用.交互方式的使用较简单,命令执行时系统会逐步提示,非交互方式的实现虽然复杂,但大大方便使用者,因为FTP会自动完成所有的操作.我们在使用FTP命令时,为了操作方便,往往会按非交互方式使用,下面笔者就介绍在SCOUNIX3.0下FTP实现非交互方式的处理. 在UNIX系统下,使用RCP命令可以实现远程文件传输,但双方都必须为同一种系统,如果远程

网络编程-怎样实现TCP客户端和TCP服务器端文本信息和文件的同时传输?

问题描述 怎样实现TCP客户端和TCP服务器端文本信息和文件的同时传输? 小弟使用winsocket api实现TCP客户端和TCP服务器端,客户端和服务器端现在可以进行文本消息 传输,就是利用send和recv发送和接收消息.我想实现文本信息和文件的同时传输,但是文件传输的时候,即使新建一个线程,文件传输代码也会调用send和recv,会与文本消息的send和recv产生冲突.应该怎样解决这个问题?现在这个模型只有一个客户端和一个服务器端.改变模型也行(比如类似QQ一样,是两个客户端通信),只