Linux程序设计6第六章Linux网络程序设计详版课资

上传人:M****1 文档编号:568297832 上传时间:2024-07-24 格式:PPT 页数:112 大小:3.82MB
返回 下载 相关 举报
Linux程序设计6第六章Linux网络程序设计详版课资_第1页
第1页 / 共112页
Linux程序设计6第六章Linux网络程序设计详版课资_第2页
第2页 / 共112页
Linux程序设计6第六章Linux网络程序设计详版课资_第3页
第3页 / 共112页
Linux程序设计6第六章Linux网络程序设计详版课资_第4页
第4页 / 共112页
Linux程序设计6第六章Linux网络程序设计详版课资_第5页
第5页 / 共112页
点击查看更多>>
资源描述

《Linux程序设计6第六章Linux网络程序设计详版课资》由会员分享,可在线阅读,更多相关《Linux程序设计6第六章Linux网络程序设计详版课资(112页珍藏版)》请在金锄头文库上搜索。

1、第六章-Linux网络程序设计1课堂优质基本要求n1、了解TCP/IP基础知识,什么是socket,socket编程,远程过程调用。n2、掌握Linux平台数据结构的传送方法。2课堂优质TCP/IP协议概述nOSI参考模型与TCP/IP参考模型应用层表示层会话层传输层网络层数据链路层物理层应用层传输层网络层网络接口层OSI参考模型TCP/IP参考模型3课堂优质OSI参考模型与TCP/IP参考模型对应关系4课堂优质TCP/IP协议族TCP/IP实际上一个一起工作的通信家族,为网际数据通信提供通路。为讨论方便可将TCP/IP协议组大体上分为三部分:1Internet协议(IP)2传输控制协议(TC

2、P)和用户数据报文协议(UDP)3处于TCP和UDP之上的一组协议专门开发的应用程序。它们包括:TELNET,文件传送协议(FTP),域名服务(DNS)和简单的邮件传送程序(SMTP)等许多协议。5课堂优质网络层n第一部分也称为网络层。包括Internet协议(IP)、网际控制报文协议(ICMP)和地址识别协议(ARP).nInternet协议(IP)。n该协议被设计成互联分组交换通信网,以形成一个网际通信环境。它负责在源主机和目的地主机之间传输来自其较高层软件的称为数据报文的数据块,它在源和目的地之间提供非连接型传递服务。n网际控制报文协议(ICMP)。n它实际上不是IP层部分,但直接同IP

3、层一起工作,报告网络上的某些出错情况。允许网际路由器传输差错信息或测试报文。n地址识别协议(ARP)。nARP实际上不是网络层部分,它处于IP和数据链路层之间,它是在32位IP地址和48位局域网物理地址之间执行翻译的协议。6课堂优质传输层协议n第二部分是传输层协议。包括传输控制协议和用户数据报文协议。n传输控制协议(TCP)。n由于IP提供非连接型传递服务,因此TCP应为应用程序存取网络创造了条件,使用可靠的面向连接的传输层服务。该协议为建立网际上用户进程之间的对话负责。此外,还确保两个以上进程之间的可靠通信。它所提供的功能如下。n1监听输入对话建立请求。n2请求另一网络站点对话。n3可靠的发

4、送和接收数据。n4适度的关闭对话。7课堂优质应用程序部分n用户数据报文协议(UDP)。UDP提供不可靠的非连接型传输层服务,它允许在源和目的地站点之间传送数据,而不必在传送数据之前建立对话。此外,该协议还不使用TCP使用的端对端差错校验。当使用UDP时,传输层功能全都发挥,而开销却比较低。它主要用于那些不要求TCP协议的非连接型的应用程序。例如,名字服务、网络管理、视频点播和网络会议等。n最后是应用程序部分。这部分包括Telnet,文件传送协议(FTP和TFTP),简单的文件传送协议(SMTP)和域名服务(DNS)等协议。nTCP/IP使用了主干网络,能连接各种主机和LAN的多级分层结构,局部

5、用户能方便的联网,不致影响到整个网络系统。此外这种结构还有利于局部用户控制操作和管理。nTCP/IP具有两个主要功能。第一是IP在网络之间(有时在个别网络内部)提供路由选择。第二是TCP将TP传递的数据传送的接收主机那的适当的处理部件。8课堂优质Internet 协议(IP)nIP主要有以下四个主要功能:n(1)数据传送n(2)寻址n(3)路由选择n(4)数据报文的分段9课堂优质IP功能nIP的主要目的是为数据输入/输出网络提供基本算法,为高层协议提供无连接的传送服务。这意味着在IP将数据递交给接收站点以前不在传输站点和接收站点之间建立对话(虚拟链路)。它只是封装和传递数据,但不向发送者或接收

6、者报告包的状态,不处理所遇到的故障。nIP协议不注意包内的数据类型,它所知道的一切是必须将某些称为IP帧头的控制协议加到高层协议(TCP或者UDP)所接受的数据上。10课堂优质IP 地址nIP地址为32位地址,一般以4个字节表示。每个字节的数字又用十进制表示,即每个字节的数的范围是0255,且每个数字之间用点隔开,例如:192.168.0.112,这种记录方法称为“点-分”十进制记号法。IP地址的结构如下所示:网络类型网络ID主机ID11课堂优质IP地址的分类nInternet地址可分成5类:nA、B、C三类由InterNIC(Internet网络信息中心)在全球范围内统一分配,D、E类为特殊

7、地址。12课堂优质0 1 7 8 310网络地址ID主机地址IDA类IP地址10网络地址ID主机地址ID0 1 2 15 16 31B类IP地址110网络地址ID主机地址ID012 3 23 24 31C类IP地址1110广播地址ID0 1 2 3 4 31D类IP地址11110保留用于将来和试验使用 0 1 2 3 4 5 31E类IP地址13课堂优质IP地址说明nA类网络地址有128个(支持127)个网络,占有最左边的一个字节(8位)。高位(0)表示识别这种地址的类型。nB类地址使用左边两个8位用来网络寻址。两个高位(10)用于识别这种地址的类型,其余的14位用作网络地址,右边的两个字节(

8、16位)用作网络节点。nC类地址是最常见的Internet地址。三个高位(110)用于地址类型识别,左边三个字节的其余21位用于寻址。C类地址支持1046个网络,每个网络可多达256端点。nD类地址是相当新的。它的识别头是1110,用于组播,例如用于路由器修改。nE类地址为时延保留,其识别头是11110。14课堂优质传输控制协议(TCP)nTCP(传输控制协议TransmissionControlProtocol)是重要的传输层协议,传输层软件TCP的目的是允许数据同网络上的另外站点进行可靠的交换。它能提供端口编号的译码,以识别主机的应用程序,而且完成数据的可靠传输。nTCP协议具有严格的内装

9、差错检验算法确保数据的完整性。nTCP是面向字节的顺序协议,这意味着包内的每个字节被分配一个顺序编号,并分配给每包一个顺序编号。15课堂优质TCP 头信息16课堂优质用户数据报文协议nUDP(用户数据报协议UserDatagramProtocol)也是TCP/IP的传输层协议,它是无连接的,不可靠的传输服务。当接收数据时它不向发送方提供确认信息,它不提供输入包的顺序,如果出现丢失包或重份包的情况,也不会向发送方发出差错报文。nUDP的主要作用是分配和管理端口编号,以正确无误的识别运行在网络站点上的个别应用程序。由于它执行功能时具有较低的开销,因而执行速度比TCP快。它多半用于不需要可靠传输的应

10、用程序,例如网络视频点播和视频会议等。17课堂优质UDP 头信息18课堂优质TCP/IP 协议分组服务1.控制数据的协议nTCP以连接为基础,即两台电脑必须先建立一个连接,然后才能传输数据。事实上,发送和接受的电脑必须一直互相通讯和联系。nUDP是一个无连接服务,数据可以直接发送而不必在两台电脑之间建立一个网络连接。它和有连接的TCP相比,占用带宽少,但是无法确认数据是否真正到达了客户端,而客户端收到的数据也不知道是否还是原来的发送顺序。19课堂优质2.数据路由协议n路由协议分析数据包的地址并且决定传输数据到目的电脑最佳路线。他们也可以把大的数据分成几部分,并且在目的地再把他们组合起来。IP处

11、理实际上传输数据。nICMP(网络控制信息协议InternetControlMessageProtocol)处理IP的状态信息,比如能影响路由决策的数据错误或改变。nRIP(路由信息协议RoutingInformationProtocol)它是几个决定信息传输的最佳路由路线协议中的一个。nOSPF(OpenShortestPathFirst)一个用来决定路由的协议。nARP(地址解析协议AddressResolutionProtocol)确定网络上一台电脑的数字地址。nDNS(域名系统DomainNameSystem)从机器的名字确定一个机器的数字地址。nRARP(反向地址解析协议Revers

12、eAddressResolutionProtocol)确定网络上一台计算机的地址,和ARP正好相反。20课堂优质3.用户服务nBOOTP(启动协议BootProtocol)由网络服务器上取得启动信息,然后将本地的网络计算机启动。nFTP(文件传输协议FileTransferProtocol)通过国际互连网从一台计算机上传输一个或多个文件到另外一台计算机。nTELNET(远程登陆)允许一个远程登陆,使用者可以从网络上的一台机器通过TELNET连线到另一台机器,就像使用者直接在本地操作一样。nEGP(外部网关协议ExteriorGatewayProtocol)为外部网络传输路由信息。nGGP(网关

13、到网关协议Gateway-to-GatewayProtocol)在网关和网关之间传输路由协议。nIGP(内部网关协议InteriorGatewayProtocol)在内部网络传输路由信息。21课堂优质4.其他协议(也为网络提供了重要的服务)nNFS(网络文件系统NetworkFileSystem)允许将一台机器的目录被另一台机器上的用户安装(Mount)到自己的机器上,就像是对本地文件系统进行操作一样进行各式各样的操作。nNIS(网络信息服务NetworkInformationService)对整个网络用户的用户名、密码进行统一管理,简化在NIS服务下整个网络登陆的用户名密码检查。nRPC(远

14、程过程调用RemoteProcedureCall)通过它可以允许远程的应用程序通过简单的、有效的手段联系本地的应用程序,反之也是。nSMTP(简单邮件传输协议SimpleMailTransferProtocol)一个专门为电子邮件在多台机器中传输的协议,平时发邮件的SMTP服务器提供的必然服务。nSNMP(简单网络管理协议SimpleNetworkManagementProtocol)这是一项为超级用户准备的服务,超级用户可以通过它来进行简单的网络管理。22课堂优质端口nTCP和UDP协议是以IP协议为基础的传输,为了方便多种应用程序,区分不同应用程序的数据和状态,引入了端口的概念。n端口是一

15、个16位的整数类型值,通常称这个值为端口号。如果是服务程序,则需要对某个端口进行绑定,这样某个客户端可以方位本主机上的此端口来与应用程序进行通信。由于IP地址只能对主机进行区分,而加上端口号就可以对区分此主机上的应用程序。实际上,IP地址和端口号的组合,可以确定在网络上的一个程序通路,端口号实际上是操作系统标识应用程序的一种方法。23课堂优质主机字节序和网络字节序n在使用网络进行程序设计中会碰到的一个问题是字节序的问题,这在基于单机或者同类型机器进行开发的过程中很少遇到。由于网络的特点是将Internet上不同的网络设备和主机进行连接和通信,这决定了使用网络进行开发的程序的特点就是要兼容各种类

16、型的设备,其中的数据在不同的设备上要有唯一的含义。字节序的问题是上述情况下的典型问题。24课堂优质字节序的含义n字节序的问题是由于CPU对整数在内存中的存放方式造成的。字节多于一个字节的数据类型在内存中的存放顺序叫主机字节序。最常见的字节序有两种,小端字节序和大端字节序:n小端字节序,即LittleEndian(简称LE),将数据的最低字节放在内存的起始位置。小端字节序的特点是内存地址较低的位存放数据的低位,内存地址高的位存放数据的高位,与思维的习惯。采用低字节序的CPU有x86架构的intel系列产品。n大端字节序,即BigEndian(简称BE),将数据的高字节放在内存的起始位置。大端字节

17、序的特点是内存中低字节位置存放数据的高位字节,内存中的高位字节存放数据的较低字节数据,与思维习惯不一致,但是与实际数据的表达方式是一致的。采用大端字节序的CPU有PowerPC的UNIX系统。25课堂优质网络字节序的转换n网络的字节序标准规定为大端字节序,不同平台上会对主机字节序进行转化,成为网络字节序后再进行传送,到主机后再转化为主机字节序,数据的传输就不会产生传输造成的问题了。同一个数据在不同的平台上可以使用网络字节序的转换函数来实现。26课堂优质什么是套接字(SOCKET)n套接口是对网络中不同主机上应用进程之间进行双向通信的端点的抽象,一个套接口就是网络上进程通信的一端,提供了应用层进

18、程利用网络协议栈交换数据的机制。27课堂优质Socket 的功能nSocket的英文原意就是“孔”或“插座”,将电话系统与面向连接的Socket机制相比,有着惊人相似的地方。以一个国家级的电话网为例。n电话的通话双方相当于相互通信的两个进程;通话双方所在的地区(享有一个全局唯一的区号)相当于一个网络,区号是它的网络地址;区内的一个单位的交换机相当于一台主机,主机分配给每个用户的局内号码相当于Socket号.n任何用户在通话之前,首先要占有一部电话机,相当于申请一个Socket号;同时要知道对方的电话号码,相当于对方有一个Socket。n然后向对方拨号呼叫,相当于发出连接请求(假如对方不在同一区

19、内,还要拨对方区号,相当于给出网络地址)。对方假如在场并空闲(相当于通信的另一主机开机且可以接受连接请求),拿起电话话筒,双方就可以正式通话,相当于连接成功。n双方通话的过程,是向电话机发出信号和从电话机接受信号的过程,相当于向Socket发送数据和从Socket接受数据。通话结束后,一方挂起电话机,相当于关闭Socket,撤消连接。28课堂优质套接字基础n从套接字所处的地位来讲,套接字上联应用进程,下联网络协议栈,是应用程序通过网络协议栈进行通信的接口,是应用程序与网络协议栈进行交互的接口。29课堂优质套接字基础(续)n从实现的角度来讲,非常复杂。套接字是一个复杂的软件机构,包含了一定的数据

20、结构,包含许多选项,由操作系统内核管理。n从使用的角度来讲,非常简单。对于套接字的操作形成了一种网络应用程序的编程接口(API)。n操作套接字的编程接口函数称作套接字编程接口,套接字是它的操作对象。n总之,套接字是网络通信的基石。30课堂优质常用的socketn流式套接字:它提供基于TCP协议的双向、可靠、有序且不重复的无记录边界的数据流。n数据报套接字:它提供基于UDP协议的双向数据流,但不一定可靠、有序和不重复。n原始套接字:它提供网络下层通信协议的直接访问。一般用于开发新的网络层协议,如新的IP协议等。31课堂优质UDP32课堂优质TCP33课堂优质三种表示套接字地址的结构n(1)str

21、uct sockaddr这个结构用来存储套接字地址。数据定义:struct sockaddr unsigned short sa_family; /* address族, AF_xxx */char sa_data14; /* 14 bytes的协议地址*/;sa_family 一般来说,都是“AF_INET”。sa_data 包含了一些远程电脑的地址、端口和套接字的数目,它里面的数据是杂溶在一切的。34课堂优质三种表示套接字地址的结构(续)n(2). struct sockaddr_in为了处理struct sockaddr, 程序员建立了另外一个相似的结构struct sockaddr_i

22、n:struct sockaddr_in (“in” 代表“Internet”)struct sockaddr_in short int sin_family; /* Internet地址族*/unsigned short int sin_port; /* 端口号*/struct in_addr sin_addr; /* Internet地址*/unsigned char sin_zero8; /* 添0(和struct sockaddr一样大小)*/;这个结构提供了方便的手段来访问socket address(struct sockaddr)结构中的每一个元素。35课堂优质三种表示套接字地址

23、的结构(续)n(3)struct in_addr专门用来存储IP地址,其定义如下:/* 因特网地址(a structure for historical reasons) */struct in_addr unsigned long s_addr;如果你声明了一个“ ina ” 作为一个struct sockaddr_in 的结构, 那么“ina.sin_addr.s_addr”就是4 个字节的IP 地址(按网络字节顺序排放)。需要注意的是,即使你的系统仍然使用联合而不是结构来表示struct in_addr,你仍然可以用上面的方法得到4 个字节的IP 地址.36课堂优质三种表示套接字地址的结

24、构(续)n(4).这些数据结构的一般用法:首先,定义一个Sockaddr_in的结构实例,并将它清零。比如:structsockaddr_inmyad;memset(&myad,0,sizeof(structsockaddr_in);然后,为这个结构赋值,比如:myad.sin_family=AF_INET;myad.sin_port=htons(8080);myad.sin_addr.s_addr=htonl(INADDR-ANY);第三步:在函数调用中使用时,将这个结构强制转换为sockaddr类型。如:accept(listenfd,(sockaddr*)(&myad),&addrlen

25、);37课堂优质本机字节顺序和网络字节顺序n在具体计算机中的多字节数据的存储顺序,称为本机字节顺序。多字节数据在网络协议报头中的存储顺序,称为网络字节顺序。n在网络上面有着许多类型的机器,这些机器在表示数据的字节顺序是不同的,比如i386芯片是低字节在内存地址的低端,高字节在高端,而alpha芯片却相反.n为了统一起来,在Linux下面,有专门的字节转换函数.unsignedlonginthtonl(unsignedlonginthostlong)unsignedshortinthtons(unisgnedshortinthostshort)unsignedlongintntohl(unsig

26、nedlongintnetlong)unsignedshortintntohs(unsignedshortintnetshort)n在这四个转换函数中,h代表host,n代表network.s代表shortl代表long第一个函数的意义是将本机器上的long数据转化为网络上的long.其他几个函数的意义也差不多.38课堂优质点分十进制的IP地址的转换n(1)inet_aton将strptr所指的字符串转换成32位的网络字节序二进制值。includeintinet_aton(constchar*strptr,structin_addr*addrptr);n(2)inet_addr功能同上,返回地

27、址。int_addr_tinet_addr(constchar*strptr);n(3)inet_ntoa将32位网络字节序二进制地址转换成点分十进制的串。char*inet_ntoa(stuctin_addrinaddr);39课堂优质域名服务在网络上标志一台机器可以用IP或者是用域名.那么我们怎么去进行转换呢?structhostent*gethostbyname(constchar*hostname)可以将机器名(如)转换为一个结构指针.在这个结构里面储存了域名的信息structhostent*gethostbyaddr(constchar*addr,intlen,inttype)可以将

28、一个32位的IP地址(C0A80001)转换为结构指针.这两个函数失败时返回NULL且设置h_errno错误变量,调用h_strerror()可以得到详细的出错信息structhostent的定义:structhostentchar*h_name;/*主机的正式名称*/char*h_aliases;/*主机的别名*/inth_addrtype;/*主机的地址类型AF_INET*/inth_length;/*主机的地址长度对于IP4是4字节32位*/char*h_addr_list;/*主机的IP地址列表*/#defineh_addrh_addr_list0/*主机的第一个IP地址*/40课堂优

29、质套接字的工作过程41课堂优质初等网络函数n1 socket #include int socket(int domain, int type,int protocol) socket为网络通讯做基本的准备.成功时返回文件描述符,失败时返回-1。通过errno可知道出错的详细情况. n参数说明:domain:说明我们网络程序所在的主机采用的通讯协族(AF_UNIX和AF_INET等)。AF_UNIX只能够用于单一的Unix系统进程间通信,而AF_INET是针对Internet的,因而可以允许在远程主机之间通信当我们 man socket时发现 domain可选项是 PF_*而不是AF_*,因为

30、glibc是posix的实现 所以用PF代替了AF,不过我们都可以使用的. type:我们网络程序所采用的通讯协议。SOCK_STREAM表明我们用的是TCP协议,这样会提供按顺序的,可靠,双向,面向连接的比特流. SOCK_DGRAM 表明我们用的是UDP协议,这样只会提供定长的,不可靠,无连接的通信。 SOCK_RAW 原始套接字,用来直接访问IP协议。protocol:由于我们指定了type,所以这个地方我们一般只要用0来代替就可以了。42课堂优质初等网络函数(续)n2 bind int bind(int sockfd, struct sockaddr *my_addr, int add

31、rlen) bind将本地的端口同socket返回的文件描述符捆绑在一起.成功是返回0,失败的情况和socket一样。n参数说明sockfd:是由socket调用返回的文件描述符. addrlen:是sockaddr结构的长度. my_addr:是一个指向sockaddr的指针. 43课堂优质构造套接字地址举例int listenfd;struct sockaddr_in server_addr;listenfd=socket(AF_INET,SOCK_STREAM,0);bzero(&server_addr,sizeof(server_addr); server_addr.sin_famil

32、y=AF_INET;server_addr.sin_port=htons(80);inet_pton(AF_INET, “211.83.241.244”, & server_addr.sin_addr);bind(listenfd,& server_addr,sizeof(struct sockaddr_in) 44课堂优质初等网络函数(续)n3 listen int listen(int sockfd,int backlog) listen函数将bind的文件描述符变为监听套接字。返回的情况和bind一样。n参数说明sockfd:是bind后的文件描述符.。backlog:设置请求排队的最大

33、长度.当有多个客户端程序和服务端相连时, 使用这个表示可以介绍的排队长度。45课堂优质初等网络函数(续)n4 accept int accept(int sockfd, struct sockaddr *addr,int *addrlen)accept成功时返回最后的服务器端的文件描述符,这个时候服务器端可以向该描述符写信息了。失败时返回-1 。n参数说明sockfd:是listen后的文件描述符.。addr,addrlen是用来给客户端的程序填写的,服务器端只要传递指针就可以了.。bind,listen和accept是服务器端用的函数,accept调用时,服务器端的程序会一直阻塞到有一个 客

34、户程序发出了连接, accept成功时返回最后的服务器端的文件描述符。46课堂优质初等网络函数(续)n5 connect int connect(int sockfd, struct sockaddr * serv_addr,int addrlen) connect函数是客户端用来同服务端连接的。成功时返回0,sockfd是同服务端通讯的文件描述符 。失败时返回-1。n参数说明sockfd:socket返回的文件描述符. serv_addr:储存了服务器端的连接信息.其中sin_add是服务端的地址 addrlen:serv_addr的长度 47课堂优质完整的读写函数n一旦我们建立了连接,我们

35、的下一步就是进行通信了.n在Linux下面把我们前面建立的通道 看成是文件描述符,这样服务器端和客户端进行通信时候,只要往文件描述符里面读写东西了. 就象我们往文件读写一样。n1 写函数write ssize_twrite(intfd,constvoid*buf,size_tnbytes)write函数将buf中的nbytes字节内容写入文件描述符fd.成功时返回写的字节数.失败时返回-1. 并设置errno变量. 在网络程序中,当我们向套接字文件描述符写时有俩种可能. 1)write的返回值大于0,表示写了部分或者是全部的数据. 2)返回的值小于0,此时出现了错误.我们要根据错误类型来处理.

36、 如果错误为EINTR表示在写的时候出现了中断错误. 如果为EPIPE表示网络连接出现了问题(对方已经关闭了连接). 48课堂优质写实例intmy_write(intfd,void*buffer,intlength)intbytes_left;intwritten_bytes;char*ptr;ptr=buffer;bytes_left=length;while(bytes_left0)/*开始写*/written_bytes=write(fd,ptr,bytes_left);if(written_bytes0)bytes_read=read(fd,ptr,bytes_read);if(byt

37、es_read0)if(errno=EINTR)bytes_read=0;elsereturn(-1);elseif(bytes_read=0)break;bytes_left-=bytes_read;ptr+=bytes_read;return(length-bytes_left);51课堂优质完整的读写函数(续)n3 数据的传递 有了上面的两个函数,我们就可以向客户端或者是服务端传递数据了.比如我们要传递一个结构.可以使用如下方式 :/*客户端向服务端写*/structmy_structmy_struct_client;write(fd,(void*)&my_struct_client,s

38、izeof(structmy_struct);/*服务端的读*/charbuffersizeof(structmy_struct);struct*my_struct_server;read(fd,(void*)buffer,sizeof(structmy_struct);my_struct_server=(structmy_struct*)buffer;在网络上传递数据时我们一般都是把数据转化为char类型的数据传递.接收的时候也是一样的。注意的是我们没有必要在网络上传递指针(因为传递指针是没有任何意义的,我们必须传递指针所指向的内容) 。52课堂优质面向连接的传输层套接字举例n服务器端程序/

39、*服务器程序(server.c)*/#include#include#include#include#include#include#include#includeintmain(intargc,char*argv)intsockfd,new_fd;structsockaddr_inserver_addr;structsockaddr_inclient_addr;intsin_size,portnumber;charhello=Hello!AreYouFine?n;if(argc!=2)fprintf(stderr,Usage:%sportnumberan,argv0);exit(1);if(

40、portnumber=atoi(argv1)0)fprintf(stderr,Usage:%sportnumberan,argv0);exit(1);/*服务器端开始建立socket描述符*/if(sockfd=socket(AF_INET,SOCK_STREAM,0)=-1)fprintf(stderr,Socketerror:%sna,strerror(errno);exit(1);/*服务器端填充sockaddr结构*/bzero(&server_addr,sizeof(structsockaddr_in);server_addr.sin_family=AF_INET;server_ad

41、dr.sin_addr.s_addr=htonl(INADDR_ANY);server_addr.sin_port=htons(portnumber);/*捆绑sockfd描述符*/if(bind(sockfd,(structsockaddr*)(&server_addr),sizeof(structsockaddr)=-1)fprintf(stderr,Binderror:%sna,strerror(errno);exit(1);/*监听sockfd描述符*/if(listen(sockfd,5)=-1)fprintf(stderr,Listenerror:%sna,strerror(err

42、no);exit(1);53课堂优质while(1)/*服务器阻塞,直到客户程序建立连接*/sin_size=sizeof(structsockaddr_in);if(new_fd=accept(sockfd,(structsockaddr*)(&client_addr),&sin_size)=-1)fprintf(stderr,Accepterror:%sna,strerror(errno);exit(1);fprintf(stderr,“Servergetconnectionfrom%sn”,inet_ntoa(client_addr.sin_addr);if(write(new_fd,h

43、ello,strlen(hello)=-1)fprintf(stderr,“WriteError:%sn”,strerror(errno);exit(1);/*这个通讯已经结束*/close(new_fd);/*循环下一个*/close(sockfd);exit(0);54课堂优质面向连接的传输层套接字举例n客户端程序/*客户端程序client.c*/#include#include#include#include#include#include#include#includeintmain(intargc,char*argv)intsockfd;charbuffer1024;structso

44、ckaddr_inserver_addr;structhostent*host;intportnumber,nbytes;if(argc!=3)fprintf(stderr,Usage:%shostnameportnumberan,argv0);exit(1);if(host=gethostbyname(argv1)=NULL)fprintf(stderr,Gethostnameerrorn);exit(1);if(portnumber=atoi(argv2)h_addr);55课堂优质/*客户程序发起连接请求*/if(connect(sockfd,(structsockaddr*)(&ser

45、ver_addr),sizeof(structsockaddr)=-1)fprintf(stderr,ConnectError:%san,strerror(errno);exit(1);/*连接成功了*/if(nbytes=read(sockfd,buffer,1024)=-1)fprintf(stderr,ReadError:%sn,strerror(errno);exit(1);buffernbytes=0;printf(Ihavereceived:%sn,buffer);/*结束通讯*/close(sockfd);exit(0);56课堂优质无连接的套接字编程使用数据报套接字开发网络应用

46、程序,既可以采用客户/服务器模式,也可以采用对等模式。57课堂优质客户/服务器模式58课堂优质UDP通信机制n在服务器端服务器先使用AF_INET协议族创建UDP数据报类型的套接字,该socket类型为SOCK_DGRAM;然后服务器调用bind函数,给此UDP套接字绑定一个端口;调用recvfrom函数在指定的端口上等待客户端发送来的UDP数据报。n在客户端先通过socket函数创建一个数据报套接字;然后由操作系统为这个套接字分配端口号;此后客户端就可以使用sendto函数向一个指定的地址发送一个UDP套接字。在服务器端收到套接字后,从recvfrom中返回,在对数据进行处理之后,再用sen

47、dto函数处理的结果返回客户端。59课堂优质UDP与TCP的比较nUDP服务器通常是非连接的因而UDP服务器进程不需要象TCP服务器那样在倾听套接字上接收新建的连接;UDP只需要在绑定的端口上等待客户机发送来的UDP数据报,并对其进行处理和响应。一个TCP服务器进程只有在完成了对某客户机的服务后,才能为其他的客户机提供服务;UDP客户机并不独占服务器,UDP服务器只是接收数据报,处理并返回结果。60课堂优质UDP的应用场合nUDP支持广播和多播。如果要使用广播和多播,必须使用UDP套接字。nUDP套接字没有连接的建立和终止过程。UDP只需要两个分组来交换一个请求和应答。nUDP不适合海量数据的

48、传输。61课堂优质无连接的传输层套接字 n两个常用的函数#includeintrecvfrom(intsockfd,void*buf,intlen,unsignedintflags,structsockaddr*fromint*fromlen)intsendto(intsockfd,constvoid*msg,intlen,unsignedintflags,structsockaddr*tointtolen)sockfd,buf,len的意义和read,write一样,分别表示套接字描述符,发送或接收的缓冲区及大小recvfrom负责从sockfd接收数据,如果from不是NULL,那么在fr

49、om里面存储了信息来源的情况,如果对信息的来源不感兴趣,可以将from和fromlen设置为NULL.sendto负责向to发送信息.此时在to里面存储了收信息方的详细资料.62课堂优质UDP实例n一个实例程序编译好后,运行时需指定双方所使用的IP地址和端口号,第一个参数是对方的IP地址,然后是对方的端口号,之后是本端的IP地址和端口号。例如在test1的终端输入:a.out192.168.1.1004321192.168.1.1685678同时在test2上输入:a.out192.168.1.1685678192.168.1.1004321然后双方都可以发送信息给对方了63课堂优质/*fir

50、ststepinudpprogramming*/#include#include#include#include#defineBUFLEN255intmain(intargc,char*argv)structsockaddr_inpeeraddr,localaddr;intsockfd;charrecmsgBUFLEN+1;intsocklen,n;if(argc!=5)printf(%sn,argv0);exit(0);sockfd=socket(AF_INET,SOCK_DGRAM,0);if(sockfd0)fprintf(stderr,socketcreatingerrorinudpt

51、alk.c!n);exit(1);socklen=sizeof(structsockaddr_in);memset(&peeraddr,0,socklen);peeraddr.sin_family=AF_INET;peeraddr.sin_port=htons(atoi(argv2);if(inet_pton(AF_INET,argv1,&peeraddr.sin_addr)=0)printf(WrongdestIPaddress!n);exit(0);64课堂优质memset(&localaddr,0,socklen);localaddr.sin_family=AF_INET;localad

52、dr.sin_port=htons(atoi(argv4);if(inet_pton(AF_INET,argv3,&localaddr.sin_addr)=0)printf(WrongsourceIPaddress!n);exit(0);if(bind(sockfd,&localaddr,socklen)0)fprintf(stderr,bindlocaladdresserrorinudptalk.c!n);exit(2);if(fgets(recmsg,BUFLEN,stdin)=NULL)exit(0);if(sendto(sockfd,recmsg,strlen(recmsg),0,&p

53、eeraddr,socklen)0)fprintf(stderr,sendtoerrorinudptalk.c!n);perror();exit(3);for(;)n=recvfrom(sockfd,recmsg,BUFLEN,0,&peeraddr,&socklen);if(n0)fprintf(stderr,);perror();exit(4);elserecmsgn=0;printf(peer:%s,recmsg);if(fgets(recmsg,BUFLEN,stdin)=NULL)exit(0);if(sendto(sockfd,recmsg,strlen(recmsg),0,&pe

54、eraddr,socklen)0)fprintf(stderr,sendtoerrorinudptalk.c!n);perror();exit(3);65课堂优质对第一个UDP例程的思考n思考:1.只有来自对方IP和端口号的数据报才予以处理,如何过滤掉其它数据报?2.双方发送和接收交替进行,只要有一方发出数据报,对方阻塞的状态就能消除。如果一个数据报丢失,通信双方都在recvfrom中阻塞,永远等待。超时机制的设置?66课堂优质对第一个UDP例程的思考n解决第一个问题:接收数据后,加入对数据报地址的检验:if(memcmp(recvaddr,perraddr,socklen)!=0)conti

55、nue;这样就将来自其他地址的数据报拒之门外了。67课堂优质对第一个UDP例程的思考n解决第二个问题:前面提到的sock选项SO_RCVTIMEO就可以完成阻塞超时的设置。在程序中加入:#includeStructtimevalrecto;Inttolen=sizeof(structtimeval);/*建立socket等操作/rcvto.tv_sec=3;/*这两句对rcvto定时为3秒0毫秒*/rccvto.tv_usec=0;Setsockopt(sockfd,SOL_SOCKET,SO_RCVTIMEO,&rcvto,tolen);getsockopt(sockfd,SOL_SOCKE

56、T,SO_RCVTIMEO,&rcvto,&tolen);Printf(“receivetimeoutsettedis%ldsecond%ldmillisecondn”,rcvto.tv_sec,rcvto.tv_usec);n如果显示Receivetimeoutsettedis3second0millisecond,那么就设置成功了;n如果结果是Receivetimeoutsettedis0second0millisecond,就意味着超时时间为无穷大。n设置了SO_RCVTIMEO,那么在发生超时后,recvfrom将返回,返回值为-1,同时errno被置为EWOULDBLOCK。68课堂

57、优质高级套接字函数n1、recv和sendrecv和send函数提供了和read和write差不多的功能。不过它们提供了第四个参数来控制读写操作。intrecv(intsockfd,void*buf,intlen,intflags)intsend(intsockfd,void*buf,intlen,intflags)前面的三个参数和read,write一样,第四个参数可以是0或者是以下的组合:MSG_DONTROUTE不查找路由表不查找路由表MSG_OOB接受或者发送带外数据接受或者发送带外数据MSG_PEEK查看数据查看数据,并不从系统缓冲区移走数据并不从系统缓冲区移走数据MSG_WAITA

58、LL等待所有数据等待所有数据69课堂优质nMSG_DONTROUTE:是send函数使用的标志。这个标志告诉IP协议,目的主机在本地网络上面,没有必要查找路由表。这个标志一般用网络诊断和路由程序里面。nMSG_OOB:表示可以接收和发送带外的数据。关于带外数据我们以后会解释的。nMSG_PEEK:是recv函数的使用标志。表示只是从系统缓冲区中读取内容,而不清楚系统缓冲区的内容。这样下次读的时候,仍然是一样的内容。一般在有多个进程读写数据时可以使用这个标志。nMSG_WAITALL:是recv函数的使用标志。表示等到所有的信息到达时才返回。使用这个标志的时候recv回一直阻塞,直到指定的条件满

59、足,或者是发生了错误。1)当读到了指定的字节时,函数正常返回.返回值等于len。2)当读到了文件的结尾时,函数正常返回,返回值小于len。3)当操作发生错误时,返回-1,且设置错误为相应的错误号(errno)。n如果flags为0,则和read,write一样的操作。70课堂优质高级套接字函数(续)nrecvmsg和sendmsgrecvmsg和sendmsg可以实现前面所有的读写函数的功能。intrecvmsg(intsockfd,structmsghdr*msg,intflags)intsendmsg(intsockfd,structmsghdr*msg,intflags)nstructm

60、sghdrvoid*msg_name;intmsg_namelen;structiovec*msg_iov;intmsg_iovlen;void*msg_control;intmsg_controllen;intmsg_flags;nstructiovecvoid*iov_base;/*缓冲区开始的地址*/size_tiov_len;/*缓冲区的长度*/71课堂优质nmsg_name和msg_namelen当套接字是非面向连接时(UDP),它们存储接收和发送方的地址信息。msg_name实际上是一个指向structsockaddr的指针,msg_name是结构的长度。当套接字是面向连接时,这两

61、个值应设为NULLnmsg_iov和msg_iovlen指出接受和发送的缓冲区内容。msg_iov是一个结构指针,msg_iovlen指出这个结构数组的大小。msg_control和msg_controllen这两个变量是用来接收和发送控制数据时的msg_flags指定接受和发送的操作选项。(和recv,send的选项一样)72课堂优质高级套接字函数(续)n套接字的关闭关闭套接字有两个函数:closeshutdown用close时和我们关闭文件一样。nshutdownintshutdown(intsockfd,inthowto)TCP连接是双向的(是可读写的),当我们使用close时,会把读写

62、通道都关闭,有时侯我们希望只关闭一个方向,这个时候我们可以使用shutdown。针对不同的howto,系统回采取不同的关闭方式。73课堂优质nshutdownintshutdown(intsockfd,inthowto)TCP连接是双向的(是可读写的),当我们使用close时,会把读写通道都关闭,有时侯我们希望只关闭一个方向,这个时候我们可以使用shutdown。针对不同的howto,系统回采取不同的关闭方式。n系统为我们提供了获取和修改套接字结构中一些属性的函数,通过修改这些属性,我们可以调整套接字的性能,进而调整某些应用程序的性能。74课堂优质套接字选项n1getsockopt和setso

63、ckoptintgetsockopt(intsockfd,intlevel,intoptname,void*optval,socklen_t*optlen)intsetsockopt(intsockfd,intlevel,intoptname,constvoid*optval,socklen_t*optlen)level指定控制套接字的层次.可以取三种值:1)SOL_SOCKET:通用套接字选项.2)IPPROTO_IP:IP选项.3)IPPROTO_TCP:TCP选项.optname指定控制的方式(选项的名称)。optval获得或者是设置套接字选项.根据选项名称的数据类型进行转换。75课堂优

64、质选项名称说明数据类型=SOL_SOCKET-SO_BROADCAST允许发送广播数据intSO_DEBUG允许调试intSO_DONTROUTE不查找路由intSO_ERROR获得套接字错误intSO_KEEPALIVE保持连接intSO_LINGER延迟关闭连接structlingerSO_OOBINLINE带外数据放入正常数据流intSO_RCVBUF接收缓冲区大小intSO_SNDBUF发送缓冲区大小intSO_RCVLOWAT接收缓冲区下限intSO_SNDLOWAT发送缓冲区下限intSO_RCVTIMEO接收超时structtimevalSO_SNDTIMEO发送超时struct

65、timevalSO_REUSERADDR允许重用本地地址和端口intSO_TYPE获得套接字类型intSO_BSDCOMPAT与BSD系统兼容int=76课堂优质=IPPROTO_IP-IP_HDRINCL在数据包中包含IP首部intIP_OPTINOSIP首部选项intIP_TOS服务类型IP_TTL生存时间int=IPPRO_TCP-TCP_MAXSEGTCP最大数据段的大小intTCP_NODELAY不使用Nagle算法int=77课堂优质套接字选项(续)n2ioctlioctl可以控制所有的文件描述符的情况,这里介绍一下控制套接字的选项.定义格式:includeintioctl(int

66、fd,longcmd,unsignedlong*argp);参数:fd是需要操作的套接字描述符;cmd是属性类别;argp是属性的参数。详细的选项请用manioctl_list查看.=iiioctl的控制选项-SIOCATMARK是否到达带外标记intFIOASYNC异步输入/输出标志intFIONREAD缓冲区可读的字节数int=78课堂优质套接字选项(续)n3、fcntl定义格式:includeIntfcntl(intfd,intcmd,longarg);参数:fd是需要操作的套接字描述符;cmd是属性类别,cmd可以是如下值:nF_SETFL:arg为O_NONBLOCK时进入非阻塞模式

67、,为0是进入阻塞模式;nF_GETFL:获得属性;nF_SETOWN:用来设置套接字属主,用来接收数据SIGIO和SIGURG;nF_GETOWN:用来获得上面设置的套接字属主信息。79课堂优质系统IO与服务器模型 n在Linux/UNIX 下,有主要有4种I/O 模型:阻塞I/O:最常用、最简单、效率最低非阻塞I/O:可防止进程阻塞在I/O操作上I/O 多路复用:允许同时对多个I/O进行控制信号驱动I/O:一种异步通信模型n一般来说,程序进行输入操作有两步:1等待有数据可以读2将数据从系统内核中拷贝到程序的数据区。对于一个对套接字的输入操作,第一步一般来说是等待数据从网络上传到本地。当数据包

68、到达的时候,数据将会从网络层拷贝到内核的缓存中;第二步是从内核中把数据拷贝到程序的数据区中。80课堂优质阻塞I/O 模式n阻塞I/O 模式是最普遍使用的I/O 模式。大部分程序使用的都是阻塞模式的I/O 。n缺省的,一个套接字建立后所处于的模式就是阻塞I/O 模式。n前面学习的很多读写函数在调用过程中会发生阻塞。读操作中的read、readv、recv、recvfrom、recvmsg写操作中的write、writev、send、sendmag另外:accept、connect81课堂优质读阻塞n以read函数为例:进程调用read函数从套接字上读取数据,当套接字的接收缓冲区中还没有数据可读,

69、函数read将发生阻塞。它会一直阻塞下去,等待套接字的接收缓冲区中有数据可读。经过一段时间后,缓冲区内接收到数据,于是内核便去唤醒该进程,通过read访问这些数据。如果在进程阻塞过程中,对方发生故障,那这个进程将永远阻塞下去。82课堂优质Socket()Bind()Recvfrom()Sendto()Close()Socket()Bind()sendto()recvfrom()Close()套接字缓冲区套接字缓冲区中没有数据中没有数据读阻塞读阻塞套接字缓冲区中数据套接字缓冲区中数据到达,进行数据复制到达,进行数据复制等待等待函数返回读到数据函数返回读到数据83课堂优质阻塞的talk程序for(

70、;)scanf();sendto();recvfrom();printf();for(;) scanf(); sendto(); recvfrom(); printf(); 84课堂优质写阻塞n在写操作时发生阻塞的情况要比读操作少。主要发生在要写入的缓冲区的大小小于要写入的数据量的情况下。n这时,写操作不进行任何拷贝工作,将发生阻塞。n一量发送缓冲区内有足够的空间,内核将唤醒进程,将数据从用户缓冲区中拷贝到相应的发送数据缓冲区。nUDP不用等待确认,没有实际的发送缓冲区,所以UDP协议中不存在发送缓冲区满的情况,在UDP套接字上执行的写操作永远都不会阻塞。85课堂优质阻塞I/O 模式实例n示例

71、:在阻塞模式下单进程对两个套接字的轮询#include#include#include#include#include#defineSERVE_PORT8003intmain(intargc,char*argv)intsockfd1,sockfd2;intconn_flag;intnum_bytes;charbuffer512;structsockaddr_inserv_addr1,serv_addr2;86课堂优质sockfd1=socket(AF_INET,SOCK_STREAM,0);if(socfd10);fprintf(stderr,”socketerror!n”);exit(1);

72、sockfd2=socket(AF_INET,SOCK_STREAM,0);if(socfd20);fprintf(stderr,”socketerror!n”);exit(1);87课堂优质bxero(&serv_addr1,sizeof(serv_addr1);serv_addr1.sin_family=AF_INET;erv_addr1.sin_port=htons(SERVE_PORT);bxero(&serv_addr2,sizeof(serv_addr1);serv_addr2.sin_family=AF_INET;erv_addr2.sin_port=htons(SERVE_PO

73、RT);conn_flag=connetct(sockfd1,(structsockaddr*)&serv_addr1,sizeof(structsockaddr1);if(conn_flag=-1)fprintf(stderr,”connecyerror!n”);exit(1);conn_flag=connetct(sockfd1,(structsockaddr*)&serv_addr1,sizeof(structsockaddr1);if(conn_flag=-1)fprintf(stderr,”connecyerror!n”);exit(1);88课堂优质while(1)num_byte

74、s=recv(sockfd1,buffer,sizeof(buffer),0);if(num_bytes=0)fprintf(stderr,”nodata!n”);elseif(num_byte0)fprintf(stderr,”recverror!n”);exit(1);elsefprintf(“recvthedata:%sn”,buffer);num_bytes=recv(sockfd2,buffer,sizeof(buffer),0);if(num_bytes=0)fprintf(stderr,”nodata!n”);elseif(num_byte0)fprintf(stderr,”re

75、cverror!n”);exit(1);elsefprintf(“recvthedata:%sn”,buffer);89课堂优质非阻塞模式I/On当我们将一个套接字设置为非阻塞模式,我们相当于告诉了系统内核:“当我请求的I/O 操作不能够马上完成,你想让我的进程进行休眠等待的时候,不要这么做,请马上返回一个错误给我。”n当一个应用程序使用了非阻塞模式的套接字,它需要使用一个循环来不停地测试是否一个文件描述符有数据可读(称做polling)。n应用程序不停的polling 内核来检查是否I/O操作已经就绪。这将是一个极浪费CPU 资源的操作。n这种模式使用中不是很普遍。90课堂优质套接字套接字缓

76、冲区缓冲区中没有中没有数据数据套接字套接字缓冲区缓冲区中没有中没有数据数据套接字缓冲套接字缓冲区中数据到区中数据到达,进行数达,进行数据复制据复制用户态核心态readread返回readreadread返回read返回多次调用多次调用readEWOULDBLOCKEWOULDBLOCK读到数据读到数据 91课堂优质非阻塞模式的实现nfcntl()函数当你一开始建立一个套接字描述符的时候,系统内核就被设置为阻塞状态。如果你不想你的套接字描述符是处于阻塞状态的,那么你可以使用函数fcntl()设置一个套接字的标志为O_NONBLOCK来实现非阻塞。fcntl()函数声明如下:#include #i

77、nclude int fcntl (int fd, int cmd, long arg);(P141)n可以通过下列操作来完成整个过程:intflagflag=fcntl(sockfd,F_GETFL,0);flag|=O_NONBLOCK;fcntl(sockfd,F_SETFL,flag);92课堂优质非阻塞式I/O的实例#include#include#include#include#include#defineSERVE_PORT8003intmain(intargc,char*argv)intsockfd1,sockfd2;intconn_flag;intnum_bytes;char

78、buffer512;structsockaddr_inserv_addr1,serv_addr2;sockfd1=socket(AF_INET,SOCK_STREAM,0);if(socfd10);fprintf(stderr,”socketerror!n”);exit(1);sockfd2=socket(AF_INET,SOCK_STREAM,0);if(socfd20);fprintf(stderr,”socketerror!n”);exit(1);93课堂优质bxero(&serv_addr1,sizeof(serv_addr1);serv_addr1.sin_family=AF_INE

79、T;erv_addr1.sin_port=htons(SERVE_PORT);bxero(&serv_addr2,sizeof(serv_addr1);serv_addr2.sin_family=AF_INET;erv_addr2.sin_port=htons(SERVE_PORT);conn_flag=connetct(sockfd1,(structsockaddr*)&serv_addr1,sizeof(structsockaddr1);if(conn_flag=-1)fprintf(stderr,”connecyerror!n”);exit(1);conn_flag=connetct(s

80、ockfd1,(structsockaddr*)&serv_addr1,sizeof(structsockaddr1);if(conn_flag=-1)fprintf(stderr,”connecyerror!n”);exit(1);94课堂优质intval;val=fcntl(sockfd1,F_GETFL,0);if(val0)fprintf(stderr,”getsocketatrributeerror”);exit(1);fcntl(sockfd1,F_SETFL,val|O_NONBLOCK);val=fcntl(sockfd2,F_GETFL,0);if(val0)fprintf(

81、stderr,”getsocketatrributeerror”);exit(1);fcntl(sockfd2,F_SETFL,val|O_NONBLOCK);while(1)num_bytes=recv(sockfd1,buffer,sizeof(buffer),0);if(num_bytes=0)fprintf(stderr,”nodata!n”);elseif(num_byte0)fprintf(stderr,”recverror!n”);exit(1);elsefprintf(“recvthedata:%sn”,buffer);num_bytes=recv(sockfd2,buffer

82、,sizeof(buffer),0);if(num_bytes=0)fprintf(stderr,”nodata!n”);elseif(num_byte0)fprintf(stderr,”recverror!n”);exit(1);elsefprintf(“recvthedata:%sn”,buffer);95课堂优质多路复用IO的基本原理n应用程序中同时处理多路输入输出流,若采用阻塞模式,将得不到预期的目的;n若采用非阻塞模式,对多个输入进行轮询,但又太浪费CPU时间;n若设置多个进程,分别处理一条数据通路,将新产生进程间的同步与通信问题,使程序变得更加复杂;n比较好的方法是使用I/O多路复

83、用。其基本思想是:先构造一张有关描述符的表,然后调用一个函数,它要到这些描述符中的一个已准备好进行I/O时才返回。返回时,它告诉进程那个描述符已准备好可以进行I/O。96课堂优质多路复用I/On首先介绍一个函数select#inxlude#include#includeintselect(intmaxfd,fd_set*read_set,fd_set*write_set,fd_set*except_set,structtimeval*timeout)参数说明:maxfd所有监控的文件描述符中最大的那一个加197课堂优质函数selectnRead_set所有要读的文件文件描述符的集合nWrite

84、_set所有要的写文件文件描述符的集合nExcept_set其他要向我们通知的文件描述符nTimeout超时设置.Null:一直阻塞,直到有文件描述符就绪或出错0:仅仅检测文件描述符集的状态,然后立即返回非0:在指定时间内,如果没有事件发生,则超时返回。98课堂优质函数selectn在我们调用select时进程会一直阻塞直到以下的一种情况发生.有文件可以读.有文件可以写.超时所设置的时间到.n为了设置文件描述符我们要使用几个宏:FD_SET将fd加入到fdsetFD_CLR将fd从fdset里面清除FD_ZERO从fdset中清除所有的文件描述符FD_ISSET判断fd是否在fdset集合中9

85、9课堂优质多路复用I/On宏的形式:voidFD_SET(intfd,fd_set*fdset)voidFD_CLR(intfd,fd_set*fdset)voidFD_ZERO(fd_set*fdset)intFD_ISSET(intfd,fd_set*fdset)100课堂优质使用select的一个例子intuse_select(int*readfd,intn)fd_setmy_readfd;intmaxfd;inti;maxfd=readfd0;for(i=1;imaxfd)maxfd=readfdi;while(1)/*将所有的文件描述符加入*/FD_ZERO(&my_readfd);

86、for(i=0;in;i+)FD_SET(readfdi,*my_readfd);/*进程阻塞*/select(maxfd+1,&my_readfd,NULL,NULL,NULL);/*有东西可以读了*/for(i=0;in;i+)if(FD_ISSET(readfdi,&my_readfd)/*原来是我可以读了*/we_read(readfdi);101课堂优质多路复用I/On在使用I/O 多路技术的时候,我们调用select()函数时候阻塞,而不是我们来调用recvfrom(或recv)的时候阻塞。n当我们调用select 函数阻塞的时候,select 函数等待数据报套接字进入读就绪状态。

87、n当select 函数返回的时候,也就是套接字可以读取数据的时候。n这时候我们就可以调用recvfrom函数来将数据拷贝到我们的程序缓冲区中。102课堂优质应用程序应用程序系统内核系统内核select没有数没有数据就绪据就绪系统调用recvfrom数据就绪,数据就绪,进行拷贝进行拷贝系统调用返回可用的描述符拷贝结束拷贝结束处理数据正常返回等待数据从内核拷贝数据进程在select处阻塞,等待描述符中的一个变为可操作程序在数据拷贝时阻塞103课堂优质多路复用I/On和阻塞模式相比较,多路复用的高级之处在于,它能同时等待多个文件描述符,而这些文件描述符(套接字描述符)其中的任意一个进入读就绪状态,s

88、elect()函数就可以返回。n多路复用除了可以使用select函数实现外,还可以用poll函数来实现。与select函数相比,poll调用形式有所不同,它与流系统紧紧相关。select()是BSD中的实现方式,而poll()则是AT&T的SVR4中的实现方式。104课堂优质poll函数n函数调用格式:#include#includeintpoll(structpollfdfdarray,unsignedlongnfds,inttimeout)n与select不同,poll不是为每个条件构造一个描述符,而是构造一个pollfd结构数组,每个数组元素指定一个描述符编号以及对其所关心的条件。str

89、uctpollfdintfd;/*要检查的文件描述符*/shortevents;/*对fd感兴趣的文件*/shortrevents;/*对fd已发生的文件*/105课堂优质多路复用I/OnI/O 多路服用技术并不只局限与网络程序应用上。几乎所有的程序都可以找到应用I/O多路复用的地方:当一个客户端需要同时处理多个文件描述符的输入输出操作的时候(一般来说是标准的输入输出和网络套接字), I/O 多路复用技术将会有机会得到使用。当程序需要同时进行多个套接字的操作的时候。如果一个TCP 服务器程序同时处理正在侦听网络连接的套接字和已经连接好的套接字。如果一个服务器程序同时使用TCP 和UDP 协议。

90、如果一个服务器同时使用多种服务并且每种服务可能使用不同的协议(比如inetd就是这样的)。106课堂优质多路复用I/O的应用实例使用多路复用的UDPTalk程序使用多路复用的TCP程序107课堂优质信号驱动I/O 模式n信号驱动I/O模式是应用了中断技术,让内核在文件描述符就绪的时候使用SIGIO 信号来通知我们。我们将这种模式称为信号驱动I/O 模式。n使用这种模式,我们首先需要允许套接字使用信号驱动I/O ,还要安装一个SIGIO 的处理函数。n在这种模式下,系统调用将会立即返回,然后我们的程序可以继续做其他的事情。n当数据就绪的时候,系统会向我们的进程发送一个SIGIO 信号。这样我们就

91、可以在SIGIO信号的处理函数中进行I/O 操作(或是我们在函数中通知主函数有数据可读)。n对于信号驱动I/O 模式,它的先进之处在于它在等待数据的时候不会阻塞,程序可以做自己的事情。n当有数据到达的时候,系统内核会向程序发送一个SIGIO 信号进行通知n这样我们的程序就可以获得更大的灵活性,因为我们不必为等待数据进行额外的编码。108课堂优质信号驱动I/O的实现过程用户态核心态设置信号SIGIO的处理函数信号处理函数readread返回有数据,发送SIGIO信号拷贝拷贝数据数据程序执行109课堂优质信号驱动I/O 模式n为了在一个套接字上使用信号驱动I/O 操作,下面这三步是所必须的:一个和

92、SIGIO 信号的处理函数必须设定。套接字的拥有者必须被设定。一般来说是使用fcntl 函数的F_SETOWN 参数来进行设定拥有者。如果第3个参数是正整数,则表示进程号,此时将由该指定的进行作为接帐者。如果第3个参数是一个负整数,则表示指定由该数的绝对值对应的进程组作来接收数据。套接字必须被允许使用异步I/O。一般是通过调用fcntl 函数的F_SETFL 命令,O_ASYNC 为参数来实现。110课堂优质信号驱动I/O 模式nUDP 套接字的SIGIO 信号在UDP 协议上使用异步I/O 非常简单这个信号将会在这个时候产生:套接字收到了一个数据报的数据包。套接字发生了异步错误。当我们在使用

93、UDP 套接字异步I/O 的时候,我们使用recvfrom()函数来读取数据报数据或是异步I/O 错误信。111课堂优质信号驱动I/O 模式nTCP 套接字的SIGIO 信号不幸的是,异步I/O 几乎对TCP 套接字而言没有什么作用。因为对于一个TCP 套接字来说, SIGIO 信号发生的几率太高了,所以SIGIO 信号并不能告诉我们究竟发生了什么事情。在TCP 连接中, SIGIO 信号将会在这个时候产生:在一个监听某个端口的套接字上成功的建立了一个新连接。一个断线的请求被成功的初始化。一个断线的请求成功的结束。套接字的某一个通道(发送通道或是接收通道)被关闭。套接字接收到新数据。套接字将数据发送出去。发生了一个异步I/O 的错误。112课堂优质

展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 办公文档 > 工作计划

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号