1、第第2章章 套接字网络编程基础套接字网络编程基础12.1 UNIX套接字网络编程接口的套接字网络编程接口的 产生与发展产生与发展2.2 套接字编程的基本概念套接字编程的基本概念2.3 面向连接的套接字编程面向连接的套接字编程2.4 无连接的套接字编程无连接的套接字编程2.5 原始套接字原始套接字 从从应用程序实现的角度,应用程序如何方便地使用协议应用程序实现的角度,应用程序如何方便地使用协议栈软件进行通信呢?栈软件进行通信呢? 2.1 UNIX套接字网络编程接口的产生与发展套接字网络编程接口的产生与发展2.1.1 问题的提出问题的提出 (P24)如果能在应用程序与协议栈软件之间提供一个软件接口
2、,如果能在应用程序与协议栈软件之间提供一个软件接口,就可以方便客户机与服务器软件的编程。就可以方便客户机与服务器软件的编程。UNIX系统的开发者系统的开发者提出了提出了套接字应用程序编程接口。套接字应用程序编程接口。套接字应用程序编程接口是网络应用程序通过网络协议栈套接字应用程序编程接口是网络应用程序通过网络协议栈进行通信时所使用的接口,即应用程序与协议栈软件之间的接进行通信时所使用的接口,即应用程序与协议栈软件之间的接口,简称套接字编程接口口,简称套接字编程接口(Socket API)。具体地说,套接字编程接口给出了应用程序能够调用的具体地说,套接字编程接口给出了应用程序能够调用的一组函数,
3、每个函数完成一个与协议栈交互的基本操作。一组函数,每个函数完成一个与协议栈交互的基本操作。 2.1.1 问题的提出问题的提出 P24 P24套接字编程接口套接字编程接口定义了应用程序与协议栈软件进行交互定义了应用程序与协议栈软件进行交互时可以使用的一组操作,决定了应用程序使用协议栈的方式、时可以使用的一组操作,决定了应用程序使用协议栈的方式、应用程序所能实现的功能、以及开发具有这些功能的程序的应用程序所能实现的功能、以及开发具有这些功能的程序的方法。方法。加州大学伯克利(加州大学伯克利(BerkleyBerkley)分校开发并推广了一个包括分校开发并推广了一个包括TCP/IPTCP/IP互联协
4、议的互联协议的UNIXUNIX,称为称为BSD UNIXBSD UNIX(Berkeley Berkeley Software Distribution UNIXSoftware Distribution UNIX)操作系统,套接字编程接口操作系统,套接字编程接口是是这个操作系统的一部分。这个操作系统的一部分。后来的许多操作系统并没有另外搞一套其它的编程接口,后来的许多操作系统并没有另外搞一套其它的编程接口,而是选择了对于套接字编程接口的支持。包括各种而是选择了对于套接字编程接口的支持。包括各种UNIXUNIX的派的派生版,后来出现的生版,后来出现的WindowsWindows,及各种,及各种
5、LinuxLinux版本。版本。2.1.2 套接字编程接口起源于套接字编程接口起源于UNIX系统系统 (P25) 2.1 UNIX套接字网络编程接口的产生与发展套接字网络编程接口的产生与发展套接字规范规定了一系列有关的套接字规范规定了一系列有关的C C函数,为在函数,为在UNIXUNIX环境环境使用使用TCP/IPTCP/IP进行网络通信提供了一套应用程序编程接口,得进行网络通信提供了一套应用程序编程接口,得以实现并广泛流传。以实现并广泛流传。套接字编程接口广泛应用在各种网络编程中,成为事实上套接字编程接口广泛应用在各种网络编程中,成为事实上的工业标准。的工业标准。由于这个套接字规范最早是由由
6、于这个套接字规范最早是由BerkeleyBerkeley大学开发的,一般大学开发的,一般将它称为将它称为Berkeley SocketsBerkeley Sockets规范。规范。2.1.2 套接字编程接口起源于套接字编程接口起源于UNIX系统系统 (P25) 2.1 UNIX套接字网络编程接口的产生与发展套接字网络编程接口的产生与发展 1)Windows系统系统微软公司以微软公司以UNIX操作系统的操作系统的Berkeley Sockets规范为范例,规范为范例,定义了定义了Windows Socktes规范,全面继承了套接字网络编程接规范,全面继承了套接字网络编程接口。详细内容将在第三章介
7、绍。口。详细内容将在第三章介绍。 2.1.3 套接字编程接口的继承和发展套接字编程接口的继承和发展 (P25) 2.1 UNIX套接字网络编程接口的产生与发展套接字网络编程接口的产生与发展 2) Linux系统系统 Linux操作系统中的套接字网络编程接口几乎与操作系统中的套接字网络编程接口几乎与UNIX操作操作系统的套接字网络编程接口一样。系统的套接字网络编程接口一样。 要想实现套接字编程接口,可以采用两种实现方式要想实现套接字编程接口,可以采用两种实现方式:1. 一种是在操作系统的内核中增加相应的软件来实现,一种是在操作系统的内核中增加相应的软件来实现,套接字函数是操作系统内核的一部分。套
8、接字函数是操作系统内核的一部分。2. 另一种是通过开发操作系统之外的函数库来实现。另一种是通过开发操作系统之外的函数库来实现。 具有与具有与UNIX套接字相同的函数名和参数。实现了程序的可套接字相同的函数名和参数。实现了程序的可移植性,程序源代码不必改动即可移植到另一个操作系统。移植性,程序源代码不必改动即可移植到另一个操作系统。只是使用时要链接库函数。只是使用时要链接库函数。2.1.4 套接字编程接口的两种实现方式套接字编程接口的两种实现方式 P25 2.1 UNIX套接字网络编程接口的产生与发展套接字网络编程接口的产生与发展UNIX操作系统对文件和所有其它操作系统对文件和所有其它的输入的输
9、入/输出设备输出设备采用采用一种统一的的操作模式,就是一种统一的的操作模式,就是“打开打开-读读-写写-关闭关闭”(open - read - write - close)的的I/O模式。模式。当当TCP/IP协议被集成到协议被集成到UNIX内核中的时候,相当于在内核中的时候,相当于在UNIX系统中引入了一种新型的系统中引入了一种新型的I/O操作,就是应用程序通过操作,就是应用程序通过网络协议栈来交换数据。网络协议栈来交换数据。 2.1.5 套接字通信与套接字通信与UNIX操作系统的输入操作系统的输入/输出的关系输出的关系 2.1 UNIX套接字网络编程接口的产生与发展套接字网络编程接口的产生
10、与发展在在UNIX系统的实现中,套接字是完全与其他系统的实现中,套接字是完全与其他I/O集成在集成在一起的。操作系统和应用程序都将套接字编程接口也看作一一起的。操作系统和应用程序都将套接字编程接口也看作一种种I/O机制。机制。这体现在三个方面:这体现在三个方面: 2.1.5 套接字通信与套接字通信与UNIXUNIX操作系统的输入操作系统的输入/ /输出输出的关系的关系1 1)操作的过程类似。使用套接字也像使用)操作的过程类似。使用套接字也像使用I/OI/O一样一样“打开打开-读写读写-关闭关闭”模式。模式。2 2)操作方法)操作方法类似类似。操作系统为文件、设备、进程通信、。操作系统为文件、设
11、备、进程通信、网络通信提供单独的一组描述符,套接字通信同样使用描述网络通信提供单独的一组描述符,套接字通信同样使用描述符方法。符方法。3 3)过程名也可以相同。例如)过程名也可以相同。例如readread和和writewrite。但是,用户进程与网络协议的交互作用实际要比用户进但是,用户进程与网络协议的交互作用实际要比用户进程与传统的程与传统的I/O设备相互作用要复杂得多。首先,进行网络操设备相互作用要复杂得多。首先,进行网络操作的两个进程是在两台不同的计算机,如何连接;其次,要作的两个进程是在两台不同的计算机,如何连接;其次,要建立一种通用机制来支持多种网络协议。建立一种通用机制来支持多种网
12、络协议。 2.1.5 套接字通信与套接字通信与UNIXUNIX操作系统的输入操作系统的输入/ /输出输出的关系的关系还有,使用套接字的应用程序必须说明许多细节。仅仅还有,使用套接字的应用程序必须说明许多细节。仅仅提供提供open、read、write、close四个过程远远不够。为避免单四个过程远远不够。为避免单个套接字函数参数过多,套接字编程接口的设计者还定义了个套接字函数参数过多,套接字编程接口的设计者还定义了其它多个函数。其它多个函数。2.2 套接字编程的基本概念套接字编程的基本概念套接口是对网络中不同主机上应用进程之间进行双向通套接口是对网络中不同主机上应用进程之间进行双向通信的端点的
13、抽象,一个套接口就是网络上进程通信的一端,信的端点的抽象,一个套接口就是网络上进程通信的一端,提供了应用层进程利用网络协议栈交换数据的机制提供了应用层进程利用网络协议栈交换数据的机制。 图2.1 电气插座与电话插座的作用2.2.1 什么是套接字(什么是套接字(SOCKET) (P27)我们应当从多个层面来理解套接字这个概念。我们应当从多个层面来理解套接字这个概念。1 1)从套接字所处的地位来讲,套接字上联应用进程,下)从套接字所处的地位来讲,套接字上联应用进程,下联网络协议栈,是应用程序通过网络协议栈进行通信的接口,联网络协议栈,是应用程序通过网络协议栈进行通信的接口,是应用程序与网络协议栈进
14、行交互的接口。是应用程序与网络协议栈进行交互的接口。 2.2.1 什么是套接字什么是套接字图图2.2 2.2 应用进程、套接口、网络协议栈及操作系统的关系应用进程、套接口、网络协议栈及操作系统的关系 2)从实现的角度来讲,非常复杂。套接字是一个复杂的)从实现的角度来讲,非常复杂。套接字是一个复杂的软件机构,包含了一定的数据结构,包含许多选项,由操作系软件机构,包含了一定的数据结构,包含许多选项,由操作系统内核管理。统内核管理。3)从使用的角度来讲,非常简单。调用相应的过程后,)从使用的角度来讲,非常简单。调用相应的过程后,生成的套接字就是套接字描述符,用一个整数来代表。对于套生成的套接字就是套
15、接字描述符,用一个整数来代表。对于套接字的操作形成了一种网络应用程序的编程接口(接字的操作形成了一种网络应用程序的编程接口(API)。)。这里把这一套操作套接字的编程接口函数称作套接字编这里把这一套操作套接字的编程接口函数称作套接字编程接口,套接字是它的操作对象。程接口,套接字是它的操作对象。总之,套接字是网络通信的基石。总之,套接字是网络通信的基石。 2.2.1 什么是套接字什么是套接字 1 1通信域通信域 套接字存在于通信域中,通信域是为了处理一般的进程通过套接字存在于通信域中,通信域是为了处理一般的进程通过套接字通信而引入的一种抽象概念,套接字通常只和同一域中的套接字通信而引入的一种抽象
16、概念,套接字通常只和同一域中的套接字交换数据。套接字交换数据。 套接字实际是通过网络协议栈来通信,通信双方要使用相同套接字实际是通过网络协议栈来通信,通信双方要使用相同的通信协议。的通信协议。 在在InternetInternet通信域中,所有计算机都使用通信域中,所有计算机都使用InternetInternet协议族协议族(即(即TCP/IPTCP/IP协议族)来通信。协议族)来通信。2.2.2 套接字的特点套接字的特点 (P28)2套接字具有三种类型套接字具有三种类型 P29 每一个正被使用的套接字都有它确定的类型,只有相同每一个正被使用的套接字都有它确定的类型,只有相同类型的套接字才能相
17、互通信。类型的套接字才能相互通信。(1)数据报套接字(数据报套接字(Datagram SOCKET) 数据报套接字提供无连接的不保证可靠的独立的数据报数据报套接字提供无连接的不保证可靠的独立的数据报传输服务。在传输服务。在Internet通信域中,数据报套接字使用通信域中,数据报套接字使用UDP数据数据报协议形成的进程间通路,具有报协议形成的进程间通路,具有UDP协议为上层所提供的服协议为上层所提供的服务的所有特点。务的所有特点。2.2.2 套接字的特点套接字的特点图图2.3 2.3 在在InternetInternet通信域中,数据报套接字基于通信域中,数据报套接字基于UDPUDP协议协议
18、2.2.2 套接字的特点套接字的特点(2) 流式套接字(流式套接字(Stream SOCKET)流式套接字提供双向的、有序的、无重复的、无记录边流式套接字提供双向的、有序的、无重复的、无记录边界的可靠的数据流传输服务。在界的可靠的数据流传输服务。在Internet通信域中,流式套接通信域中,流式套接字使用字使用TCP协议形成的进程间通路,具有协议形成的进程间通路,具有TCP协议为上层所协议为上层所提供的服务的所有特点,在使用流式套接字传输数据之前,提供的服务的所有特点,在使用流式套接字传输数据之前,必须在数据的发送端和接收端之间建立连接,如图必须在数据的发送端和接收端之间建立连接,如图2.4所
19、示。所示。 2.2.2 套接字的特点套接字的特点图图2.4 2.4 在在InternetInternet通信域中,流式套接字基于通信域中,流式套接字基于TCPTCP协议协议2.2.2 套接字的特点套接字的特点(3) 原始式套接字(原始式套接字(RAW SOCKET)原始式套接字允许对较低层次的协议,如原始式套接字允许对较低层次的协议,如IP、ICMP直直接访问,用于检验新的协议的实现。接访问,用于检验新的协议的实现。 2.2.2 套接字的特点套接字的特点3套接字由应用层的通信进程创建,并为其服务套接字由应用层的通信进程创建,并为其服务 就是说,每一个套接字都有一个相关的应用进程,操作该就是说,
20、每一个套接字都有一个相关的应用进程,操作该套接字的代码是该进程的组成部分。套接字的代码是该进程的组成部分。2.2.2 套接字的特点套接字的特点4 4使用确定的使用确定的IPIP地址和传输层端口号地址和传输层端口号往往在生成套接字的描述符后,要将套接字与计算机往往在生成套接字的描述符后,要将套接字与计算机上的特定的上的特定的IP地址和传输层端口号相关联,这个过程称为地址和传输层端口号相关联,这个过程称为绑定。绑定。一个套接字要使用一个确定的三元组网络地址信息,一个套接字要使用一个确定的三元组网络地址信息,才能使它在网络中唯一地被标识。才能使它在网络中唯一地被标识。2.2.2 套接字的特点套接字的
21、特点(1 1)不管是采用对等模式或者客户机)不管是采用对等模式或者客户机/ /服务器模式,通信服务器模式,通信双方的应用程序都需要开发。双方的应用程序都需要开发。(2 2)双方所交换数据的结构和交换数据的顺序有特定的)双方所交换数据的结构和交换数据的顺序有特定的要求,不符合现在成熟的应用层协议,甚至需要自己去开发应要求,不符合现在成熟的应用层协议,甚至需要自己去开发应用层协议,自己设计最适合的数据结构和信息交换规程。用层协议,自己设计最适合的数据结构和信息交换规程。 在这种情况下,套接字很有用,因为套接字直接与传输层在这种情况下,套接字很有用,因为套接字直接与传输层连接,提供了网络应用进程之间
22、交换数据的方法,程序员编程连接,提供了网络应用进程之间交换数据的方法,程序员编程有很大的自由度。有很大的自由度。2.2.3 套接字的应用场合套接字的应用场合 (P30)2.2 套接字编程的基本概念套接字编程的基本概念2.2.4 套接字使用的数据类型和相关的问题套接字使用的数据类型和相关的问题 P301三种表示套接字地址的结构三种表示套接字地址的结构 在套接字编程接口中,专门定义了三种结构的数据类型,在套接字编程接口中,专门定义了三种结构的数据类型,用来存储协议相关的网络地址,在套接字编程接口的函数调用来存储协议相关的网络地址,在套接字编程接口的函数调用中要用到它们。用中要用到它们。2.2 套接
23、字编程的基本概念套接字编程的基本概念2.2.4 套接字套接字使用的数据类型和相关的问题使用的数据类型和相关的问题(1)sockaddr结构,针对各种通信域的套接字,存储它们结构,针对各种通信域的套接字,存储它们的地址信息。的地址信息。struct sockaddr unsigned short sa_family; / 地址家族地址家族char sa_data14; / 14字节协议地址字节协议地址 (2)sockaddr_in结构,专门针对结构,专门针对Internet通信域,存储套接通信域,存储套接字相关的网络地址信息,例如字相关的网络地址信息,例如IP地址,传输层端口号等信息。地址,传输
24、层端口号等信息。struct sockaddr_in short int sin_family; / 协议簇协议簇 unsigned short 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 套接字套接字使用的数据类型和相关
25、的问题使用的数据类型和相关的问题(4) 这些数据结构的一般用法:这些数据结构的一般用法:第第1步,定义一个步,定义一个sockaddr_in的结构实例,并将它清的结构实例,并将它清零。零。比如:比如:struct sockaddr_in myad;memset(&myad,0,sizeof(struct sockaddr_in); 2.2.4 套接字套接字使用的数据类型和相关的问题使用的数据类型和相关的问题第第3步,在函数调用中使用时,将这个结构强制转换为步,在函数调用中使用时,将这个结构强制转换为sockaddr类型。如:类型。如:accept(listenfd,(sockaddr*)(&m
26、yad),&addrlen); 第第2步,步,为这个结构赋值,比如:为这个结构赋值,比如: myad.sin_family=AF_INET; myad.sin_port=htons(8080); myad.sin_addr.s_addr=htonl(INADDR-ANY);2.2.4 套接字套接字使用的数据类型和相关的问题使用的数据类型和相关的问题2本机字节顺序和网络字节顺序本机字节顺序和网络字节顺序 P31 不同的计算机中存放多字节的顺序可能不同,有的先低后不同的计算机中存放多字节的顺序可能不同,有的先低后高,有的先高后低。在具体计算机中的多字节数据的存储顺高,有的先高后低。在具体计算机中的
27、多字节数据的存储顺序,称为本机字节顺序。序,称为本机字节顺序。 多字节数据在网络协议报头中的存储顺序,称为网络字节多字节数据在网络协议报头中的存储顺序,称为网络字节顺序。顺序。 2.2.4 套接字套接字使用的数据类型和相关的问题使用的数据类型和相关的问题1 1网络字节顺序格式网络字节顺序格式在在网络传输过程中,网络传输过程中,IPIP地址被保存地址被保存为为3232位二进制数。位二进制数。TCP/IPTCP/IP协议规定,协议规定,在低位存储地址中保存数据的高位字在低位存储地址中保存数据的高位字节,这种存储顺序格式被称为网络字节,这种存储顺序格式被称为网络字节顺序。数据按照节顺序。数据按照32
28、32位二进制数为一位二进制数为一组进行传输,因为采用网络字节顺序,组进行传输,因为采用网络字节顺序,所以数据的传输顺序是由高位至低位所以数据的传输顺序是由高位至低位进行的。进行的。存储地址存储地址20012002200320042000高位字节高位字节1低位字节低位字节1高位字节高位字节2低位字节低位字节2.2 2主机字节顺序格式主机字节顺序格式不不同的主机在对同的主机在对IPIP地址进行存储时地址进行存储时使用的格式也不同。有些操作系统使用的格式也不同。有些操作系统的的IPIP地址存储顺序与网络字节顺序地址存储顺序与网络字节顺序格式相同,而格式相同,而Intel x86Intel x86系列
29、主机系列主机的主机字节顺序格式则与网络字节的主机字节顺序格式则与网络字节顺序格式正好相反。顺序格式正好相反。 存储地址存储地址20012002200320042000高位字节高位字节1低位字节低位字节1高位字节高位字节2低位字节低位字节2.网络应用程序要在不同的计算机中运行,本机字节顺序网络应用程序要在不同的计算机中运行,本机字节顺序是不同的,但是,网络字节顺序是一定的。是不同的,但是,网络字节顺序是一定的。所以,应用程序在编程的时候,在把所以,应用程序在编程的时候,在把IPIP地址和端口号装地址和端口号装入套接字的时候,应当把它们从本机字节顺序转换为网络字入套接字的时候,应当把它们从本机字节
30、顺序转换为网络字节顺序;相反,在本机输出时,应将它们从网络字节顺序转节顺序;相反,在本机输出时,应将它们从网络字节顺序转换为本机字节顺序。换为本机字节顺序。 2.2.4 套接字套接字使用的数据类型和相关的问题使用的数据类型和相关的问题字节序转换的字节序转换的方法方法套接字编程接口特为解决这个问题设置了四个函数:套接字编程接口特为解决这个问题设置了四个函数:htons():短整数本机顺序转换为网络顺序,用于端口号。短整数本机顺序转换为网络顺序,用于端口号。htonl():长整数本机顺序转换为网络顺序,用于长整数本机顺序转换为网络顺序,用于IP地址。地址。ntohs():短整数网络顺序转换为本机顺
31、序,用于端口号。短整数网络顺序转换为本机顺序,用于端口号。ntohl():长整数网络顺序转化为本机顺序,用于长整数网络顺序转化为本机顺序,用于IP地址。地址。这四个函数将被转换的数值作为函数的参数,函数返回这四个函数将被转换的数值作为函数的参数,函数返回值是转换后的结果值是转换后的结果。2.2.4 套接字套接字使用的数据类型和相关的问题使用的数据类型和相关的问题3点分十进制的点分十进制的IP地址的转换地址的转换 P31在因特网中,在因特网中,IP地址常常用点分十进制的表示方法,地址常常用点分十进制的表示方法,但在套接字中,但在套接字中,IP地址是无符号的长整型数,是地址是无符号的长整型数,是网
32、络字节网络字节顺序的地址。顺序的地址。套接字编程接口设置了两个函数,专门用于两种形式套接字编程接口设置了两个函数,专门用于两种形式的的IP地址的转换。地址的转换。2.2.4 套接字套接字使用的数据类型和相关的问题使用的数据类型和相关的问题 1)inet_addr函数函数点分十进制形式点分十进制形式-网络字节顺序网络字节顺序unsigned long inet_addr( const char* cp)入口参数入口参数cp:点分十进制形式的:点分十进制形式的IP地址。地址。返回值:返回值: 网络字节顺序的网络字节顺序的IP地址,是无符号的长整数。地址,是无符号的长整数。2.2.4 套接字套接字使
33、用的数据类型和相关的问题使用的数据类型和相关的问题2)inet_ntoa函数函数网络字节顺序网络字节顺序-点分十进制形式点分十进制形式 char* inet_ntoa(struct in_addr in) 入口参数入口参数in:包含长整型:包含长整型IP地址的地址的 in_addr 结构变量结构变量。 返回值返回值: 指向点分十进制指向点分十进制IP地址的字符串的指针地址的字符串的指针。2.2.4 套接字套接字使用的数据类型和相关的问题使用的数据类型和相关的问题通常,我们使用域名来标识站点,可以将文字型的主机域通常,我们使用域名来标识站点,可以将文字型的主机域名直接转换成名直接转换成IP地址:
34、地址:struct hostent* gethostbyname( const char* name);入口参数:是站点的主机域名字符串,入口参数:是站点的主机域名字符串,返回值:是指向返回值:是指向hostent 结构的指针,结构的指针,hostent结构包含主机名,主机别名数组,返回地址的类型结构包含主机名,主机别名数组,返回地址的类型(一般是(一般是AF-INET),地址长度的字节数,已符合网络字节顺),地址长度的字节数,已符合网络字节顺序的主机网络地址等。序的主机网络地址等。 4域名服务域名服务 P322.2.4 套接字套接字使用的数据类型和相关的问题使用的数据类型和相关的问题2.3.
35、1 可靠的传输控制协议可靠的传输控制协议 (P32) 传输控制协议传输控制协议(TCP)是是TCP/IP协议簇中主要的传输层协议簇中主要的传输层协议,负责为应用层提供可靠的传输服务。协议,负责为应用层提供可靠的传输服务。 TCP建立在网络层的建立在网络层的IP之上,为应用层进程提供一个面向之上,为应用层进程提供一个面向连接的、端到端的、完全可靠的(无差错、无丢失、无重连接的、端到端的、完全可靠的(无差错、无丢失、无重复复和无和无失序)全双工的流传输服务,允许网络中的两个应失序)全双工的流传输服务,允许网络中的两个应用程序建立一个虚拟连接,并在任何一个方向上发送数据,用程序建立一个虚拟连接,并在
36、任何一个方向上发送数据,把数据当作一个双向字节流进行交换,然后终止连接。每把数据当作一个双向字节流进行交换,然后终止连接。每一一TCP连接可靠地建立,从容地终止,在终止发生之前的连接可靠地建立,从容地终止,在终止发生之前的所有数据都会被可靠地传递。所有数据都会被可靠地传递。2.3 面向连接的套接字编程面向连接的套接字编程2.3 面向连接的套接字编程面向连接的套接字编程2.3.2 套接字的工作过程套接字的工作过程 P331. 1. 创建网络套接字函数创建网络套接字函数 socket( )socket( )2. 2. 绑定一个地址端口对绑定一个地址端口对 bind( )bind( )3. 3. 监
37、听本地端口监听本地端口 listen ( )listen ( )4. 4. 接受一个网络请求接受一个网络请求 accept( )accept( )5. 5. 连接目标网络服务器连接目标网络服务器 connect( )connect( )6. 6. 写入数据函数写入数据函数 write( )write( )7. 7. 读取数据函数读取数据函数 read( )read( )8. 8. 关闭套接字函数关闭套接字函数 close( )close( )TCPTCP网络编程流程网络编程流程TCPTCP网络编程有两种模式:网络编程有两种模式: 1 1服务器端的程序设计模式服务器端的程序设计模式 2 2客户端
38、的程序设计模式客户端的程序设计模式服务器模式创建一个服务进程,等待客户端用户的连接,服务器模式创建一个服务进程,等待客户端用户的连接,接收到用户的连接请求后,根据用户的请求进行处理;接收到用户的连接请求后,根据用户的请求进行处理;客户端模式则根据目的服务器的客户端模式则根据目的服务器的IPIP地址和端口进行连接,地址和端口进行连接,向服务器发送请求并对服务器的响应进行数据处理。向服务器发送请求并对服务器的响应进行数据处理。TCPTCP网络编程流程网络编程流程流程主要分为流程主要分为: : 套接字初始化套接字初始化-socket( )-socket( ) 套接字与端口的绑定套接字与端口的绑定-b
39、ind( )-bind( ) 设置服务器的侦听连接设置服务器的侦听连接-listen( )-listen( ) 接受客户端连接接受客户端连接-accept( )-accept( ) 发送数据发送数据-write( )-write( ) 接收数据接收数据-read( )-read( )并进行数据处理并进行数据处理 处理完毕的套接字关闭处理完毕的套接字关闭-close( )-close( )1. 1. 服务器端的程序设计模式服务器端的程序设计模式客户端模式分为客户端模式分为: : 套接字初始化套接字初始化-socket( )-socket( ) 连接服务器连接服务器-connect( )-conn
40、ect( ) 发送数据发送数据-write( )-write( ) 接收数据接收数据-read( )-read( )并进行数据处理并进行数据处理 最后的套接字关闭最后的套接字关闭-close( )-close( )2. 2. 客户端的程序设计模式客户端的程序设计模式客户端与服务器在连客户端与服务器在连接、读写数据、关接、读写数据、关闭过程中有交互过闭过程中有交互过程。程。3. 3. 客户端与服务器的交客户端与服务器的交互过程互过程 UNIXUNIX套接字编程接口的系统调用套接字编程接口的系统调用 (P33)(P33)1 1socket( )-socket( )-创建套接字创建套接字 系统调用系
41、统调用socket( )socket( )函数建立一个协议族为函数建立一个协议族为Protofamily Protofamily 、协、协议类型为议类型为typetype、协议编号为、协议编号为protocolprotocol的套接字文件描述符。的套接字文件描述符。socket( )socket( )函数在函数在socket.hsocket.h文件中定义文件中定义int socket( int Protofamily, int Type, int Protocol);int socket( int Protofamily, int Type, int Protocol);使用时注意把使用时注意
42、把socket.hsocket.h包含进来包含进来#include #include #include #include 2.3.2 套接字的工作过程套接字的工作过程int socket( int Protofamily, int Type, int Protocol); int socket( int Protofamily, int Type, int Protocol); socket( )socket( )函数用来获得文件描述符函数用来获得文件描述符sockfdsockfd。如果函数调用成功,。如果函数调用成功,会返回一个表示这个套接字的文件描述符会返回一个表示这个套接字的文件描述符(
43、f (file descriptorile descriptor) ),失,失败的时候返回败的时候返回11。使用举例:使用举例:sockfd = SOCKET(AF_INET, SOCK_STREAM, 0);LinuxLinux系统中,系统中,socket( )socket( )的定义在的定义在/usr/include/sys/socket.h/usr/include/sys/socket.hint socket (int _domain, int _type, int _protocol)int socket (int _domain, int _type, int _protocol)U
44、NIXUNIX套接字编程接口的系统调用套接字编程接口的系统调用 UNIXUNIX套接字编程接口的系统调用套接字编程接口的系统调用 2 2 bind( )- bind( )- 绑定套接字到指定的地址绑定套接字到指定的地址 服务器端在建立套接字文件描述符成功后,需要对套接字服务器端在建立套接字文件描述符成功后,需要对套接字进行进行IPIP地址和端口的绑定,才能进行数据的接收和发送操作。地址和端口的绑定,才能进行数据的接收和发送操作。 bind( ) bind( )函数将长度为函数将长度为addlenaddlen的的struct sockaddstruct sockadd类型的结类型的结构体变量构体
45、变量my_addrmy_addr与与sockfdsockfd绑定在一起,将绑定在一起,将sockfdsockfd绑定到某绑定到某IPIP和端口上。如果是客户端使用和端口上。如果是客户端使用connect()connect()函数则没有绑定的函数则没有绑定的必要。绑定的函数原型如下:必要。绑定的函数原型如下:int bind( int sockfd, struct sockaddrint bind( int sockfd, struct sockaddr* * my_addr, int my_addr, int addrlen);addrlen);使用时注意把使用时注意把socket.hsock
46、et.h包含进来包含进来#include #include #include #include UNIXUNIX套接字编程接口的系统调用套接字编程接口的系统调用 int bind( int sockfd, struct sockaddrint bind( int sockfd, struct sockaddr* * my_addr, int my_addr, int addrlen);addrlen);LinuxLinux系统中,系统中, bind bind ( )( )的定义在的定义在/usr/include/sys/socket.h/usr/include/sys/socket.hint
47、bind (int _fd, _CONST_SOCKADDR_ARG _addr, int bind (int _fd, _CONST_SOCKADDR_ARG _addr, socklen_t _len)socklen_t _len)UNIXUNIX套接字编程接口的系统调用套接字编程接口的系统调用 3 3listen( )- listen( )- 启动监听启动监听 函数函数listen( )listen( )用来初始化服务器可连接队列,服务器处理客用来初始化服务器可连接队列,服务器处理客户端连接请求的时候是顺序处理的,同一时间仅能处理一个客户端连接请求的时候是顺序处理的,同一时间仅能处理一个
48、客户端连接。当多个客户端的连接请求同时到来的时候,服务器户端连接。当多个客户端的连接请求同时到来的时候,服务器并不是同时处理,而是将不能处理的客户端连接请求放到等待并不是同时处理,而是将不能处理的客户端连接请求放到等待队列中,这个队列的长度由队列中,这个队列的长度由listen( )listen( )函数来定义。函数来定义。 listen( ) listen( )函数的原型如下:函数的原型如下:int listen( int sockfd, int queuesize);int listen( int sockfd, int queuesize);其中的其中的queuesizequeuesiz
49、e表示等待队列的长度。表示等待队列的长度。注意把注意把socket.hsocket.h包含进来包含进来#include #include #include #include UNIXUNIX套接字编程接口的系统调用套接字编程接口的系统调用 int listen( int sockfd, int queuesize);int listen( int sockfd, int queuesize);举例:举例: if (listen(sockfd, qlenth) 0) 出错出错 LinuxLinux系统中,系统中, l listen isten ( )( )的定义在的定义在/usr/include
50、/sys/socket.h/usr/include/sys/socket.hint listen (int _fd, int _n)int listen (int _fd, int _n)举例:举例:listenlisten(sockfd, 10); 图图2.6 2.6 监听套接字使用缓冲区接纳多个客户端的连接请求监听套接字使用缓冲区接纳多个客户端的连接请求 UNIXUNIX套接字编程接口的系统调用套接字编程接口的系统调用 UNIXUNIX套接字编程接口的系统调用套接字编程接口的系统调用 4 4accept ( )-accept ( )-接收连接请求接收连接请求 当一个客户端的连接请求到达服务