套接字网络编程基础课件.ppt

上传人:牧羊曲112 文档编号:3678977 上传时间:2023-03-15 格式:PPT 页数:111 大小:2.20MB
返回 下载 相关 举报
套接字网络编程基础课件.ppt_第1页
第1页 / 共111页
套接字网络编程基础课件.ppt_第2页
第2页 / 共111页
套接字网络编程基础课件.ppt_第3页
第3页 / 共111页
套接字网络编程基础课件.ppt_第4页
第4页 / 共111页
套接字网络编程基础课件.ppt_第5页
第5页 / 共111页
点击查看更多>>
资源描述

《套接字网络编程基础课件.ppt》由会员分享,可在线阅读,更多相关《套接字网络编程基础课件.ppt(111页珍藏版)》请在三一办公上搜索。

1、第2章 套接字网络编程基础,1,2.1 UNIX套接字网络编程接口的 产生与发展,2.2 套接字编程的基本概念,2.3 面向连接的套接字编程,2.4 无连接的套接字编程,2.5 原始套接字,从应用程序实现的角度,应用程序如何方便地使用协议栈软件进行通信呢?,2.1 UNIX套接字网络编程接口的产生与发展,2.1.1 问题的提出(P24),如果能在应用程序与协议栈软件之间提供一个软件接口,就可以方便客户机与服务器软件的编程。UNIX系统的开发者提出了套接字应用程序编程接口。,套接字应用程序编程接口是网络应用程序通过网络协议栈进行通信时所使用的接口,即应用程序与协议栈软件之间的接口,简称套接字编程

2、接口(Socket API)。,具体地说,套接字编程接口给出了应用程序能够调用的一组函数,每个函数完成一个与协议栈交互的基本操作。,2.1.1 问题的提出 P24,套接字编程接口定义了应用程序与协议栈软件进行交互时可以使用的一组操作,决定了应用程序使用协议栈的方式、应用程序所能实现的功能、以及开发具有这些功能的程序的方法。,加州大学伯克利(Berkley)分校开发并推广了一个包括TCP/IP互联协议的UNIX,称为BSD UNIX(Berkeley Software Distribution UNIX)操作系统,套接字编程接口是这个操作系统的一部分。后来的许多操作系统并没有另外搞一套其它的编程

3、接口,而是选择了对于套接字编程接口的支持。包括各种UNIX的派生版,后来出现的Windows,及各种Linux版本。,2.1.2 套接字编程接口起源于UNIX系统(P25),2.1 UNIX套接字网络编程接口的产生与发展,套接字规范规定了一系列有关的C函数,为在UNIX环境使用TCP/IP进行网络通信提供了一套应用程序编程接口,得以实现并广泛流传。套接字编程接口广泛应用在各种网络编程中,成为事实上的工业标准。由于这个套接字规范最早是由Berkeley大学开发的,一般将它称为Berkeley Sockets规范。,2.1.2 套接字编程接口起源于UNIX系统(P25),2.1 UNIX套接字网络

4、编程接口的产生与发展,1)Windows系统微软公司以UNIX操作系统的Berkeley Sockets规范为范例,定义了Windows Socktes规范,全面继承了套接字网络编程接口。详细内容将在第三章介绍。,2.1.3 套接字编程接口的继承和发展(P25),2.1 UNIX套接字网络编程接口的产生与发展,2)Linux系统 Linux操作系统中的套接字网络编程接口几乎与UNIX操作系统的套接字网络编程接口一样。,要想实现套接字编程接口,可以采用两种实现方式:1.一种是在操作系统的内核中增加相应的软件来实现,套接字函数是操作系统内核的一部分。2.另一种是通过开发操作系统之外的函数库来实现。

5、具有与UNIX套接字相同的函数名和参数。实现了程序的可移植性,程序源代码不必改动即可移植到另一个操作系统。只是使用时要链接库函数。,2.1.4 套接字编程接口的两种实现方式 P25,2.1 UNIX套接字网络编程接口的产生与发展,UNIX操作系统对文件和所有其它的输入/输出设备采用一种统一的的操作模式,就是“打开-读-写-关闭”(open-read-write-close)的I/O模式。当TCP/IP协议被集成到UNIX内核中的时候,相当于在UNIX系统中引入了一种新型的I/O操作,就是应用程序通过网络协议栈来交换数据。,2.1.5 套接字通信与UNIX操作系统的输入/输出的关系,2.1 UN

6、IX套接字网络编程接口的产生与发展,在UNIX系统的实现中,套接字是完全与其他I/O集成在一起的。操作系统和应用程序都将套接字编程接口也看作一种I/O机制。这体现在三个方面:,2.1.5 套接字通信与UNIX操作系统的输入/输出的关系,1)操作的过程类似。使用套接字也像使用I/O一样“打开-读写-关闭”模式。2)操作方法类似。操作系统为文件、设备、进程通信、网络通信提供单独的一组描述符,套接字通信同样使用描述符方法。3)过程名也可以相同。例如read和write。,但是,用户进程与网络协议的交互作用实际要比用户进程与传统的I/O设备相互作用要复杂得多。首先,进行网络操作的两个进程是在两台不同的

7、计算机,如何连接;其次,要建立一种通用机制来支持多种网络协议。,2.1.5 套接字通信与UNIX操作系统的输入/输出的关系,还有,使用套接字的应用程序必须说明许多细节。仅仅提供open、read、write、close四个过程远远不够。为避免单个套接字函数参数过多,套接字编程接口的设计者还定义了其它多个函数。,2.2 套接字编程的基本概念,套接口是对网络中不同主机上应用进程之间进行双向通信的端点的抽象,一个套接口就是网络上进程通信的一端,提供了应用层进程利用网络协议栈交换数据的机制。,图2.1 电气插座与电话插座的作用,2.2.1 什么是套接字(SOCKET)(P27),我们应当从多个层面来理

8、解套接字这个概念。1)从套接字所处的地位来讲,套接字上联应用进程,下联网络协议栈,是应用程序通过网络协议栈进行通信的接口,是应用程序与网络协议栈进行交互的接口。,2.2.1 什么是套接字,图2.2 应用进程、套接口、网络协议栈及操作系统的关系,2)从实现的角度来讲,非常复杂。套接字是一个复杂的软件机构,包含了一定的数据结构,包含许多选项,由操作系统内核管理。3)从使用的角度来讲,非常简单。调用相应的过程后,生成的套接字就是套接字描述符,用一个整数来代表。对于套接字的操作形成了一种网络应用程序的编程接口(API)。这里把这一套操作套接字的编程接口函数称作套接字编程接口,套接字是它的操作对象。总之

9、,套接字是网络通信的基石。,2.2.1 什么是套接字,1通信域 套接字存在于通信域中,通信域是为了处理一般的进程通过套接字通信而引入的一种抽象概念,套接字通常只和同一域中的套接字交换数据。套接字实际是通过网络协议栈来通信,通信双方要使用相同的通信协议。在Internet通信域中,所有计算机都使用Internet协议族(即TCP/IP协议族)来通信。,2.2.2 套接字的特点(P28),2套接字具有三种类型 P29 每一个正被使用的套接字都有它确定的类型,只有相同类型的套接字才能相互通信。(1)数据报套接字(Datagram SOCKET)数据报套接字提供无连接的不保证可靠的独立的数据报传输服务

10、。在Internet通信域中,数据报套接字使用UDP数据报协议形成的进程间通路,具有UDP协议为上层所提供的服务的所有特点。,2.2.2 套接字的特点,图2.3 在Internet通信域中,数据报套接字基于UDP协议,2.2.2 套接字的特点,(2)流式套接字(Stream SOCKET)流式套接字提供双向的、有序的、无重复的、无记录边界的可靠的数据流传输服务。在Internet通信域中,流式套接字使用TCP协议形成的进程间通路,具有TCP协议为上层所提供的服务的所有特点,在使用流式套接字传输数据之前,必须在数据的发送端和接收端之间建立连接,如图2.4所示。,2.2.2 套接字的特点,图2.4

11、 在Internet通信域中,流式套接字基于TCP协议,2.2.2 套接字的特点,(3)原始式套接字(RAW SOCKET),原始式套接字允许对较低层次的协议,如IP、ICMP直接访问,用于检验新的协议的实现。,2.2.2 套接字的特点,3套接字由应用层的通信进程创建,并为其服务 就是说,每一个套接字都有一个相关的应用进程,操作该套接字的代码是该进程的组成部分。,2.2.2 套接字的特点,4使用确定的IP地址和传输层端口号,往往在生成套接字的描述符后,要将套接字与计算机上的特定的IP地址和传输层端口号相关联,这个过程称为绑定。一个套接字要使用一个确定的三元组网络地址信息,才能使它在网络中唯一地

12、被标识。,2.2.2 套接字的特点,(1)不管是采用对等模式或者客户机/服务器模式,通信双方的应用程序都需要开发。(2)双方所交换数据的结构和交换数据的顺序有特定的要求,不符合现在成熟的应用层协议,甚至需要自己去开发应用层协议,自己设计最适合的数据结构和信息交换规程。在这种情况下,套接字很有用,因为套接字直接与传输层连接,提供了网络应用进程之间交换数据的方法,程序员编程有很大的自由度。,2.2.3 套接字的应用场合(P30),2.2 套接字编程的基本概念,2.2.4 套接字使用的数据类型和相关的问题 P301三种表示套接字地址的结构 在套接字编程接口中,专门定义了三种结构的数据类型,用来存储协

13、议相关的网络地址,在套接字编程接口的函数调用中要用到它们。,2.2 套接字编程的基本概念,2.2.4 套接字使用的数据类型和相关的问题,(1)sockaddr结构,针对各种通信域的套接字,存储它们的地址信息。struct sockaddr unsigned short sa_family;/地址家族char sa_data14;/14字节协议地址,(2)sockaddr_in结构,专门针对Internet通信域,存储套接字相关的网络地址信息,例如IP地址,传输层端口号等信息。struct sockaddr_in short int sin_family;/协议簇 unsigned short

14、int sin_port;/端口号 struct in_addr sin_addr;/IP 地址 unsigned char sin_zero8;/全为0,2.2.4 套接字使用的数据类型和相关的问题,(3)in_addr结构,专门用来存储 IP地址。struct in_addr unsigned long s_addrl;,2.2.4 套接字使用的数据类型和相关的问题,(4)这些数据结构的一般用法:第1步,定义一个sockaddr_in的结构实例,并将它清零。比如:struct sockaddr_in myad;memset(,2.2.4 套接字使用的数据类型和相关的问题,第3步,在函数调用

15、中使用时,将这个结构强制转换为sockaddr类型。如:accept(listenfd,(sockaddr*)(,第2步,为这个结构赋值,比如:myad.sin_family=AF_INET;myad.sin_port=htons(8080);myad.sin_addr.s_addr=htonl(INADDR-ANY);,2.2.4 套接字使用的数据类型和相关的问题,2本机字节顺序和网络字节顺序 P31 不同的计算机中存放多字节的顺序可能不同,有的先低后高,有的先高后低。在具体计算机中的多字节数据的存储顺序,称为本机字节顺序。多字节数据在网络协议报头中的存储顺序,称为网络字节顺序。,2.2.4

16、 套接字使用的数据类型和相关的问题,1网络字节顺序格式,在网络传输过程中,IP地址被保存为32位二进制数。TCP/IP协议规定,在低位存储地址中保存数据的高位字节,这种存储顺序格式被称为网络字节顺序。数据按照32位二进制数为一组进行传输,因为采用网络字节顺序,所以数据的传输顺序是由高位至低位进行的。,存储地址,2001,2002,2003,2004,2000,高位字节1,低位字节1,高位字节2,低位字节2,.,2主机字节顺序格式,不同的主机在对IP地址进行存储时使用的格式也不同。有些操作系统的IP地址存储顺序与网络字节顺序格式相同,而Intel x86系列主机的主机字节顺序格式则与网络字节顺序

17、格式正好相反。,存储地址,2001,2002,2003,2004,2000,高位字节1,低位字节1,高位字节2,低位字节2,.,网络应用程序要在不同的计算机中运行,本机字节顺序是不同的,但是,网络字节顺序是一定的。所以,应用程序在编程的时候,在把IP地址和端口号装入套接字的时候,应当把它们从本机字节顺序转换为网络字节顺序;相反,在本机输出时,应将它们从网络字节顺序转换为本机字节顺序。,2.2.4 套接字使用的数据类型和相关的问题,字节序转换的方法,套接字编程接口特为解决这个问题设置了四个函数:htons():短整数本机顺序转换为网络顺序,用于端口号。htonl():长整数本机顺序转换为网络顺序

18、,用于IP地址。ntohs():短整数网络顺序转换为本机顺序,用于端口号。ntohl():长整数网络顺序转化为本机顺序,用于IP地址。这四个函数将被转换的数值作为函数的参数,函数返回值是转换后的结果。,2.2.4 套接字使用的数据类型和相关的问题,3点分十进制的IP地址的转换 P31在因特网中,IP地址常常用点分十进制的表示方法,但在套接字中,IP地址是无符号的长整型数,是网络字节顺序的地址。套接字编程接口设置了两个函数,专门用于两种形式的IP地址的转换。,2.2.4 套接字使用的数据类型和相关的问题,1)inet_addr函数,点分十进制形式-网络字节顺序unsigned long inet

19、_addr(const char*cp)入口参数cp:点分十进制形式的IP地址。返回值:网络字节顺序的IP地址,是无符号的长整数。,2.2.4 套接字使用的数据类型和相关的问题,2)inet_ntoa函数,网络字节顺序-点分十进制形式 char*inet_ntoa(struct in_addr in)入口参数in:包含长整型IP地址的 in_addr 结构变量。返回值:指向点分十进制IP地址的字符串的指针。,2.2.4 套接字使用的数据类型和相关的问题,通常,我们使用域名来标识站点,可以将文字型的主机域名直接转换成IP地址:struct hostent*gethostbyname(const

20、char*name);入口参数:是站点的主机域名字符串,返回值:是指向hostent 结构的指针,hostent结构包含主机名,主机别名数组,返回地址的类型(一般是AF-INET),地址长度的字节数,已符合网络字节顺序的主机网络地址等。,4域名服务 P32,2.2.4 套接字使用的数据类型和相关的问题,2.3.1 可靠的传输控制协议(P32)传输控制协议(TCP)是TCP/IP协议簇中主要的传输层协议,负责为应用层提供可靠的传输服务。TCP建立在网络层的IP之上,为应用层进程提供一个面向连接的、端到端的、完全可靠的(无差错、无丢失、无重复和无失序)全双工的流传输服务,允许网络中的两个应用程序建

21、立一个虚拟连接,并在任何一个方向上发送数据,把数据当作一个双向字节流进行交换,然后终止连接。每一TCP连接可靠地建立,从容地终止,在终止发生之前的所有数据都会被可靠地传递。,2.3 面向连接的套接字编程,2.3 面向连接的套接字编程,2.3.2 套接字的工作过程 P33,1.创建网络套接字函数 socket()2.绑定一个地址端口对 bind()3.监听本地端口 listen()4.接受一个网络请求 accept()5.连接目标网络服务器 connect()6.写入数据函数 write()7.读取数据函数 read()8.关闭套接字函数 close(),TCP网络编程流程,TCP网络编程有两种

22、模式:1服务器端的程序设计模式 2客户端的程序设计模式服务器模式创建一个服务进程,等待客户端用户的连接,接收到用户的连接请求后,根据用户的请求进行处理;客户端模式则根据目的服务器的IP地址和端口进行连接,向服务器发送请求并对服务器的响应进行数据处理。,TCP网络编程流程,流程主要分为:套接字初始化-socket()套接字与端口的绑定-bind()设置服务器的侦听连接-listen()接受客户端连接-accept()发送数据-write()接收数据-read()并进行数据处理 处理完毕的套接字关闭-close(),1.服务器端的程序设计模式,客户端模式分为:套接字初始化-socket()连接服务

23、器-connect()发送数据-write()接收数据-read()并进行数据处理 最后的套接字关闭-close(),2.客户端的程序设计模式,客户端与服务器在连接、读写数据、关闭过程中有交互过程。,3.客户端与服务器的交互过程,UNIX套接字编程接口的系统调用(P33)1socket()-创建套接字 系统调用socket()函数建立一个协议族为Protofamily、协议类型为type、协议编号为protocol的套接字文件描述符。socket()函数在socket.h文件中定义int socket(int Protofamily,int Type,int Protocol);使用时注意把s

24、ocket.h包含进来#include#include,2.3.2 套接字的工作过程,int socket(int Protofamily,int Type,int Protocol);socket()函数用来获得文件描述符sockfd。如果函数调用成功,会返回一个表示这个套接字的文件描述符(file descriptor),失败的时候返回1。使用举例:sockfd=SOCKET(AF_INET,SOCK_STREAM,0);Linux系统中,socket()的定义在/usr/include/sys/socket.hint socket(int _domain,int _type,int _p

25、rotocol),UNIX套接字编程接口的系统调用,UNIX套接字编程接口的系统调用,2 bind()-绑定套接字到指定的地址 服务器端在建立套接字文件描述符成功后,需要对套接字进行IP地址和端口的绑定,才能进行数据的接收和发送操作。bind()函数将长度为addlen的struct sockadd类型的结构体变量my_addr与sockfd绑定在一起,将sockfd绑定到某IP和端口上。如果是客户端使用connect()函数则没有绑定的必要。绑定的函数原型如下:int bind(int sockfd,struct sockaddr*my_addr,int addrlen);使用时注意把soc

26、ket.h包含进来#include#include,UNIX套接字编程接口的系统调用,int bind(int sockfd,struct sockaddr*my_addr,int addrlen);Linux系统中,bind()的定义在/usr/include/sys/socket.hint bind(int _fd,_CONST_SOCKADDR_ARG _addr,socklen_t _len),UNIX套接字编程接口的系统调用,3listen()-启动监听 函数listen()用来初始化服务器可连接队列,服务器处理客户端连接请求的时候是顺序处理的,同一时间仅能处理一个客户端连接。当多个

27、客户端的连接请求同时到来的时候,服务器并不是同时处理,而是将不能处理的客户端连接请求放到等待队列中,这个队列的长度由listen()函数来定义。listen()函数的原型如下:int listen(int sockfd,int queuesize);其中的queuesize表示等待队列的长度。注意把socket.h包含进来#include#include,UNIX套接字编程接口的系统调用,int listen(int sockfd,int queuesize);举例:if(listen(sockfd,qlenth)0)出错 Linux系统中,listen()的定义在/usr/include/s

28、ys/socket.hint listen(int _fd,int _n),举例:listen(sockfd,10);,图2.6 监听套接字使用缓冲区接纳多个客户端的连接请求,UNIX套接字编程接口的系统调用,UNIX套接字编程接口的系统调用,4accept()-接收连接请求 当一个客户端的连接请求到达服务器主机侦听的端口时,此时客户端的连接会在队列中等待,直到服务器接收请求。函数accept()成功执行后,返回一个新的套接字文件描述符来表示客户端的连接,客户端连接信息通过这个新描述符获得。int accept(int sockfd,struct sockaddr*addr,int*addrl

29、en);int clientfd;/定义响应套接字描述符变量int addrlen=sizeof(sockaddr);/获得套接字地址结构长度。struct sockaddr_in cltsockaddr;/定义用于返回客户端地址的结构。,UNIX套接字编程接口的系统调用,int accept(int sockfd,struct sockaddr*addr,int*addrlen);举例:clientfd=accept(sockfd,(sockaddr*)(,5connect()-请求建立连接客户端在建立套接字之后,不需要进行地址绑定就可以直接连接服务器。int connect(int soc

30、kfd,struct sockaddr*service_addr,int addrlen);使用时注意包含socket.h#include#include 举例:if(connect(sockfd,(struct sockaddr*)(&serv_addr),sizeof(struct sockaddr)0)报错,并退出,UNIX套接字编程接口的系统调用,int connect(int sockfd,struct sockaddr*service_addr,int addrlen);Linux系统中,connect()的定义在/usr/include/sys/socket.hint conne

31、ct(int _fd,_CONST_SOCKADDR_ARG _addr,socklen_t _len);,UNIX套接字编程接口的系统调用,6read()和 write()-读/写套接字 当服务器端在接收到一个客户端的连接后,可以通过套接字描述符进行数据的写入操作。对套接字进行写入的形式和过程与普通文件的操作方式一致,内核会根据文件描述符的值来查找所对应的属性,当为套接字的时候,会调用相对应的内核函数。int read(int sockfd,void*buffer,int len);int write(int sockfd,void*buffer,int len);,UNIX套接字编程接口的

32、系统调用,7 send()和recv()-向套接字发送和从套接字接收int send(int sockfd,char*buf,int len,int flags);在Linux中:send(int _fd,_const void*_buf,size_t _n,int _flags)int recv(int sockfd,char*buf,int len,int flags);在Linux中:recv(int _fd,void*_buf,size_t _n,int _flags),UNIX套接字编程接口的系统调用,8close()-关闭套接字 可以使用close()函数关闭socket连接,函数

33、的作用是关闭已经打开的socket连接,内核会释放相关的资源,关闭套接字之后就不能再使用这个套接字文件描述符进行读写操作了。int close(int sockfd);,UNIX套接字编程接口的系统调用,2.3.3 面向连接的套接字编程实例 P341实例的功能 服务器对来访的客户计数,并向客户报告这个计数值。客户建立与服务器的一个连接并等待它的输出。每当连接请求到达时,服务器生成一个可打印的ASCII串信息,将它在连接上发回,然后关闭连接。客户显示收到的信息,然后退出。,面向连接的套接字编程实例,例如,对于服务器接收的第10次客户连接请求,该客户将收到并打印如下信息:This server h

34、as been contacted 10 times.,2实例程序的命令行参数 实例是UNIX环境下的C程序,客户和服务器程序在编译后,均以命令行的方式执行。服务器程序执行时可以带一个命令行参数,是用来接受请求的监听套接字的协议端口号。这个参数是可选的。如果不指定端口号,代码将使用程序内定的缺省端口号5188。,面向连接的套接字编程实例,客户程序执行时可以带两个命令行参数:一个是服务器所在计算机的主机名,另一个是服务器监听的协议端口号。这两个参数都是可选的。如果没有指定协议端口号,客户使用程序内定的缺省值5188。如果一个参数也没有,客户使用缺省端口和主机名localhost,localhos

35、t是映射到客户所运行的计算机的一个别名。允许客户与本地机上的服务器通信,对调试是很有用的。,面向连接的套接字编程实例,3客户程序代码(P35)/*-*程序:client.c*目的:创建一个套接字,通过网络连接一个服务器,并打印来自服务器的信息。*语法:client host port*host-运行服务器的计算机的名字*port-服务器监听套接字所用协议端口号*注意:两个参数都是可选的。如果未指定主机名,客户使用localhost;如果未指定端口号,客户将使用PROTOPORT中给定的缺省协议端口号。*-*/,面向连接的套接字编程实例-客户程序代码,#include#include/*UNIX

36、下,套接字的相关包含文件。*/#include#include#include#include#include#define PROTOPORT 5188/*默认协议端口号*/extern int errno;/*声明errorno*/char localhost=“localhost”;/*默认主机名*/,面向连接的套接字编程实例-客户程序代码,main(int argc,char*argv)/*指向主机列表中一个条目的指针*/struct hostent*ptrh;/*存放服务器端网络地址的结构*/struct sockaddr_in servaddr;/*客户端的套接字描述符*/ints

37、ockfd;/*服务器端套接字协议端口号*/intport;char*host;/*服务器主机名指针*/int n;/*读取的字符数*/*缓冲区,接收服务器发来的数据*/char buf1000;,面向连接的套接字编程实例-客户程序代码,/*清空sockaddr结构*/memset(char*)/*否则,使用缺省端口号*/,面向连接的套接字编程实例-客户程序代码,if(port0)/*如果端口号是合法的数值,就将它装入网络地址结构*/servaddr.sin_port=htons(u_short)port);else/*否则,打印错误信息并退出*/fprintf(stderr,”bad por

38、t number%sn”,argv2);exit(1);/*检查主机参数并指定主机名*/if(argc1)host=argv1;/*如果指定了主机名参数,就使用它*/elsehost=localhost;/*否则,使用默认值*/,面向连接的套接字编程实例-客户程序代码,/*将主机名转换成相应的IP地址并复制到servaddr 结构中*/*从服务器主机名得到相应的IP地址*/ptrh=gethostbyname(host);/*检查主机名的有效性,无效则退出*/if(char*)ptrh=null)fprintf(stderr,”invalid host:%sn”,host);exit(1);m

39、emcpy(,面向连接的套接字编程实例-客户程序代码,/*创建一个套接字*/sockfd=SOCKET(AF_INET,SOCK_STREAM,0);if(sockfd 0)fprintf(stderr,”socket creation failedn”);exit(1);/*请求连接到服务器*/if(connect(sockfd,(struct sockaddr*),面向连接的套接字编程实例-客户程序代码,/*从套接字反复读数据,并输出到用户屏幕上*/n=recv(sockfd,buf,sizeof(buf),0);while(n 0)write(1,buf,n);/*1是标准输出*/n=r

40、ecv(sockfd,buf,sizeof(buf),0);/*关闭套接字*/closesocket(sockfd);/*终止客户程序*/exit(0);,面向连接的套接字编程实例-客户程序代码,4服务器实例代码(P37)/*-*程序:server.c*目的:分配一个套接字,然后反复执行如下几步:*(1)等待客户的下一个连接*(2)发送一个短消息给客户*(3)关闭与客户的连接*(4)转向(1)步*命令行语法:server port*port 服务器端监听套接字使用的协议端口号*注意:端口号可选。如果未指定端口号,服务器使用PROTOPORT中指定的默认端口号*-*/,面向连接的套接字编程实例-

41、服务器程序代码,#include#include#include#include#include#include#define PROTOPORT 5188/*监听套接字的缺省协议端口号*/#define QLEN 6/*监听套接字的请求队列大小*/int visits=0;/*对于客户连接的计数*/,面向连接的套接字编程实例-服务器程序代码,main(int argc,char*argv)struct hostent*ptrh;/*指向主机列表中一个条目的指针*/struct sockaddr_in servaddr;/*存放服务器网络地址的结构*/struct sockaddr_in cl

42、ientaddr;/*存放客户网络地址的结构*/int listenfd;/*监听套接字描述符*/int clientfd;/*响应套接字描述符*/int port;/*协议端口号*/int alen;/*地址长度*/char buf1000;/*供服务器发送字符串所用的缓冲区*/,面向连接的套接字编程实例-服务器程序代码,/*清空sockaddr结构*/memset(char*)/否则,使用缺省端口号,面向连接的套接字编程实例-服务器程序代码,if(port 0)/*测试端口号是否合法*/servaddr.sin_port=htons(u_short)port);else/*打印错误信息并退

43、出*/fprintf(stderr,”bad port number%sn”,argv1);exit(1);/*创建一个用于监听的流式套接字*/listenfd=SOCKET(AF_INET,SOCK_STREAM,0);if(listenfd 0)fprintf(stderr,“socket creation failedn”);exit(1);,面向连接的套接字编程实例-服务器程序代码,/*将本地地址绑定到监听套接字*/if(bind(listenfd,(struct sockaddr*),面向连接的套接字编程实例-服务器程序代码,/*服务器主循环接受和处理来自客户端的连接请求*/whil

44、e(1)/*接受客户端连接请求,并生成响应套接字*/alen=sizeof(clientaddr);if(clientfd=accept(listenfd,(struct sockaddr*)/*关闭响应套接字*/,面向连接的套接字编程实例-服务器程序代码,操作系统中的阻塞状态,正在执行的进程由于发生某事件而暂时无法继续执行时,便放弃处理机而处于暂停状态,亦即进程的执行受到阻塞,把这种暂停状态称为阻塞状态。致使进程阻塞的典型事件有:请求I/O,申请内存空间等。,通常将这种处于阻塞状态的进程也排成一个队列。有的系统则根据阻塞原因的不同而把处于阻塞状态的进程排成多个队列。,2.3.4 进程的阻塞问

45、题和对策 P40,图2.6 服务器进程因调用ACCEPT()而被阻塞,2.3.4 进程的阻塞问题和对策,2.3.4 进程的阻塞问题和对策,1什么是阻塞(P40)阻塞是指一个进程执行了一个函数或者系统调用,该函数由于某种原因不能立即完成,因而不能返回调用它的进程,导致进程受控于这个函数而处于等待的状态,进程的这种状态称为阻塞。在程序中用了一条让用户在键盘上输入字符串的语句,当程序执行到这条语句时就会停下来,等待用户输入字符串并按下回车键,如果用户没有输入,程序就会一直等下去。这时程序的状态就是阻塞。,图2.7 RECV()函数的两种执行方式,2.3.4 进程的阻塞问题和对策,2能引起阻塞的套接字

46、调用在Berkeley套接字网络编程接口的模型中,套接字的默认行为是阻塞的,具体地说,在一定情况下,有多个操作套接字的系统调用会引起进程阻塞。(1)ACCEPT()(2)READ()、RECV()和READFORM()(3)WRITE()、SEND()和SENDTO()(4)CONNECT()(5)SELECT()(6)CLOSESOCKET(),2.3.4 进程的阻塞问题和对策,3阻塞工作模式带来的问题采用阻塞工作模式的单进程服务器是不能很好地同时为多个客户服务的。图2.9是一个例子。,图2.8 采用阻塞工作模式的服务器不能很好地为多个客户服务,2.3.4 进程的阻塞问题和对策,4一种解决方

47、案,利用UNIX操作系统的FORK()系统调用,编制多进程并发执行的服务器程序。可以创建子进程。对于每一个客户端,用一个专门的进程为它服务,通过进程的并发执行,来实现对多个客户的并发服务。基本的编程框架如下。,2.3.4 进程的阻塞问题和对策,父进程代码 If(pid=FORK()=0).子进程代码.else if(pid0)报错信息 父进程代码,2.3.4 进程的阻塞问题和对策,举例:#include#include#include#include void main(int argc,char*argv)int listenfd,clientfd,pid;struct sockaddr_i

48、n ssockaddr,csockaddr;char buffer1024;int addrlen,n;,2.3.4 进程的阻塞问题和对策,/*创建监听套接字*/listenfd=socket(AF_INET,SOCK_STREAM,0);if(listenfd 0)fprintf(stderr,socket error!n);exit(1);,2.3.4 进程的阻塞问题和对策,/*为监听套接字绑定网络地址*/memset(,2.3.4 进程的阻塞问题和对策,/*启动套接字的监听*/listen(listenfd,5);addrlen=sizeof(sockaddr);/*服务器进入循环,接受

49、并处理来自不同客户端的连接请求*/while(1)clientfd=accept(listenfd,(sockaddr*)(/*accept调用返回时,表明有客户端请求连接,创建子进程处理连接*/If(pid=FORK()=0),2.3.4 进程的阻塞问题和对策,/*显示客户端的网络地址*/printf(Client Addr:%s%dn,inet_ntoa(csockaddr.sin_addr),ntohs(csockaddr.sin_port);/*读取客户端发送来的数据,在将它们返回到客户端*/while(n=read(clientfd,buffer,1024)0)buffern=0;p

50、rintf(Client Send:%s,buffer);write(clientfd,buffer,n);if(n 0)fprintf(stderr,read error!n);exit(3);,2.3.4 进程的阻塞问题和对策,/*通信完毕,关闭与这个客户连接的套接字*/printf(clent%s closed!n,inet_ntoa(csockaddr.sin_addr);close(clientfd);exit(1);else if(pid 0)printf(fork failed!n);close(clientfd);close(listenfd);/*关闭监听套接字*/,2.3.

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 生活休闲 > 在线阅读


备案号:宁ICP备20000045号-2

经营许可证:宁B2-20210002

宁公网安备 64010402000987号