标准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 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中定义: 


1

2

3

4

5

6

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中定义: 


1

2

3

4

5

6

7

8

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向服务器发送连接请求,接收从服务器端发来的数据,并将接收到的数据写入目标文件。

运行截图:

服务端:

 

客户端:

 

源程序如下: 


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

/*服务器源程序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(″ ″);

  

  printf(″ input filename:″);

  scanf(″%s″,file);

  if ((source=open(file,O_RDONLY))<0){

   perror(″open error″);

   exit(1);

  }

  printf(″ conveying,waiting...″);

  hp=gethostbyname(″server″);

  if (hp==NULL){

   perror(″return host error″);

   exit(2);

  }

  s=socket(AF_INET,SOCK_STREAM,0);

  if(s<0){

   perror(″fault to obtain socket″);

   exit(3);

  }

  sin.sin_family=AF_INET;

  sin.sin_port=htons(1500);

 

  bcopy(hp->h_addr,&sin.sin_addr,hp->h_length);

  if(bind(s,&sin,sizeof(sin))<0){

   perror(″connect tie to 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(″ OK ″);

  close(ns);

}

  close(source);

  exit(0);

  


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

/*客户机源程序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=″ conveying,waiting...″;

   int target;

   register int k,s;

   struct sockaddr_in sin;

   struct hostent *hp;

   system(″clear″);

   printf(″ ″);

   

   hp=gethostbyname(″server″);

   if(hp==NULL){

          perror(″fault to return server addresss″);

    exit(1);

   }

   s=socket(AF_INET,SOCK_STREAM,0);

   if(s<0){

    perror(″fault to obbtain socket″);

    exit(2);

   }

   sin.sin_family=AF_INET;

   sin.sin_port=htons(1500);/*端口号需与服务器程序使用的一致*/

   bcopy(hp->h_addr,&sin.sin_addr,hp->h_length);

   printf(″ connecting the server...″);

   if(connect(s,&sin,sizeof(sin),0)<0){

    perror(″cannot connect server!″);

    exit(3);

   }

   while((k=read(s,file,sizeof(file)))

   if((target=open(file,o_WRONLY|O_CREAT|O_TRUNC,0644))<0){

    perror(″cannot open file″);

    exit(4);

  }

  strcat(strs,file);

  strcat(strs,″,waiting…″);

  write(1,strs,strlen(strs));

  while((k=read(s,buf,sizeof(buf)))>0)

   write(tatget,buf,k);

  printf(″ OK ″);

  close(s);

  close(target);

  }

  

时间: 2024-05-25 18:03:51

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

基于TCP/IP协议的C++网络编程(API函数版)

源代码:http://download.csdn.net/detail/nuptboyzhb/4169959 基于TCP/IP协议的网络编程 定义变量--获得WINSOCK版本--加载WINSOCK库--初始化--创建套接字 --设置套接字选项--关闭套接字--卸载WINSOCK库--释放所有资源 整个程序架构分为两大部分,服务器端客户端. 服务器SOCKET程序流程: socket()→bind()→listen→accept()→recv()/send()→closesocket() 客户端

TCP/IP协议 详解

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

《趣学CCNA——路由与交换》一第2章 TCP/IP协议2.1 TCP协议简介

第2章 TCP/IP协议 趣学CCNA--路由与交换 在上一章,我们郑重其事地介绍了无聊的OSI七层参考模型,并浓墨重彩地讲述了其中每一层负责提供的功能.OSI模型出身名门.条理清晰,只有一个"小小的"缺点,那就是一直没人太拿它当回事儿.所以,如果对它太认真,你就败了. 我们是有职业精神的,因此在介绍OSI模型时反复强调了这个模型是如何地曲高和寡.我们在上一章中花大篇幅介绍OSI模型有三个目的:一是延续各类技术教材的惯例,以免将本书作为技术开蒙读物的读者在与别人讨论技术问题时,因全然不

《Linux高性能服务器编程》——第1章 TCP/IP协议族 1.1 TCP/IP协议族体系结构以及主要协议

第1章 TCP/IP协议族 现在Internet(因特网)使用的主流协议族是TCP/IP协议族,它是一个分层.多协议的通信体系.本章简要讨论TCP/IP协议族各层包含的主要协议,以及它们之间是如何协作完成网络通信的. TCP/IP协议族包含众多协议,我们无法一一讨论.本书将在后续章节详细讨论IP协议和TCP协议,因为它们对编写网络应用程序具有最直接的影响.本章则简单介绍其中几个相关协议:ICMP协议.ARP协议和DNS协议,学习它们对于理解网络通信很有帮助.读者如果想要系统地学习网络协议,那么R

Http、TCP/IP协议与Socket之间的区别

网络由下往上分为: 物理层-- 数据链路层-- 网络层-- IP协议 传输层-- TCP协议 会话层-- 表示层和应用层-- HTTP协议 1.TCP/IP连接 手机能够使用联网功能是因为手机底层实现了TCP/IP协议,可以使手机终端通过无线网络建立TCP连接.TCP协议可以对上层网络提供接口,使上层网络数据的传输建立在"无差别"的网络之上. 建立起一个TCP连接需要经过"三次握手": 第一次握手:客户端发送syn包(syn=j)到服务器,并进入SYN_SEND状态

技术往事:改变世界的TCP/IP协议

1.前言 作为应用层开发人员,接触最多的网络协议通常都是传输层的TCP(与之同处一层的另一个重要协议是UDP协议),但对于IP协议,对于应用程序员来说更多的印象还是IP地址这个东西,再往深一点也就很难说的清楚. 本文将简要回故TCP/IP协议的过去.简单介绍TCP/IP协议族的关系,并与大家一起直观地分享由TCP/IP协议族所构建的虚拟网络与真实世界的"连接"情况. 2.TCP/IP协议简介 互联网协议族(英语:Internet Protocol Suite,缩写为IPS),是一个网络

什么是TCP IP 网络TCP IP协议

什么是TCP.IP协议?概括的说TCP/IP协议是(传输控制协议/网间协议)TCP/IP 协议集确立了 Internet 的技术基础.全称Transmission Control Protocol/Internet Protocol.中译名为传输控制协议/因特网互联协议,又名网络通讯协议,是Internet最基本的协议.Internet国际互联网络的基础,由 网络层的IP协议和传输层的TCP协议组成.TCP/IP 定义了电子设备如何连入因特网,以及数据如何在它们之间传输的标准.协议采用了4层的层

深入浅出--iOS的TCP/IP协议族剖析&amp;amp;&amp;amp;Socket

简介 该篇文章主要回顾--TCP/IP协议族中的TCP/UDP.HTTP:还有Socket.(--该文很干,酝酿了许久!你能耐心看完吗?) 我在这个文章中,列举了常见的TCP/IP族中的协议,今天主角是--传输层协议. 传输层(Transport Layer)是OSI(七层模型)中最重要.最关键的一层,它负责总体的数据传输和数据控制的一层,传输层提供端到端(应用会在网卡注册一个端口号)的交换数据的机制,检查分组编号与次序.传输层对其上三层如会话层等,提供可靠的传输服务,对网络层提供可靠的目的地站

门面模式的典型应用 Socket 和 Http(post,get)、TCP/IP 协议的关系总结

门面模式的一个典型应用:Socket 套接字(Socket)是通信的基石,是支持TCP/IP协议的网络通信的基本操作单元.它是网络通信过程中端点的抽象表示,包含进行网络通信必须的五种信息: 连接使用的协议,本地主机的IP地址,本地进程的协议端口,远地主机的IP地址,远地进程的协议端口. 在设计模式中,Socket其实就是一个⻔面模式,它把复杂的TCP/IP协议族隐藏在Socket接⼝后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议.它是应用层与TCP/IP协议