网络程序设计基本知识

上传人:大米 文档编号:572401723 上传时间:2024-08-13 格式:PPT 页数:172 大小:834.55KB
返回 下载 相关 举报
网络程序设计基本知识_第1页
第1页 / 共172页
网络程序设计基本知识_第2页
第2页 / 共172页
网络程序设计基本知识_第3页
第3页 / 共172页
网络程序设计基本知识_第4页
第4页 / 共172页
网络程序设计基本知识_第5页
第5页 / 共172页
点击查看更多>>
资源描述

《网络程序设计基本知识》由会员分享,可在线阅读,更多相关《网络程序设计基本知识(172页珍藏版)》请在金锄头文库上搜索。

1、第第6章章 网络程序设计基本知识网络程序设计基本知识 n n6.1 6.1 6.1 6.1 网络应用程序的概念网络应用程序的概念网络应用程序的概念网络应用程序的概念n n6.2 6.2 6.2 6.2 TCP/IPTCP/IPTCP/IPTCP/IP应用程序工作模型与网络编程接应用程序工作模型与网络编程接应用程序工作模型与网络编程接应用程序工作模型与网络编程接口口口口n n6.3 6.3 6.3 6.3 套接口的概念及其编程原理套接口的概念及其编程原理套接口的概念及其编程原理套接口的概念及其编程原理n n6.4 Winsock API6.4 Winsock API6.4 Winsock API

2、6.4 Winsock API基本函数基本函数基本函数基本函数套接口与连套接口与连套接口与连套接口与连接的建立接的建立接的建立接的建立n n6.5 Winsock API6.5 Winsock API6.5 Winsock API6.5 Winsock API基本函数基本函数基本函数基本函数数据传输数据传输数据传输数据传输n n6.6 Winsock API6.6 Winsock API6.6 Winsock API6.6 Winsock API基本函数基本函数基本函数基本函数连接与套接连接与套接连接与套接连接与套接口的关闭口的关闭口的关闭口的关闭n n习题习题习题习题6.1 网络应用程序的概

3、念网络应用程序的概念6.1.1 6.1.1 什么是网络应用程序什么是网络应用程序n n我我们们设设计计的的应应用用程程序序可可以以简简单单地地分分为为两两种种:一一种种程程序序不不需需要要使使用用其其他他程程序序产产生生的的数数据据并并且且其其他他程程序序也也不不使使用用它它输输出出的的数数据据;另另一一种种程程序序需需要要与与其其他他的的应应用用程程序序进进行行数数据据交交换换才能完成其功能,也就是说程序之间存在通信问题。才能完成其功能,也就是说程序之间存在通信问题。n n进进程程间间通通信信的的问问题题也也可可以以分分为为两两种种:一一种种是是在在操操作作系系统统中中论论述述的的单单机机系

4、系统统中中进进程程间间的的通通信信问问题题,另另一一种种一一般般是是在在不不同同系系统统的的进进程程间间通通过过网网络络通通信信协协议议进进行行的的进进程程间的通信问题。间的通信问题。6.1.2 6.1.2 网络应用程序的标识问题网络应用程序的标识问题n n同一系统中不同进程间进行通信时,通过系统同一系统中不同进程间进行通信时,通过系统分配的进程号分配的进程号(Process ID)(Process ID)就可以惟一标识一个进就可以惟一标识一个进程。也就是说,要通信的进程只要知道对方的进程。也就是说,要通信的进程只要知道对方的进程号就可以进行通信。而网络情况下进程间的通程号就可以进行通信。而网

5、络情况下进程间的通信问题就要复杂得多,不能只简单地用进程号来信问题就要复杂得多,不能只简单地用进程号来标识不同的进程,因为各主机都独立地分配其进标识不同的进程,因为各主机都独立地分配其进程号。程号。 n n为为了了惟惟一一地地标标识识网网络络中中通通信信的的一一个个进进程程( (即即通通信的某一方信的某一方) ),就要使用一个如下的三元组:,就要使用一个如下的三元组:( (本地协议,本地本地协议,本地IPIP地址,本地端口号地址,本地端口号) ) n n 这这样样一一个个三三元元组组由由于于它它只只指指定定了了通通信信时时一一条条连连接接的的半半个个部部分分,即即通通信信的的一一方方,因因而而

6、称称为为半半相相关关(Half-(Half-association)association)。如如果果要要完完整整地地表表示示网网络络中中进进行行通通信信的的两两个个进程,那么就要使用一个如下结构的六元组:进程,那么就要使用一个如下结构的六元组:n n( (本本地地协协议议,本本地地地地址址,本本地地端端口口号号,远远地地协协议议,远地地址,远地端口号远地地址,远地端口号) )n n在在互互联联网网中中通通信信的的两两台台主主机机在在网网络络层层都都只只能能使使用用IPIP协协议议,但但在在网网络络层层之之上上可可以以选选择择使使用用TCPTCP协协议议或或UDPUDP协议,这样就可能得到以下

7、协议,这样就可能得到以下4 4种类型的相关六元组:种类型的相关六元组:n n ( (本本地地TCPTCP协协议议,本本地地IPIP地地址址,本本地地端端口口号号,远远程程TCPTCP协议,远程协议,远程IPIP地址,远程端口号地址,远程端口号) );n n ( (本地本地UDPUDP协议,本地协议,本地IPIP地址,本地端口号,远程地址,本地端口号,远程UDPUDP协议,远程协议,远程IPIP地址,远程端口号地址,远程端口号) ); n n( (本本地地TCPTCP协协议议,本本地地IPIP地地址址,本本地地端端口口号号,远远程程UDPUDP协议,远程协议,远程IPIP地址,远程端口号地址,远

8、程端口号) );n n( (本本地地UDPUDP协协议议,本本地地IPIP地地址址,本本地地端端口口号号,远远程程TCPTCP协议,远程协议,远程IPIP地址,远程端口号地址,远程端口号) )。n n如如果果通通信信的的两两端端使使用用不不同同的的协协议议( (后后两两类类六六元元组组) ),根根据据前前面面我我们们所所学学的的知知识识,由由于于TCPTCP协协议议和和UDPUDP协协议议使使用用的的协协议议格格式式大大不不相相同同,通通信信时时双双方方在在传传输输层层不不能能相相互互识识别别对对方方送送来来的的数数据据,也也就就不不可可能能进进行行正常的通信,因此后两种情况是不存在的。正常的

9、通信,因此后两种情况是不存在的。n n换换句句话话说说,通通信信的的两两个个进进程程在在端端到到端端的的传传输输层层只只能能使使用用相相同同的的协协议议,因因此此一一个个完完整整的的网网间间通通信信就就可可以以简简化化为为用用一一个五元组来标识通信的两个进程:个五元组来标识通信的两个进程:( (协议,本地协议,本地IPIP地址,本地端口号,远程地址,本地端口号,远程IPIP地址,远程端口号地址,远程端口号) )6.1.3 客户/服务器模型 1 1客户客户/ /服务器模型的特点服务器模型的特点n n客客户户/ /服服务务器器模模型型的的通通信信方方式式从从所所具具有有的的资资源源角角度度来来说说

10、,有有明明显显的的非非对对称称性性。服服务务器器拥拥有有较较多多的的资资源源,它它具具有有运运算算能能力力强强,数数据据存存储储容容量量大大,通通信信速速度度快快,系系统统的的可可靠靠性性高高等等优优点点。相相对对来来说说,客客户户则则拥拥有有较较少少的的资资源源,它它在在各各方方面面的性能一般要比服务器差。的性能一般要比服务器差。 n n客客户户/ /服服务务器器模模型型在在工工作作时时,要要求求有有一一套套客客户户机机和和服服务务器器能能共共同同识识别别的的规规则则或或约约定定,用用来来保保证证服服务务器器方方可可以以识识别别客客户户提提出出的的请请求求是是什什么么,客客户户方方也也能能够

11、够解解释释收收到到的的服服务务器器应应答答。从从本本质质上上来来说说,这这其其实实就就是是服服务务器器方方和和客客户户方方在在通通信信中中所所使使用用的的一套协议,它必须在通信的两端都被实现。一套协议,它必须在通信的两端都被实现。n n根据实际情况,协议可能是对称的也可能是根据实际情况,协议可能是对称的也可能是非对称的。在对称的协议中,每一方都有可能扮非对称的。在对称的协议中,每一方都有可能扮演主从角色;在非对称协议中,一方被不可改变演主从角色;在非对称协议中,一方被不可改变地认为是主机地认为是主机( (服务器服务器) ),而另一方则是从机,而另一方则是从机( (客客户机户机) )。 2 2服

12、务器的分类服务器的分类n n根根据据服服务务器器提提供供服服务务方方式式的的不不同同,服服务务器器可可以以分分为为串串行行服服务务器器和和并并发发服服务务器器。串串行行服服务务器器只只有有一一个个进进程程用用串串行行的的方方式式对对客客户户的的请请求求提提供供服服务务;并并发发服服务务器器可可以以为为请请求求的的每每一一个个客客户户创创建建一一个个进进程程或或线线程程,然然后后由由对对应应的的进进程程或或线线程程给给每每一一个个客客户户提提供供服服务务。并并发发服服务务器器又又可可以以分分为为预预先先创创建建服服务务子子进进程程( (或或线线程程) )和和按按需需创创建建服服务务子子进进程程(

13、 (或或线线程程) )两两种种方式。方式。n n根根据据上上面面的的分分析析,我我们们来来总总结结一一下下客客户户/ /服服务务器器模模型型的的特点。特点。对于服务器方来说:对于服务器方来说:n n服服务务进进程程一一般般在在启启动动后后就就一一直直运运行行,以以等等待待客客户户请请求求的到来,除非服务被禁止或执行强迫终止服务程序。的到来,除非服务被禁止或执行强迫终止服务程序。n n服服务务器器方方进进程程使使用用的的是是众众所所周周知知的的端端口口,否否则则客客户户无无法法知知道道提提供供服服务务的的端端口口,也也就就不不可可能提出服务的请求。能提出服务的请求。n n服服务务器器方方通通常常

14、拥拥有有较较多多的的资资源源( (对对称称方方式式除除外外) )。n n服服务务器器方方进进程程可可以以并并行行处处理理多多个个客客户户的的请请求求,当当然然可可以以同同时时处处理理的的客客户户请请求求数数目目是是有有一一定限制的。定限制的。n n服务器方在通信时属于被动的一方。服务器方在通信时属于被动的一方。对于客户方来说:对于客户方来说:n n在在需需要要服服务务时时向向服服务务器器提提出出请请求求,请请求求的的服服务务得得到到满满足足并并完完成成处处理理任任务务后后,就就终终止止客客户户程序的执行。程序的执行。n n 使用向系统申请的临时端口(如10245000之间)与服务器方进程进行通

15、信。n n拥有相对较少的资源(对称方式除外)。n n 客户方在通信时属于主动的一方。6.2 TCP/IP应用程序工作模型与网络编程接口应用程序工作模型与网络编程接口 6.2.1 TCP/IP应用程序工作模型n n使用TCP/IP协议的网络,其协议核心内容在层次结构的低三层,即网络接口层、IP层和传输层,而这三层的功能一般是由操作系统的内核来实现的。n n如图6-1所示的是两台主机的进程间通过网络编程接口进行通信的原理图。图6-1 TCP/IP应用程序工作模型图 n n图6-1所示的是使用TCP/IP协议网络的典型应用方式,即客户/服务器模式。n n通过图6-1用户还要明白一个问题,网络程序设计

16、其实是使用系统提供的网络协议完成用户程序的功能,即在网络应用程序中使用网络协议提供的服务,而不是让用户去实现网络协议各层的功能。 6.2.2 Windows Sockets简介1 1Windows SocketsWindows Sockets的概念的概念n nWindows Windows SocketsSockets是是在在WindowsWindows环环境境下下使使用的一套网络编程规范,常常简称为用的一套网络编程规范,常常简称为WinsockWinsock。2 2Windows SocketsWindows Sockets的来源的来源n nSocketsSockets本本来来是是UnixU

17、nix操操作作系系统统下下流流行行的的一一种种网网络络编编程程接接口口(API)(API),它它是是19831983年年在在BerkeleyBerkeley( (加加州州大大学学伯伯克克利利分分校校)4.2 )4.2 BSDBSD操操作作系系统统中中被被首首先先引引入入的的,因因此此被被称称为为“ “Berkeley Berkeley Socket Socket API”API”。 3Windows Sockets的版本n n目前常用的Winsock有两个版本:一个是16位的Winsock 1.1,由动态链接库WINSOCK.DLL提供支持;另一个是32位的Winsock 2.2,由动态链接库

18、WSOCK32.DLL提供支持。4Winsock API函数的分类n n在Winsock规范中把Winsock API函数集分为与BSD Socket(用在Unix中)相兼容的基本函数、网络数据信息检索函数和Windows专用扩展函数三类。 n nWinsockWinsock规范的核心内容是符合规范的核心内容是符合Berkeley Berkeley SocketSocket风格的库函数,但为了使程序员能充分利风格的库函数,但为了使程序员能充分利用用WindowsWindows消息驱动机制进行编程,又定义开发消息驱动机制进行编程,又定义开发了一组针对了一组针对WindowsWindows的扩展库

19、函数。的扩展库函数。 n n Windows Windows SocketsSockets规规范范中中针针对对WindowsWindows的的扩扩展展部部分分,为为应应用用程程序序开开发发者者提提供供了了开开发发WindowsWindows应应用用软软件件的的功功能能,它它有有利利于于程程序序员员写写出出更更加加稳稳定定并并 且且 更更 加加 高高 效效 的的 程程 序序 。 另另 外外 , 除除 了了WSAStartupWSAStartup()()和和WSACleanupWSACleanup()()两两个个函函数数外外( (在在6.56.5节节介介绍绍) ),其其他他WindowsWindo

20、ws扩扩展展函函数数的的使使用用不不是是强制性的。强制性的。各种各种各种各种WindowsWindowsWindowsWindows平台支持的平台支持的平台支持的平台支持的 Winsock Winsock Winsock Winsock 版本版本版本版本 Windows 95 Windows 95 Windows 95 Windows 95 1.1 1.1 1.1 1.1 (2.2)(2.2)(2.2)(2.2) Windows 98 Windows 98 Windows 98 Windows 98 2.2 2.2 2.2 2.2 Windows Me Windows Me Windows M

21、e Windows Me 2.2 2.2 2.2 2.2 Windows NT 4.0 Windows NT 4.0 Windows NT 4.0 Windows NT 4.0 2.2 2.2 2.2 2.2 Windows 2000 Windows 2000 Windows 2000 Windows 2000 2.2 2.2 2.2 2.2 Windows XP Windows XP Windows XP Windows XP 2.2 2.2 2.2 2.2 Windows CE Windows CE Windows CE Windows CE 1.1 1.1 1.1 1.15 5Windo

22、ws SocketsWindows Sockets对多线程的支持对多线程的支持n nWindows Windows SocketsSockets支支持持多多线线程程的的WindowsWindows进进程程。一一个个进进程程可可以以包包含含一一个个或或多多个个同同时时执执行行的的线线程程( (在在Windows Windows 3.13.1非非多多线线程程版版本本中中,一一个个任任务务对对应应了了一一个个仅具有单个线程的进程仅具有单个线程的进程) )。6.2.3 Windows Sockets规范的目标及几个相关的概念1 1Windows SocketsWindows Sockets规范的目标规

23、范的目标n nWindows Windows SocketsSockets规规范范的的目目标标有有两两个个:一一是是给给网网络络应应用用程程序序的的开开发发者者提提供供一一套套简简单单的的网网络络编编程程APIAPI;二二是是让让各各家家网网络络软软件件供供应应商商能能够够根根据据这这套套规规范范建建立立各各自自的的符符合合Windows Windows SocketsSockets标标准准的的实实现现和和应应用用程程序。序。n n此此外外,在在一一个个特特定定WindowsWindows版版本本的的基基础础上上,Windows Windows SocketsSockets也也定定义义了了一一

24、个个二二进进制制接接口口(ABI)(ABI),以以此此来来保保证证应应用用Windows Windows Sockets Sockets APIAPI的的应应用用程程序序能能够够在在任任何何网网络络软软件件供供应应商商的的符符合合Windows Windows SocketsSockets协议的实现上工作。协议的实现上工作。2 2Windows Windows SocketsSockets兼兼容容和和Windows Windows SocketsSockets提提供供者者n n遵遵守守Windows Windows SocketsSockets规规范范的的网网络络软软件件称称之之为为是是Win

25、dows Windows SocketsSockets兼兼容容的的,而而Windows Windows SocketsSockets兼兼容容实实现现的的提提供供者者称称之之为为Windows Windows SocketsSockets提提供供者者。一一个个网网络络软软件件供供应应商商必必须须百百分分之之百百地地实实现现Windows Windows SocketsSockets规范才能做到与规范才能做到与Windows SocketsWindows Sockets兼容。兼容。 3Windows Sockets应用程序n n任何能够与Windows Sockets兼容实现协同工作的应用程序都被

26、认为是具有Windows Sockets接口的,称这种应用程序为Windows Sockets应用程序。应用程序通过调用Windows Sockets的API实现它们之间的相互通信。Windows Sockets又利用下层的网络通信协议功能和操作系统调用来实现实际的通信工作。6.3 套接口的概念及其编程原理6.3.1 套接口(Socket)n nWindows Windows Sockets Sockets APIAPI依依靠靠套套接接口口(Socket)(Socket)进进行行通通信信。套套接接口口可可以以看看成成是是两两个个网网络络应应用用程程序序进进行行通通信信时时,各各自自通通信信连连

27、接接中中的的一一个个端端点点。通通信信时时,其其中中的的一一个个网网络络应应用用程程序序将将要要传传输输的的一一段段信信息息写写入入它它所所在在主主机机的的SocketSocket中中,该该SocketSocket通通过过网网络络接接口口卡卡(NIC)(NIC)的的传传输输介介质质将将这这段段信信息息发发送送到到另另一一台台主主机机的的SocketSocket中中,使使这这段段信信息息能能传传送送到到其其他他程程序序中中,如图如图6-26-2所示。所示。 图6-2 套接口示意图 n n现在我们根据图6-2来分析一下使用套接口进行通信的过程。当主机A(Host A)上的网络应用程序(Progra

28、m A)要发送数据时,通过调用数据发送函数首先将要发送的一段信息写入其Socket中,Socket中的内容通过主机A的网络管理软件由主机A的网络接口卡发送到主机B(Host B),主机B的网络接口卡接收到这段信息后,再传送给主机B的网络管理软件,网络管理软件将这段信息保存在主机B的Socket中,然后程序B(Program B)才能在Socket中读取并使用这段信息。n n从以上的通信过程可以看出,如果不考虑通信过程中的网络接口卡和传输介质等,则网络通信的过程就是由数据的发送者将要发送的信息写入一个套接口,再通过中间环节将信息传输到接收端的套接口中,然后就可以由接收端的应用程序将信息从套接口中

29、取出。因此,两个应用程序之间的数据传输要通过套接口来完成。在学习了后面更多的内容后我们将会体会到,套套接接口口的的本本质质是是通通信信过过程程中中所所要使用的一些缓冲区及一些相关的数据结构要使用的一些缓冲区及一些相关的数据结构。6.3.2 套接口的分类n n为了满足不同的通信程序对通信质量和性能的要求,一般的网络系统提供了三种不同类型的套接口,以供用户在设计网络应用程序时根据不同的要求来选择。这三种套接口分别是:(1) 流式套接口(SOCK_STREAM) 。(2) 数据报套接口(SOCK_DGRAM) 。(3) 原始套接口(SOCK_RAW) 。流套接字(SOCK_STREAM):用于提供面

30、向连接、可靠的数据传输服务。 该服务将保证数据能够实现无差错、无重复发送,并按顺序接收。 流套接字之所以能够实现可靠的数据服务,原因在于其使用了传输控制协议TCP。 这类套接字中,传输数据之前必须在两个应用进程之间建立一条通信连接,这就确保了参与通信的两个应用进程都是活动并且响应的。 当连接建立之后,应用进程只要通过套接字向TCP层发送数据流,而另一个应用进程便可以接收到相应的数据流,它们不需要知道传输层是如何对数据流进行处理。 特别需要注意的是通信连接必须显式建立。该套接字类型适合传输大量的数据,但不支持广播和多播方式。数据报套接字(数据报套接字(数据报套接字(数据报套接字(SOCK_DGR

31、AMSOCK_DGRAM):提供了一种无连:提供了一种无连接的服务,通信双方不需要建立任何显式连接,数据接的服务,通信双方不需要建立任何显式连接,数据可以发送到指定的套接字,并且可以从指定的套接字可以发送到指定的套接字,并且可以从指定的套接字接收数据。接收数据。该服务并不能保证数据传输的可靠性,数据有可能在该服务并不能保证数据传输的可靠性,数据有可能在传输过程中丢失或出现数据重复,且无法保证顺序地传输过程中丢失或出现数据重复,且无法保证顺序地接收到数据。接收到数据。数据报套接字使用数据报套接字使用UDPUDP进行数据的传输。进行数据的传输。由于数据包套接字不能保证数据传输的可靠性,对于由于数据

32、包套接字不能保证数据传输的可靠性,对于有可能出现的数据丢失情况,需要在程序中做相应的有可能出现的数据丢失情况,需要在程序中做相应的处理。处理。与数据报套接字相比,使用流式套接字是一个更为可与数据报套接字相比,使用流式套接字是一个更为可靠的方法,但对于某些应用,建立一个显式连接所导靠的方法,但对于某些应用,建立一个显式连接所导致的系统开销是令人难以接收的,并且数据报套接字致的系统开销是令人难以接收的,并且数据报套接字支持广播和多播方式。支持广播和多播方式。原始套接字(原始套接字(SOCK_RAW):与标准套接字(标准套接字指的是前面介绍的流套接字和数据报套接字)的区别在于:原始套接字可以读写内核

33、没有处理的IP数据包流套接字只能读取TCP的数据数据报套接字只能读取UDP的数据。使用原始套接字的主要目的是为了避开TCP/IP处理机制,被传送的数据包可以被直接传送给需要它的应用程序。因此,其主要是在编写自定义底层协议的应用程序时使用,例如各种不同的TCP/IP实用程序(如ping和arp)都使用原始套接字实现,也可以用来实现数据包捕捉分析等。6.3.3 套接口编程原理该过程可以分为以下几个阶段:该过程可以分为以下几个阶段:(1) (1) 电电信信局局必必须须要要有有一一个个电电话话总总机机,相相当当于于套套接接口口通通信信机机制制中中提提供供服服务务的的服服务务器器。在在SocketSoc

34、ket中中通通过过调调用用socket()socket()函函数数来来开开启启一一个个服服务务,即即创创建建一一个提供服务的套接口。个提供服务的套接口。(2) (2) 电信局必须给电话总机分配一个号码电信局必须给电话总机分配一个号码( (如如114114,即查号服务的号码是,即查号服务的号码是114)114),以便用户通过拨,以便用户通过拨该号码得到电话服务,同时接入该电信局的用户该号码得到电话服务,同时接入该电信局的用户必须知道该总机的号码。必须知道该总机的号码。 (3) (3) 电电信信局局114114查查号号台台下下会会开开设设一一些些自自动动服服务务的的分分机机,但但是是它它们们的的数

35、数量量是是有有限限的的。总总机机开开通通后后就就一一直直在在监监听听(listen)(listen)用用户户的的拨拨号号,用用户户拨拨打打114114时时,可可能能拨拨通通,得得到到服服务务;也也可可能能拨拨不不通通,就就会会听听到到忙忙音音。同同样样,我我们们在在建建立立一一个个SocketSocket服服务务时时,也也会会调调用用listen()listen()函函数数来来监监听听客客户的请求。户的请求。(4) (4) 对对于于用用户户来来说说,如如果果知知道道电电信信局局的的查查号号号号码码,在在想想得得到到查查号号服服务务时时就就可可以以拨拨打打114114,请请求求得得到到电电信信局

36、局的的服服务务,这这相相当当于于在在客客户户端端要要进行的操作。进行的操作。 (5) (5) 电信局的总机接受了某用户拨打的电话电信局的总机接受了某用户拨打的电话后,负责把用户与一个分机连通,而总机本身后,负责把用户与一个分机连通,而总机本身则又回到等待状态,等待其他客户的请求。则又回到等待状态,等待其他客户的请求。 (6) (6) 服服务务完完成成后后,挂挂上上电电话话,线线路路断断开开,一一次次服服务务过过程程结结束束,否否则则该该线线路路将将一一直直被被占占用用,浪浪费费了了通通信信资资源源。在在服服务务器器和和客客户户之之间间,最最后后也也要要使使用用closesocketcloses

37、ocket()()函函数数关关闭闭套套接接口口,释释放放该该套套接接口口上上的的有有关关资资源源,这这可可以以由由通通信信的的任任何何一一方或双方同时提出。方或双方同时提出。6.3.4 Winsock套接口编程时对错误的处理机制 n n用户编写网络应用程序时,出现错误是不可避用户编写网络应用程序时,出现错误是不可避免的,因此对错误的检查和控制至关重要,一个好免的,因此对错误的检查和控制至关重要,一个好的或者说成功的的或者说成功的WinsockWinsock应用程序应该尽可能地检应用程序应该尽可能地检测和处理各种错误。测和处理各种错误。n n对对WinsockWinsock函数来说,返回错误是很

38、常见的。与函数来说,返回错误是很常见的。与大多数系统调用类似,大多数系统调用类似,WinsockWinsock函数发生的错误也函数发生的错误也有两种。有两种。n n不成功的不成功的WinsockWinsock函数调用返回的最常见的值是函数调用返回的最常见的值是宏定义宏定义SOCKET_ERRORSOCKET_ERROR,在,在WinsockWinsock的头文件中的头文件中( (如如Winsock2.h)Winsock2.h),它的数值是它的数值是 1 1。 该函数的使用非常简单,格式如下:该函数的使用非常简单,格式如下:intint WSAGetLastErrorWSAGetLastErro

39、r ( void ); ( void );n n这这是是一一个个无无参参函函数数,调调用用时时返返回回最最新新发发生生的的网网络络错错误误代码。代码。n n调调用用该该函函数数时时要要注注意意,当当一一特特定定的的Windows Windows Sockets Sockets APIAPI函函数数指指出出一一个个错错误误已已经经发发生生时时,就就应应该该调调用用本本函函数数来来获获得得对对应应的的错错误误代代码码。WSAGetLastErrorWSAGetLastError()()函函数数返返回回的的这这些些错错误误都都已已预预定定义义成成常常量量值值,根根据据WinsockWinsock版版

40、本本的的不不同同,这这些些值值的的声声明明不不在在Winsock1.hWinsock1.h中中,就就在在Winsock2.hWinsock2.h中中。这这两两个个头头文文件件的的惟惟一一差差别别是是Winsock2.hWinsock2.h中中包包含含的的错错误误代代码码( (针针对对Winsock Winsock 2 2而而引引入入的的一一些些新新的的APIAPI函函数数) )更更多多。为为各各种种错错误误代代码定义的常量码定义的常量( (带有带有# #定义的宏定义的宏) )一般都以一般都以WSAEWSAE开头。开头。 6.3.5 网络字节顺序n n不不同同的的主主机机对对字字节节值值的的存存

41、储储顺顺序序不不同同。在在存存储储由由多多个个字字节节组组成成的的一一个个字字时时,有有的的计计算算机机在在起起始始地地址址处处存存放放整整数数的的低低序序号号字字节节,这这种种存存储储格格式式叫叫“ “小小序序在在前前” ”(Little-endian)(Little-endian);而而有有的的计计算算机机在在起起始始地地址址处处存存放放整整数数的的高高序序号号字字节节,这这种种存存储储格格式式叫叫“ “大大序序在在前前” ”(Big-endian)(Big-endian)。n n计算机究竟采用那种字节存储顺序由各自的设计计算机究竟采用那种字节存储顺序由各自的设计决定,如决定,如Windo

42、wsWindows系列的操作系统使用的是小序在前系列的操作系统使用的是小序在前的存储方式,而的存储方式,而Sun OSSun OS和和SolarisSolaris等采用的大序在前的等采用的大序在前的存储方式。存储方式。 n n在在计计算算机机中中,TCP/IPTCP/IP协协议议使使用用的的1616位位整整数数( (如如端端口口号号) )和和3232位位整整数数( (如如IPIP地地址址) )是是按按计计算算机机各各自的自的“ “主机字节主机字节” ”(Host-byte)(Host-byte)来表示的。来表示的。n n在网络中,为了保证数据的正确性,网络通在网络中,为了保证数据的正确性,网络

43、通信协议中必须指定网络字节顺序。如果在网络信协议中必须指定网络字节顺序。如果在网络中使用中使用IPIP地址和端口号,按地址和端口号,按“ “互联网联网标准互联网联网标准” ”的要求,指定的多字节值必须用的要求,指定的多字节值必须用“ “大序在前大序在前” ”的形式来表示,一般称之为的形式来表示,一般称之为“ “网络字节网络字节” ”(Network-byte)(Network-byte)顺序。顺序。 在在WinsockWinsock中中,有有一一系系列列的的函函数数可可用用于于多多字字节节数数的的转转换换,把把它它们们从从主主机机字字节节顺顺序序转转换换成成网网络络字字节节顺顺序序,反反之之亦

44、亦然然。下下面面4 4个个APIAPI函函数数便便将将一一个个数数从从主主机机字字节节顺顺序序转转换换成成网网络络字字节顺序:节顺序:n nhtonlhtonl() ():参参数数是是主主机机字字节节顺顺序序的的一一个个4 4字字节节数数,函函数数返返回回网网络字节顺序的数;络字节顺序的数;n nWSAHtonlWSAHtonl() ():参参数数是是主主机机字字节节顺顺序序的的一一个个4 4字字节节数数,函函数数返回网络字节顺序的数;返回网络字节顺序的数;n nhtonshtons() ():参参数数是是主主机机字字节节顺顺序序的的一一个个2 2字字节节数数,函函数数返返回回网网络字节顺序的

45、数;络字节顺序的数;n nWSAHtonsWSAHtons() ():参参数数是是主主机机字字节节顺顺序序的的一一个个2 2字字节节数数,函函数数返回网络字节顺序的数。返回网络字节顺序的数。6.4 Winsock API基本函数套接口与连接的建立6.4.1 6.4.1 打开打开WinsockWinsockWSAStartupWSAStartup()()应应用用程程序序或或DLLDLL只只能能在在一一次次成成功功的的WSAStartupWSAStartup()()调调用之后才能进一步调用其他的用之后才能进一步调用其他的Windows Sockets APIWindows Sockets API函

46、数。函数。1 1函数格式函数格式WSAStartupWSAStartup()()函数的格式如下:函数的格式如下:intint WSAStartupWSAStartup( (WORD WORD wVersionRequestedwVersionRequested, ,LPWSADATA LPWSADATA lpWSADatalpWSAData) );2 2函数参数说明函数参数说明wVersionRequestedwVersionRequested:此此参参数数是是一一个个WORDWORD型型( (双双字字节节型型) )数数值值,它它指指定定准准备备在在应应用用程程序序中中要要使使用用的的Wins

47、ockWinsock库库的的版版本本号号。其其中中,用用高高位位字字节节指指定定副副版版本本,用用低低位位字字节节指指定定主主版版本本。就就目目前前的的Win32Win32平平台台而而言言,Winsock Winsock 2 2库库的的最最新新版版本本是是2.2(Win952.2(Win95为为Winsock Winsock 1.1)1.1)。如如果果需需要要加加载载Winsock Winsock 2.22.2版版,指指 定定 此此 参参 数数 的的 值值 为为 0x02020x0202; 也也 可可 使使 用用 宏宏MAKEWORD(X,Y)MAKEWORD(X,Y),其其中中X X为为高高

48、位位字字节节,Y Y为为低低位位字字节节,如如MAKEWORD(2,2)MAKEWORD(2,2)。lpWSADatalpWSAData:此参数是一个指向此参数是一个指向WSADATAWSADATA结构的指针。结构的指针。当该函数被调用时,它返回关于当该函数被调用时,它返回关于Windows SocketsWindows Sockets实现的详实现的详细信息,该结构的定义如下:细信息,该结构的定义如下: typedeftypedef structstruct WSADataWSAData WORDWORD wVersionwVersion; ;WORDWORD wHighVersionwHig

49、hVersion; ;CharChar szDescriptionWSADESCRIPTION_LEN+1; szDescriptionWSADESCRIPTION_LEN+1;CharChar szSystemStatusWSASYS_STATUS_LEN+1; szSystemStatusWSASYS_STATUS_LEN+1;unsigned shortunsigned short iMaxSocketsiMaxSockets; ;unsigned shortunsigned short iMaxUdpDgiMaxUdpDg; ;char FAR *char FAR * lpVendor

50、InfolpVendorInfo; ; WSADATA WSADATA,FAR *LPWSADATA;FAR *LPWSADATA;各字段的含义说明如下:各字段的含义说明如下: wVersionwVersion:调用者希望使用的调用者希望使用的WinsockWinsock版本号;版本号; wHighVersionwHighVersion: 加加 载载 的的 WinsockWinsock库库 所所 支支 持持 的的 最最 高高WinsockWinsock版本版本, ,通常和通常和wVersionwVersion的值相同;的值相同; szDescriptionszDescription:系系统统加

51、加载载的的WinsockWinsock库库的的说说明明字字符符串串,如如“ “Winsock 2.0”Winsock 2.0”; szSystemStatusszSystemStatus:系统状态或配置信息的说明字符串;系统状态或配置信息的说明字符串; iMaxSocketsiMaxSockets:套套接接口口的的最最大大编编号号( (该该字字段段被被Winsock Winsock 2 2或其后的版本忽略或其后的版本忽略) ); iMaxUdpDgiMaxUdpDg:UDPUDP数数据据报报的的最最大大容容量量( (该该字字段段被被Winsock Winsock 2 2或其后的版本忽略或其后的

52、版本忽略) ); lpVendorInfolpVendorInfo:厂商专有信息厂商专有信息( (该字段被该字段被Winsock 2Winsock 2或其后的或其后的版本忽略版本忽略) )。3 3函数返回信息函数返回信息WSAStartupWSAStartup()()函函数数的的返返回回值值是是一一个个整整数数,如如果果调调用用成成功功则返回则返回0 0。 WSAStartupWSAStartup()()函数调用不成功时返回如下的错误信息:函数调用不成功时返回如下的错误信息: WSASYSNOTREADYWSASYSNOTREADY:在在WinsockWinsock的的头头文文件件Winsoc

53、k2.hWinsock2.h中中,该该错错误误代代码码定定义义的的数数值值为为1009110091,它它表表明明加加载载的的Winsock Winsock DLLDLL不存在或底层的网络子系统无法使用。不存在或底层的网络子系统无法使用。 WSAVERNOTSUPPORTEDWSAVERNOTSUPPORTED:该该代代码码的的数数值值为为1009210092,所所需需 的的 Windows Windows Sockets Sockets APIAPI的的 版版 本本 未未 由由 特特 定定 的的 Windows Windows SocketsSockets实实现现提提供供。 如如果果由由wVe

54、rsionwVersion返返回回的的版版本本用用户户不不能能接接受受, ,则要调用则要调用WSACleanupWSACleanup()()函数清除对函数清除对WinsockWinsock的加载。的加载。 WSAEINVALWSAEINVAL:该该代代码码的的数数值值为为1002210022,说说明明应应用用程程序序指指出出的的Windows Windows SocketsSockets版版本本不不能能被被该该Winsock Winsock DLLDLL的的实实现现所所支支持。持。 WSAEINPROGRESSWSAEINPROGRESS:该该代代码码的的数数值值为为1003610036,说说

55、明明一一个个阻塞的阻塞的WinsockWinsock调用正在进行中。调用正在进行中。 WSAEPROCLIMWSAEPROCLIM:该代码的数值为该代码的数值为1006710067,说明已经达到,说明已经达到了了Windows SocketsWindows Sockets实现所支持的任务数量的极限。实现所支持的任务数量的极限。 WSAEFAULTWSAEFAULT: 该该 代代 码码 数数 值值 为为 1001410014, 说说 明明lpWSADatalpWSAData参数是一个无效的指针。参数是一个无效的指针。n n注注意意:在在这这里里为为了了便便于于大大家家理理解解错错误误代代码码,列

56、列出出了了给给错错误误代代码码定定义义的的数数值值。以以后后为为了了节节省省篇篇幅幅,不不再再列列出出错错误误代代码码的的数数值值。如如果果要要查查询询对对应应错错误误代代码码对对应应的的数数值值,可可以以在在WinsockWinsock的的头头文文件件Winsock.hWinsock.h或或Winsock2.hWinsock2.h中中去查找。去查找。4 4函数使用说明函数使用说明如如果果用用户户在在没没有有正正确确加加载载Winsock Winsock DLLDLL的的情情况况下下使使用用了了其其 他他 的的 Winsock Winsock APIAPI函函 数数 , 则则 被被 调调 用用

57、 的的 函函 数数 返返 回回WSANOTINITIALISEDWSANOTINITIALISED错误信息,代码为错误信息,代码为1009310093。该函数在程序中的基本使用方法如下:该函数在程序中的基本使用方法如下:#include#include/其他代码WORD wVersionRequested;WSADATA wsaData;wVersionRequested=MAKEWORD(2,2);if(WSAStartup(wVersionRequested,&wasData)!=0) /Winsock/Winsock初始化错误初始化错误/ /输出输出WinsockWinsock初始化错误

58、提示信息,如初始化错误提示信息,如“ “WSAStartupWSAStartup failed” failed”return;return; / /下面可以用两种方法中的任一种进行版本号匹配的检查下面可以用两种方法中的任一种进行版本号匹配的检查/ /if(LOBYTE(wsaData.wVersionif(LOBYTE(wsaData.wVersion)!=2|HIBYTE(wsaData.wVersi)!=2|HIBYTE(wsaData.wVersion)!=0)on)!=0)if(wsaData.wVersionif(wsaData.wVersion!=!=wVersionRequest

59、edwVersionRequested) ) /Winsock/Winsock版本号不匹配版本号不匹配/ /输出输出WinsockWinsock版本号不匹配的错误提示信息版本号不匹配的错误提示信息; ;WSACleanupWSACleanup();();return;return; / /说说明明Winsock Winsock DLLDLL的的加加载载正正确确,可可以以执执行行以以下下的的其他代码其他代码/其他程序代码其他程序代码结结束束对对Winsock Winsock DLLDLL库库的的使使用用时时,一一定定要要调调用用WSACleanupWSACleanup()()函数卸载所加载的库。

60、函数卸载所加载的库。#include #include void main(void) void main(void) WSADATA WSADATA wsaDatawsaData; / ; / 初始化初始化 Winsock Winsock 版本版本 2.22.2 if (Ret = WSAStartup(MAKEWORD(2,2), &if (Ret = WSAStartup(MAKEWORD(2,2), &wsaDatawsaData) != 0) != 0) printf(WSAStartupprintf(WSAStartup failed with error %dn, Ret); f

61、ailed with error %dn, Ret); return; return; / / 编写编写 Winsock Winsock 通信代码通信代码 / / 程序结束后调用程序结束后调用 WSACleanupWSACleanup if (if (WSACleanupWSACleanup() = SOCKET_ERROR)() = SOCKET_ERROR) printf(WSACleanupprintf(WSACleanup failed with error %dn, failed with error %dn, WSAGetLastErrorWSAGetLastError(); ()

62、; WinsockWinsock应用程序框架应用程序框架6.4.2 6.4.2 创建套接口创建套接口socket()socket()或或WSASocketWSASocket()()应应用用程程序序在在使使用用套套接接口口通通信信前前,必必须须要要拥拥有有一一个个套套接接口口。使使用用socket()socket()或或WSASocketWSASocket()()函函数数来来给给应应用用程程序创建一个套接口序创建一个套接口1 1函数格式函数格式 在在Winsock Winsock 1 1中中提提供供的的创创建建套套接接口口函函数数的的格格式式如如下下: SOCKET SOCKET sockets

63、ocket( ( intint afaf, , intint type, type, intint protocol protocol ); );在Winsock 2中提供的该函数的扩展格式如下: SOCKET WSASocket( int af, int type, int protocol, LPWSAPROTOCOL_INFO lpProtocolInfo, Group g, int iFlags );2 2函数参数说明函数参数说明以以上上两两种种格格式式中中,前前面面三三个个参参数数的的含含义义是是一一样样的的,说说明明如下:如下: afaf:该该参参数数说说明明套套接接口口要要使使用

64、用的的协协议议地地址址族族,地地址址族族与与协协议议族族的的含含义义相相同同。如如果果想想建建立立一一个个UDPUDP或或TCPTCP套套接接口口,只只能能用用常常量量AF_INETAF_INET表表示示使使用用互互联联网网协协议议(IP)(IP)地地址址。当当然然,Winsock 2Winsock 2还支持其他的协议,但一般在程序中很少使用。还支持其他的协议,但一般在程序中很少使用。 typetype:该该参参数数描描述述套套接接口口的的协协议议类类型型。当当第第一一个个参参数数afaf是是 AF_INETAF_INET时时 , 它它 只只 能能 使使 用用 SOCK_STREAMSOCK_

65、STREAM、SOCK_DGRAMSOCK_DGRAM或或SOCK_RAWSOCK_RAW三三个个协协议议类类型型中中的的任任一一个个,分分别别表表示示要要创创建建的的是是流流式式套套接接口口、数数据据报报套套接接口口或或原原始始套套接接口。口。 protocolprotocol:该该参参数数说说明明该该套套接接口口使使用用的的特特定定协协议议。当当协协议议地地址址族族afaf和和协协议议类类型型typetype已已经经确确定定后后,协协议议字字段段可可以以使使用用的的值值是是限限定定的的,如如表表6-16-1所所示示。如如果果调调用用者者不不希希望望特特别别指指定定所所使使用用的的协协议议,

66、可可以以将将此此参参数数设设置置为为0 0,系系统统就就根根据据前前两两个个参参数数的的值值自自动动确确定定一一个个协协议议字字段段的的取值。取值。以上三个参数就可以确定一个套接口,它们之间以上三个参数就可以确定一个套接口,它们之间的对应关系可以用表的对应关系可以用表6-16-1表示。表示。 表6-1 套接口参数 系系统统可可以以根根据据这这三三个个参参数数建建立立一一个个套套接接口口,并并给给它它分分配配相相应应的的资资源源,同同时时返返回回一一个个整整型型套套接接口口号号。因因此此,socket()socket()函函数数调调用用实实际际上上指指定定了了相相关关五五元元组组中中的的“ “协

67、协议议” ”这这一元。一元。使使用用Winsock Winsock 2 2时时,一一般般可可以以先先用用WSAEnumProtocolsWSAEnumProtocols()()函函数数( (该该函函数数在在第第8 8章章介介绍绍) ),以以获获得得系系统统所所安安装装协协议议的的相相关关信信 息息 。 当当 然然 对对 现现 在在 的的 绝绝 大大 部部 分分 用用 户户 来来 说说 , 直直 接接 使使 用用AF_INET(IPAF_INET(IP协协议议族族) )就就可可以以了了,因因为为几几乎乎所所有有的的协协议议实实现现系系统统都都支支持持IPIP协协议议族族。但但要要编编写写通通用用

68、性性好好的的应应用用程程序序时时,最最好好还还是是先先使使用用WSAEnumProtocolsWSAEnumProtocols()()函函数数查查询询一一下下系系统统安安装的协议。装的协议。在在Winsock Winsock 2 2提提供供的的扩扩展展格格式式中中,增增加加了了三三个个参参数数,其其含含义义说说明明如如下下( (因因为为常常用用的的是是格格式式1 1,所所以以这这三三个个参参数数只需了解其大概的含义只需了解其大概的含义) ): lpProtocolInfolpProtocolInfo:一一个个指指向向WSAPROTOCOL_INFOWSAPROTOCOL_INFO结结构构的的指

69、指针针,该该结结构构定定义义所所创创建建套套接接口口的的特特性性。如如果果本本参参数数不不指指向向空空(NULL)(NULL),则则前前三三个个参参数数( (afaf, , type, type, protocol)protocol)被被忽忽略略,系系统统就就根根据据该该结结构构中中三三个个字字段段的的值值确确定定套套接接口口类型。类型。 g g:套套接接口口组组的的描描述述字字。组组参参数数始始终终为为0 0,因因为为目目前尚无可支持套接口组的前尚无可支持套接口组的WinsockWinsock版本。版本。 iFlagsiFlags:套接口属性描述。套接口属性描述。iFlagsiFlags可用

70、参数如下:可用参数如下:WSA_FLAG_OVERLAPPEDWSA_FLAG_OVERLAPPEDWSA_FLAG_MULTIPOINT_C_ROOTWSA_FLAG_MULTIPOINT_C_ROOTWSA_FLAG_MULTIPOINT_C_LEAFWSA_FLAG_MULTIPOINT_C_LEAFWSA_FLAG_MULTIPOINT_C_ROOFWSA_FLAG_MULTIPOINT_C_ROOFWSA_FLAG_MULTIPOINT_D_LEAFWSA_FLAG_MULTIPOINT_D_LEAF第第一一个个标标志志WSA_FLAG_OVERLAPPEDWSA_FLAG_OVER

71、LAPPED用用于于指指定定这这个个套套接接口口具具备备重重叠叠I/O(I/O(是是适适用用于于WinsockWinsock的的通通信信模模式式之之一一) )的的特特性性。调调用用socket()socket()建建立立一一个个套套接接字字时时,WSA_FLAG_OVERLAPPEDWSA_FLAG_OVERLAPPED便便是是默默认认设设置置。一一般般说说来来,在在使使用用WSASocketWSASocket时时,最最好好始始终终保保持持设设定定该该标标志志。后后面面4 4个个标标志用于处理多播套接口。志用于处理多播套接口。3 3函数返回信息函数返回信息该该函函数数调调用用成成功功后后,返返

72、回回新新创创建建的的套套接接口口号号,它它被被定定义义成是一个无符号的整型数据。成是一个无符号的整型数据。函函数数调调用用错错误误时时返返回回INVALID_SOCKETINVALID_SOCKET,应应用用程程序序可可进进一一步步调调用用WSAGetLastErrorWSAGetLastError()()函函数数来来获获取取相相应应的的错错误误代代码码。可能获得的错误代码说明如下:可能获得的错误代码说明如下: WSANOTINITIALISEDWSANOTINITIALISED: 在在 调调 用用 本本 APIAPI之之 前前 应应 成成 功功 调调 用用WSAStartupWSAStart

73、up();();WSAENETDOWNWSAENETDOWN:网络子系统失效;网络子系统失效; WSAEAFNOSUPPORTWSAEAFNOSUPPORT:不支持指定的地址族;不支持指定的地址族; WSAEINPROGRESSWSAEINPROGRESS:一一个个阻阻塞塞的的WinsockWinsock调调用用正正在在进进行行中中,或者服务提供者仍在处理一个回调函数;或者服务提供者仍在处理一个回调函数; WSAEMFILEWSAEMFILE:无可用的套接口描述字;无可用的套接口描述字; WSAENOBUFSWSAENOBUFS:无可用的缓冲区空间,套接口无法创建;无可用的缓冲区空间,套接口无

74、法创建; WSAEPROTONOSUPPORTWSAEPROTONOSUPPORT:不支持指定的协议;不支持指定的协议; WSAEPROTOTYPEWSAEPROTOTYPE:指指定定的的协协议议对对于于本本套套接接口口类类型型错错误;误; WSAESOCKTNOSUPPORTWSAESOCKTNOSUPPORT:本本地地址址族族不不支支持持指指定定的的套接口类型;套接口类型; WSAEINVALWSAEINVAL:g g参数非法。参数非法。4 4函数使用说明函数使用说明 要创建一个流套接口时,可以使用下列三种格式之一:要创建一个流套接口时,可以使用下列三种格式之一:SOCKET SOCKET

75、 sockidsockid= =socket(AF_INET,SOCK_STREAM,IPPROTO_TCPsocket(AF_INET,SOCK_STREAM,IPPROTO_TCP); );SOCKET SOCKET sockidsockid=WSASocket(AF_INET,SOCK_STREAM,0);=WSASocket(AF_INET,SOCK_STREAM,0);SOCKET SOCKET sockidsockid=WSASocket(AF_INET,SOCK_STREAM,0,NULL,0,=WSASocket(AF_INET,SOCK_STREAM,0,NULL,0, WS

76、A_FLAG_OVERLAPPED);WSA_FLAG_OVERLAPPED);要要创创建建一一个个数数据据报报套套接接口口时时,其其格格式式如如下下( (为为节节省省篇篇幅幅,两种套接口的创建只给出了一种格式两种套接口的创建只给出了一种格式) ):SOCKET SOCKET sockidsockid= =socket(AF_INET,SOCK_GDRAM,IPPROTO_UDPsocket(AF_INET,SOCK_GDRAM,IPPROTO_UDP); );要创建一个原始套接口时,其格式如下:要创建一个原始套接口时,其格式如下:SOCKET SOCKET sockidsockid= =so

77、cket(AF_INET,SOCK_RAW,IPPROTO_ICMPsocket(AF_INET,SOCK_RAW,IPPROTO_ICMP); ); 6.4.3 6.4.3 指定本地地址指定本地地址bind()bind()当当用用socket()socket()创创建建了了一一个个套套接接口口后后,该该套套接接口口还还是是不不能能直直接接使使用用,因因为为它它只只存存在在于于一一个个名名字字空空间间( (地地址址族族) )中中,也也就就是是说说它它只只确确定定了了通通信信所所希希望望使使用用的的服服务务类类型型,并并没没有有与与该该主主机机上上提提供供服服务务的的某某端端口口联联系系在在一一

78、起起,这这样样的的套套接接口口可以叫未命名的套接口。可以叫未命名的套接口。bind()bind()函函数数通通过过给给一一个个未未命命名名的的套套接接口口分分配配一一个个本本地地名名字字来来为为套套接接口口建建立立本本地地捆捆绑绑,即即把把一一个个套套接接口口与与一一个个主主机机地地址址和和端端口口号号联联系系起起来来。本本函函数数适适用用于于数数据据报报或或流流类类套套接口。接口。1 1函数格式函数格式bind()bind()函数的格式如下:函数的格式如下:intint bind( bind(SOCKET s,SOCKET s,const const structstruct sockadd

79、rsockaddr FAR* name, FAR* name,intint namelennamelen); );2 2函数参数说明函数参数说明bind()bind()函数中各参数的说明如下:函数中各参数的说明如下: s s:标标识识一一未未绑绑定定套套接接口口的的描描述述字字,它它它它是是是是socket()socket()函函函函数数数数调调调调用用用用成功时返回的值成功时返回的值成功时返回的值成功时返回的值。 namename:是是一一个个与与指指定定协协议议有有关关的的地地址址结结构构指指针针, ,它它指指向向的的值值是是赋赋予予套套接接口口的的地地址址信信息息。在在WinsockWi

80、nsock中中使使用用sockaddr_insockaddr_in结结构指定构指定IPIP地址和端口信息,它的定义如下:地址和端口信息,它的定义如下:structstruct sockaddr_insockaddr_in short short sin_familysin_family; ;u_short u_short sin_port;sin_port;structstruct in_addrin_addrsin_addrsin_addr; ;charcharsin_zero8;sin_zero8; sin_familysin_family字字段段必必须须为为AF_INETAF_INET,

81、以以告告诉诉WinsockWinsock所所使用的是使用的是IPIP地址族;地址族;sin_portsin_port是是以以网网络络字字节节顺顺序序表表示示的的1616位位端端口口号号;sin_addrsin_addr是是以以网网络络字字节节顺顺序序表表示示的的3232位位IPIP地地址址;sin_zerosin_zero字字段段不不用用,一一般般用用0 0填填充充,在在程程序序中中通通常常是是使用使用sockaddr_insockaddr_in之前将整个结构置之前将整个结构置0 0。 namelennamelen:bind()bind()函数的这个参数指地址参数函数的这个参数指地址参数(na

82、me)(name)的的长度。长度。 3 3函数返回信息函数返回信息如如果果调调用用没没有有错错误误发发生生,则则bind()bind()返返回回0 0,否否则则将将返返 回回 SOCKET_ERRORSOCKET_ERROR, 应应 用用 程程 序序 可可 进进 一一 步步 通通 过过WSAGetLastErrorWSAGetLastError()()函函数数来来获获取取相相应应的的错错误误代代码码。下下面面是可能获取的错误代码:是可能获取的错误代码: WSANOTINITIALISEDWSANOTINITIALISED:在在使使用用此此APIAPI之之前前应应首首先成功调用先成功调用WSAS

83、tartupWSAStartup()(); WSAENETDOWNWSAENETDOWN:WindowsWindows套套接接口口实实现现检检测测到到网络子系统失效;网络子系统失效; WSAEADDRINUSEWSAEADDRINUSE:所指定的端口已在使用中;所指定的端口已在使用中; WSAEFAULTWSAEFAULT:namelennamelen参参数数太太小小( (小小于于sockaddrsockaddr结结构构的的大大小小) ); WSAEINPROGRESSWSAEINPROGRESS:一一个个阻阻塞塞的的WindowsWindows套套接接口口调调用用正在运行中;正在运行中; W

84、SAEAFNOSUPPORTWSAEAFNOSUPPORT:本协议不支持所指定的地址族;本协议不支持所指定的地址族; WSAEINVALWSAEINVAL:该套接口已与一个地址捆绑;该套接口已与一个地址捆绑; WSAENOBUFSWSAENOBUFS:无足够可用缓冲区,连接过多;无足够可用缓冲区,连接过多; WSAENOTSOCKWSAENOTSOCK:指定的描述字不是一个套接口。指定的描述字不是一个套接口。4函数使用说明各种IP地址和端口的设置可用表6-2表示。 表6-2 IP地址和端口的几种设置方式在程序中使用在程序中使用bind()bind()调用的典型方式如下所示:调用的典型方式如下所

85、示:#include #include SOCKET SOCKET s; s;sockaddr_insockaddr_in tcpaddrtcpaddr; ;intint iSockErriSockErr; ;intint port=5000; port=5000;/ /端口号端口号/ /先创建一个使用先创建一个使用IPIP地址族的流式套接口地址族的流式套接口s=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);s=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);/ /以下给结构类型的地址提供数值以下给结构类型的地址提供数值tcpa

86、ddr.sin_familytcpaddr.sin_family=AF_INET;=AF_INET;/ /htonshtons()()函函数数把把一一个个1616位位主主机机字字节节顺顺序序的的端端口口号号转转化化为为网络字节顺序网络字节顺序tcpaddr.sin_porttcpaddr.sin_port= =htons(porthtons(port); ); / /htonshtons()()函函数数把把一一个个3232位位主主机机字字节节顺顺序序的的IPIP地地址址转转化化为为网络字节顺序网络字节顺序tcpaddr.sin_addr.s_addrtcpaddr.sin_addr.s_add

87、r= =htonl(INADDR_ANYhtonl(INADDR_ANY); );/ / tcpaddr.sin_addr.s_addrtcpaddr.sin_addr.s_addr= =inet_addr(“127.0.0.1inet_addr(“127.0.0.1”);”);struct sockaddr u_short sa_family; char sa_data14; ; struct in_addr union struct u_char s_b1,s_b2,s_b3,s_b4; S_un_b; struct u_short s_w1,s_w2; S_un_w; u_long S_

88、addr; S_un; ;几个结构:if(bind(s,(LPSOCKADDR)&tcpaddr,sizeof(tcpaddrif(bind(s,(LPSOCKADDR)&tcpaddr,sizeof(tcpaddr)=SOCKET_ERROR) )=SOCKET_ERROR) / /该函数的调用失败,进行错误处理该函数的调用失败,进行错误处理iSockErriSockErr= =WSAGetLastErrorWSAGetLastError();();/ /根据不同的错误类型进行输出提示信息根据不同的错误类型进行输出提示信息return;return; / /函数调用成功,进行其他处理函数调用

89、成功,进行其他处理n n该该程程序序段段是是使使用用bind()bind()调调用用常常用用的的形形式式,由由内内核核指指定定IPIP地地址址,应应用用程程序序指指定定端端口口号号。至至此此,通通信信过过程程中中一一端端的的协协议议、地地址址和和所所使使用用的的端端口口号号已已经经确确定定,一一个个套套接接口口就就可可以以正正常常使使用用了了,即即可可以以进进行行数数据据的的接接收收或或发送操作了。发送操作了。6.4.4 6.4.4 监听连接监听连接listen()listen()在在一一个个服服务务器器端端用用socket()socket()调调用用成成功功创创建建了了一一个个套套接接口口,

90、并并用用bind()bind()函函数数和和一一个个指指定定的的地地址址关关联联( (即即绑绑定定) )在在一一起起后后,要要指指示示该该套套接接口口进进入入监监听听连连接接请请求求的的状状态态以以及及接接收收由由客客户户发出的连接请求,就要用到发出的连接请求,就要用到Winsock APIWinsock API函数函数listen()listen()。1 1函数格式函数格式intint listen( listen( SOCKET s, SOCKET s, intint backlog backlog ); ); 2 2函数参数说明函数参数说明listen()listen()函数中各参数说明

91、如下:函数中各参数说明如下: s s:用用于于标标识识一一个个已已绑绑定定了了地地址址,但但还还未未建建立立连连接的套接口描述字。接的套接口描述字。 backlogbacklog:该该参参数数指指定定了了正正在在等等待待连连接接的的最最大大队队列列长长度度。这这个个参参数数非非常常重重要要, ,因因为为完完全全可可能能同同时时出出现现几几个个对对服服务务器器的的连连接接请请求求。例例如如,假假定定backlogbacklog参参数数为为2 2时时有有三三个个客客户户机机同同时时发发出出连连接接请请求求,那那么么前前两两个个会会被被放放在在一一个个“ “等等待待处处理理” ”队队列列中中,以以便

92、便应应用用程程序序依依次次为为它它们们提供服务。提供服务。第三个连接的请求会造成一个第三个连接的请求会造成一个WSAECONNREFUSEDWSAECONNREFUSED错错误。一旦服务器接受了一个连接请求,那个连接请求就误。一旦服务器接受了一个连接请求,那个连接请求就会从队列中删去,以便可以继续接收其他客户发出的连会从队列中删去,以便可以继续接收其他客户发出的连接请求。要注意的是,接请求。要注意的是,backlogbacklog参数本身的大小就存在着参数本身的大小就存在着限制(限制(SOMAXCONN SOMAXCONN ),这个限制是由协议提供者决定),这个限制是由协议提供者决定的。的。3

93、 3函数返回信息函数返回信息如如果果listen()listen()函函数数的的调调用用无无错错误误发发生生,则则返返回回值值为为0 0,否否 则则 返返 回回 SOCKET_ERRORSOCKET_ERROR错错 误误 , 应应 用用 程程 序序 可可 通通 过过WSAGetLastErrorWSAGetLastError()()获获取取相相应应的的错错误误代代码码。下下面面是是可可能能获获得的错误代码的说明:得的错误代码的说明: WSANOTINITIALISEDWSANOTINITIALISED:在在使使用用此此APIAPI之之前前应应成成功功调调用用WSAStartupWSAStart

94、up()(); WSAENETDOWNWSAENETDOWN:WindowsWindows套套接接口口实实现现检检测测到到网网络络子子系统失效;系统失效; WSAEADDRINUSEWSAEADDRINUSE:试试图图用用listen()listen()去去监监听听一一个个正正在在使使用中的地址;用中的地址; WSAEINPROGRESSWSAEINPROGRESS:一一个个阻阻塞塞的的WindowsWindows套套接接口口调调用用正在运行中;正在运行中; WSAEINVALWSAEINVAL:该该套套接接口口未未用用bind()bind()进进行行捆捆绑绑,或或已已被被连接;连接; WSA

95、EISCONNWSAEISCONN:套接口已被连接;套接口已被连接; WSAEMFILEWSAEMFILE:无可用文件描述字;无可用文件描述字; WSAENOBUFSWSAENOBUFS:无可用缓冲区空间;无可用缓冲区空间; WSAENOTSOCKWSAENOTSOCK:描述字不是一个套接口描述字不是一个套接口 WSAEOPNOTSUPPWSAEOPNOTSUPP:该该套套接接口口不不能能正正常常支支持持对对listen()listen()的的调用。调用。4 4函数使用说明函数使用说明listen()listen()仅仅 适适 用用 于于 支支 持持 连连 接接 的的 套套 接接 口口 , 如

96、如SOCK_STREAMSOCK_STREAM类类型型的的套套接接口口。也也就就是是说说,在在IPIP地地址址族族中中,它它只只适适用用于于同同时时有有多多个个连连接接请请求求的的TCPTCP服服务务器器。如如果果当当一一个个 连连 接接 请请 求求 到到 来来 时时 队队 列列 已已 满满 , 那那 么么 客客 户户 将将 收收 到到 一一 个个WSAECONNREFUSEDWSAECONNREFUSED错误。错误。6.4.5 6.4.5 请求连接请求连接connect()connect()或或WSAConnectWSAConnect()()当当服服务务器器端端建建立立好好套套接接口口并并与

97、与一一个个本本地地地地址址绑绑定定后后,就就进进入入监监听听状状态态,等等待待客客户户发发出出连连接接请请求求,从从而而为客户提供服务。为客户提供服务。在在 客客 户户 端端 当当 套套 接接 口口 建建 立立 好好 之之 后后 , 就就 要要 调调 用用connect()connect()函函数数,提提出出与与一一个个服服务务器器建建立立连连接接的的请请求求,如如果果服服务务器器接接受受请请求求,就就可可以以在在服服务务器器的的远远程程套套接接口口与客户端的本地套接口之间建立一条连接。与客户端的本地套接口之间建立一条连接。1 1函数格式函数格式在在Winsock 1Winsock 1中提供的

98、中提供的connect()connect()函数格式是:函数格式是:int connect(SOCKET s,SOCKET s,const const structstruct sockaddrsockaddr FAR* name, FAR* name,intint namelennamelen); );在在Winsock 2Winsock 2中提供的扩展格式是:中提供的扩展格式是: intint WSAConnectWSAConnect( (SOCKET s,SOCKET s,const const structstruct sockaddrsockaddr FAR* name, FAR*

99、name,intint namelennamelen, ,LPWSABUF LPWSABUF lpCallerDatalpCallerData, ,LPWSABUF LPWSABUF lpCalleeDatalpCalleeData, ,LPQOS LPQOS lpSQOSlpSQOS, ,LPQOS LPQOS lpGQOSlpGQOS); );它是它是Winsock 2Winsock 2对对connect()connect()函数的扩展版本,支持函数的扩展版本,支持连接数据交换和确定服务质量连接数据交换和确定服务质量(QOS)(QOS)。 2 2函数参数说明函数参数说明connect()c

100、onnect()函数中各参数说明如下:函数中各参数说明如下: s s:将要建立连接的套接口描述字。将要建立连接的套接口描述字。 namename: 是是 一一 个个 指指 向向 远远 端端 套套 接接 口口 地地 址址 结结 构构( (sockaddr_insockaddr_in) )的指针,表示的指针,表示s s套接口欲与其建立一条连接。套接口欲与其建立一条连接。 namelennamelen:namename名字的长度。名字的长度。Winsock Winsock 1 1中中提提供供的的请请求求建建立立连连接接函函数数的的格格式式和和Winsock Winsock 2 2提提供供的的扩扩展展

101、格格式式前前三三个个参参数数是是完完全全一一样样的的。Winsock Winsock 2 2中中后后四个参数的含义是:四个参数的含义是: lpCallerDatalpCallerData:指指向向用用户户数数据据缓缓冲冲区区的的一一个个指指针针,该该缓缓冲冲区区中中包包含含有有在在建建立立连连接接时时由由本本机机传传输输到到服服务务器器端端( (远远端端) )的的数据。数据。 lpCalleeDatalpCalleeData:指指向向另另一一个个用用户户数数据据缓缓冲冲区区的的指指针针,该该缓缓冲冲区区中中包包含含在在建建立立连连接接时时从从服服务务器器端端( (远远端端) )传传送送到到本本

102、机的数据。机的数据。以以 上上 两两 个个 参参 数数 都都 是是 WSABUFWSABUF结结 构构 型型 的的 指指 针针 ,WSABUFWSABUF是是一一种种在在Winsock Winsock 2 2中中很很常常用用的的结结构构,该该结结构构的的定义如下:定义如下:typedeftypedef structstruct _WSABUF _WSABUF intintlenlen; ;/ the length of the buffer/ the length of the bufferchar FAR *char FAR *bufbuf; ;/ the pointer to the bu

103、ffer/ the pointer to the bufferWSABUF, FAR* LPWSABUF;WSABUF, FAR* LPWSABUF;根根据据该该结结构构具具体体应应用用的的不不同同,lenlen字字段段要要么么指指定定由由bufbuf字字段段指指向向的的那那个个缓缓冲冲区区的的长长度度,要要么么指指定定包包含含在在数数据据缓缓冲冲区区bufbuf中中的的数数据据长长度度。在在该该函函数数中中lenlen字字段段显显然然表表示示缓缓冲冲区区的长度。的长度。 lpSQOSlpSQOS:是是一一个个指指向向服服务务质质量量(QOS)(QOS)结结构构的的指指针针,它它用用于于指指定

104、定流流式式套套接接口口s s需需要要的的服服务务质质量量,在在数数据据的的发发送送与与接接收收方方各各有有一一个个;若若为为空空值值,则则表表明明没没有有对对该该应应用用指指定定专用的专用的QOSQOS。 lpGQOSlpGQOS:也也是是一一个个指指向向服服务务质质量量(QOS)(QOS)结结构构的的指指针针,它它指指出出套套接接口口组组所所需需要要的的服服务务质质量量;目目前前,尚尚未未提提供供对对套套接字组的支持,因此该指针可设置为接字组的支持,因此该指针可设置为NULLNULL。这这两两个个参参数数都都是是QOSQOS型型的的指指针针,QOSQOS结结构构的的定定义义如下:如下:typ

105、edeftypedef structstruct _ _QualityOfServiceQualityOfService WSABUFWSABUFSendingFlowspecSendingFlowspec; / the flow spec for data sending; / the flow spec for data sendingWSABUFWSABUFReceivingFlowspecReceivingFlowspec; / the flow spec for data receiving; / the flow spec for data receiving QOS, FAR *

106、 LPQOS; QOS, FAR * LPQOS;3 3函数返回信息函数返回信息如如无无错错误误发发生生,connect()connect()和和WSAConnectWSAConnect()()都都返返回回0 0,否否则则 将将 返返 回回 INVALID_SOCKETINVALID_SOCKET错错 误误 , 应应 用用 程程 序序 可可 通通 过过WSAGetLastErrorWSAGetLastError()()获取相应错误代码。获取相应错误代码。 对于阻塞套接口来说,返回值表示连接试图是否成功。对于阻塞套接口来说,返回值表示连接试图是否成功。对对于于非非阻阻塞塞套套接接口口来来说说,连

107、连接接试试图图不不一一定定马马上上完完成成。在在这这 种种 情情 况况 下下 , WSAConnectWSAConnect()()返返 回回 SOCKET_ERRORSOCKET_ERROR, 且且WSAGetLastErrorWSAGetLastError()()返返回回WSAEWOULDBLOCKWSAEWOULDBLOCK,此此时时应应用用程程序序可可以以采采用用下下列列方方法法进进一一步步做做出出判判断断( (所所使使用用的的函函数数在在第第8 8章介绍章介绍) ): 利利用用select()select()函函数数,通通过过检检查查套套接接口口是是否否可可写写来来判判断断连接请求是否

108、完成;连接请求是否完成; 如如果果应应用用程程序序已已使使用用WSAAsyncSelectWSAAsyncSelect()()函函数数来来确确定定对对连连接接事事件件的的兴兴趣趣,则则当当连连接接操操作作完完成成时时应应用用程程序序将将收收到到FD_CONNECTFD_CONNECT通知;通知; 如如果果应应用用程程序序已已使使用用WSAEventSelectWSAEventSelect()()函函数数来来确确定定对对连连接接事事件件的的兴兴趣趣,则则当当连连接接操操作作完完成成时时相相应应的的事事件件对对象象将设置信号。将设置信号。对于一个非阻塞套接口来说,在连接试图完成之前,对于一个非阻塞

109、套接口来说,在连接试图完成之前,任何对该套接口的任何对该套接口的WSAConnectWSAConnect()()调用都将以调用都将以WSAEALREADYWSAEALREADY错误失败。错误失败。 如果返回值指出连接试图失败如果返回值指出连接试图失败( (例如例如WSAECONNREFUSEDWSAECONNREFUSED,WSAENETUNREACHWSAENETUNREACH,WSAETIMEDOUT)WSAETIMEDOUT),则应用程序可对该套接口再次调用则应用程序可对该套接口再次调用WSAConnectWSAConnect()()函数。函数。下面是由下面是由WSAGetLastErr

110、orWSAGetLastError()()获得的错误代码的说明:获得的错误代码的说明: WSANOTINITIALISEDWSANOTINITIALISED:在在调调用用本本APIAPI之之前前应应成成功功调调用用WSAStartupWSAStartup()(); WSAENETDOWNWSAENETDOWN:网络子系统失效;网络子系统失效; WSAEADDRINUSEWSAEADDRINUSE:所指地址已被使用;所指地址已被使用; WSAEINTRWSAEINTR:通通过过WSACancelBlockingCallWSACancelBlockingCall()()函函数数中中止了阻塞调用;止

111、了阻塞调用; WSAEINPROGRESSWSAEINPROGRESS:一一个个阻阻塞塞的的WinsockWinsock调调用用正在进行中,或者服务提供者仍在处理一个回调函数;正在进行中,或者服务提供者仍在处理一个回调函数; WSAEALREADYWSAEALREADY:在在所所指指定定的的套套接接口口上上正正在在进进行一个非阻塞的行一个非阻塞的connect()connect()或或WSAConnectWSAConnect()()调用;调用; WSAEADDRNOTAVAILWSAEADDRNOTAVAIL:本本地地机机器器上上所所指指定定的的地址不可用;地址不可用; WSAEAFNOSUP

112、PORTWSAEAFNOSUPPORT:所所指指定定地地址址族族中中的的地地址址无法与本套接口一起使用;无法与本套接口一起使用; WSAECONNREFUSEDWSAECONNREFUSED:连接试图被拒绝;连接试图被拒绝; WSAEFAULTWSAEFAULT:namename或或namelennamelen参参数数不不是是用用户户地地址址空空间间的的一一个个有有效效部部分分,namelennamelen参参数数太太小小,lpCalleeDatalpCalleeData、lpSQOSlpSQOS和和lpGQOSlpGQOS的缓冲区太小,或者的缓冲区太小,或者lpCallerDatalpCal

113、lerData的缓冲区太大;的缓冲区太大; WSAEINVALWSAEINVAL:套接口没有准备好与一地址捆绑;套接口没有准备好与一地址捆绑; WSAEISCONNWSAEISCONN:套套接接口口已已经经连连接接( (仅仅适适用用于于面面向向连连接接的的套接口套接口) ); WSAENETUNREACHWSAENETUNREACH:当前无法从本主机访问网络;当前无法从本主机访问网络; WSAENOBUFSWSAENOBUFS:无可用缓冲区,套接口未连接;无可用缓冲区,套接口未连接; WSAENOTSOCKWSAENOTSOCK:描述字不是一个套接口;描述字不是一个套接口; WSAEOPNOT

114、SUPPWSAEOPNOTSUPP:lpSQOSlpSQOS和和lpGQOSlpGQOS中中的的流流描描述述无法满足;无法满足; WSAEPROTONOSUPPORTWSAEPROTONOSUPPORT:服服务务提提供供者者不不支支持持lpCallerDatalpCallerData参数;参数; WSAETIMEDOUTWSAETIMEDOUT:超时时间到,连接未建立;超时时间到,连接未建立; WSAEDESTADDREQWSAEDESTADDREQ:需要目的地址;需要目的地址; WSAEWOULDBLOCKWSAEWOULDBLOCK:套套接接口口标标志志为为非非阻阻塞塞,连连接接无无法法立

115、立即即完完成成,当当套套接接口口用用select()select()函函数数设设置置为为写写时时,可可调用调用select()select()函数;函数; WSAEACCESWSAEACCES:由由于于未未使使用用setsockoptsetsockopt()()函函数数设设置置允允许许SO_BROADCASTSO_BROADCAST,无无法法将将一一个个数数据据报报套套接接口口与与一一个个广广播播地地址连接。址连接。4 4函数使用说明函数使用说明 在在客客户户端端使使用用该该函函数数请请求求建建立立连连接接时时,将将激激活活建建立立连连接接的的三三次次握握手手,用用来来建建立立一一条条与与服服

116、务务器器的的TCPTCP连连接接。如如果果在在调调用用该该函函数数前前没没有有调调用用bind()bind()来来绑绑定定本本地地地地址址,则则由由系系统统隐隐式式地地绑定一个地址到该套接口。绑定一个地址到该套接口。该该函函数数用用于于使使用用UDPUDP的的客客户户端端时时,connect()connect()函函数数并并不不是是真真正正地地发发出出建建立立连连接接的的请请求求,调调用用将将从从本本地地操操作作系系统统直直接接返返回。回。这这样样做做的的好好处处是是可可以以将将服服务务器器的的地地址址信信息息保保存存下下来来,在在后后续续UDPUDP端端口口上上发发送送数数据据时时,由由套套

117、接接口口自自动动在在发发送送函函数数中中填填入入服服务务器器地地址址信信息息,而而不不需需要要由由应应用用程程序序在在调调用用发发送送函函数数时时填入。填入。6.4.6 6.4.6 接受连接接受连接accept()accept()或或WSAAcceptWSAAccept()()在在服服务务器器端端通通过过listen()listen()函函数数调调用用表表示示服服务务器器进进入入监监听听客客户户的的连连接接请请求求状状态态,而而在在服服务务器器端端调调用用accept()accept()函函数数表表示示可可以以接接收收来来自自客客户户端端由由connect()connect()发发出出的的连连

118、接接请请求求,这这就就好好像像是是在在通通话话过过程程中中,被被叫叫方方听听到到电电话话铃铃声声后后提提起起话话筒筒,然然后后双双方方进进入通话状态。入通话状态。1 1函数格式函数格式在在Winsock 1Winsock 1中提供的中提供的accept()accept()函数的格式是:函数的格式是:SOCKET accept(SOCKET accept(SOCKET s,SOCKET s,structstruct sockaddrsockaddr FAR* FAR* addraddr, ,intint FAR* FAR* addrlenaddrlen); ); 在在Winsock 2Winso

119、ck 2中提供的中提供的accept()accept()函数的扩展格式是:函数的扩展格式是: SOCKET SOCKET WSAAcceptWSAAccept( (SOCKET s, SOCKET s, structstruct sockaddrsockaddr FAR * FAR * addraddr, , intint FAR * FAR * addrlenaddrlen, ,LPCONDITIONPROC LPCONDITIONPROC lpfnConditionlpfnCondition, ,DWORD DWORD dwCallbackDatadwCallbackData ); );该

120、该扩扩展展函函数数可可根根据据条条件件函函数数的的返返回回值值,有有条条件件地地接受连接,同时接受连接,同时( (可选地可选地) )创建和创建和/ /或加入一个套接口组。或加入一个套接口组。2 2函数参数说明函数参数说明accept()accept()函数的参数说明如下:函数的参数说明如下: s s:标标识识一一个个套套接接口口描描述述字字,该该套套接接口口处处于于监监听听连接的状态。连接的状态。 addraddr:是是一一个个地地址址结结构构的的指指针针, ,用用来来存存放放发发出出连连接接请请求求的的那那个个客客户户机机的的IPIP地地址址信信息息。addraddr参参数数的的实实际际格格

121、式由套接口创建时所使用的地址族确定。式由套接口创建时所使用的地址族确定。 addrlenaddrlen:该该参参数数指指出出客客户户套套接接口口地地址址结结构构的的长长度。度。以以上上三三个个参参数数在在Winsock Winsock 1 1和和Winsock Winsock 2 2扩扩展展版版本本中中是是完全一样的。完全一样的。Winsock 2Winsock 2中后两个参数的含义是:中后两个参数的含义是: lpfnConditionlpfnCondition:是是一一个个指指向向条条件件函函数数进进程程的的指指针针。这这个个函函数数是是根根据据客客户户的的请请求求来来调调用用的的,该该函函

122、数数决决定定是是否否接受客户的连接请求。它的定义如下:接受客户的连接请求。它的定义如下:intint CALLBACK CONDITIONPROC CALLBACK CONDITIONPROC( (LPWSABUF LPWSABUF lpCallerIdlpCallerId, /, /指出客户连接实体的地址指出客户连接实体的地址 LPWSABUF LPWSABUF lpCallerDatalpCallerData, /, /由客户在连接请求中发来的数据由客户在连接请求中发来的数据 LPQOS LPQOS lpSQOSlpSQOS, /, /指定一个客户连接请求的服务质量指定一个客户连接请求的服

123、务质量 LPQOS LPQOS lpGQOSlpGQOS, /, /指定套接口组的服务质量指定套接口组的服务质量 LPWSABUF LPWSABUF lpCalleeIdlpCalleeId, /, /指出本地连接实体的地址指出本地连接实体的地址 LPWSABUF LPWSABUF lpCalleeDatalpCalleeData, /, /建立连接时发给客户的数据建立连接时发给客户的数据 GROUP FAR * g, /GROUPGROUP FAR * g, /GROUP是一个无符号整型量,确定是一个无符号整型量,确定 / /一个组一个组DWORD DWORD dwCallbackDatad

124、wCallbackData / /返回的数据返回的数据); ); dwCallbackDatadwCallbackData:作作为为条条件件函函数数参参数数返返回回给给应应用用程序的回调数据,程序的回调数据,WinsockWinsock不分析该参数。不分析该参数。3 3函数返回信息函数返回信息如如无无错错误误发发生生,该该函函数数就就返返回回一一个个新新的的套套接接口口描描述述符符,它它对对应应于于已已经经接接受受的的那那个个客客户户机机的的连连接接。对对该该客客户户机机后后续续的的所所有有操操作作,都都使使用用这这个个新新的的套套接接口口描描述述符符,因因此此把把它它叫叫已已连连接接套套接接

125、口口(Connected (Connected Socket)Socket)描描述述符符。至至于于原原来来那那个个监监听听套套接接口口,它它仍仍然然用用于于接接收收其其他他客客户户机机发发送送的的连连接接请请求求,而而且且仍仍处处于于监监听听模模式式,因因此此把它叫监听套接口把它叫监听套接口(Listening Socket)(Listening Socket)描述符。描述符。如如果果发发生生错错误误,则则返返回回INVALID_SOCKETINVALID_SOCKET错错误误,应用程序可通过应用程序可通过WSAGetLastErrorWSAGetLastError()()获取相应错误代码。获

126、取相应错误代码。下面是由下面是由WSAGetLastErrorWSAGetLastError()()获得的错误代码的说明:获得的错误代码的说明: WSANOTINITIALISEDWSANOTINITIALISED:在在调调用用本本APIAPI之之前前应应成成功功调用调用WSAStartupWSAStartup()(); WSAECONNREFUSEDWSAECONNREFUSED:根根据据条条件件函函数数的的返返回回值值(CF_REJECT)(CF_REJECT)强制拒绝连接请求;强制拒绝连接请求; WSAENETDOWNWSAENETDOWN:套套接接口口实实现现检检测测到到网网络络子子系

127、系统统失效;失效; WSAEFAULTWSAEFAULT:addrlenaddrlen参参数数太太小小( (小小于于sockaddrsockaddr结结构构的大小的大小) ),或者,或者lpfnConditionlpfnCondition并不是用户空间的一部分;并不是用户空间的一部分; WSAEINTRWSAEINTR:通过通过accept()accept()或或WSACancelBlockingCallWSACancelBlockingCall()()函数取消函数取消( (阻塞阻塞) )调用;调用; WSAEINPROGRESSWSAEINPROGRESS:一一个个阻阻塞塞WinsockWi

128、nsock调调用用正正在进行。在进行。 WSAEINVALWSAEINVAL:accept()accept()或或WSAAcceptWSAAccept()()调调用用前前未未执执行行listen()listen()调调用用,条条件件函函数数中中的的g g参参数数非非法法,条条件件函函数的返回值非法,套接口处于非法状态;数的返回值非法,套接口处于非法状态; WSAEMFILEWSAEMFILE:accept()accept()或或WSAAcceptWSAAccept()()调调用用时时排队队列非空,且无可用套接口描述字;排队队列非空,且无可用套接口描述字; WSAENOBUFSWSAENOBUF

129、S:无可用缓冲区空间;无可用缓冲区空间; WSAENOTSOCKWSAENOTSOCK:描述字不是一个套接口;描述字不是一个套接口; WSAEOPNOTSUPPWSAEOPNOTSUPP:所所引引用用的的套套接接口口不不是是支支持持面面向连接服务类型的;向连接服务类型的; WSATRY_AGAINWSATRY_AGAIN: 根根 据据 条条 件件 函函 数数 的的 返返 回回 值值(CF_DEFER)(CF_DEFER),连接请求被推迟;连接请求被推迟; WSAEWOULDBLOCKWSAEWOULDBLOCK:套套接接口口标标志志为为非非阻阻塞,无连接请求供接受;塞,无连接请求供接受; WS

130、AEACCESWSAEACCES:被推迟的连接请求超时或撤销。被推迟的连接请求超时或撤销。4 4函数使用说明函数使用说明该函数用于面向连接的服务器端,在该函数用于面向连接的服务器端,在IPIP协议族中,只协议族中,只用于用于TCPTCP服务器端。服务器端。 服务器程序实例#include void main(void) WSADATA wsaData; SOCKET ListeningSocket; SOCKET NewConnection; SOCKADDR_IN ServerAddr;SOCKADDR_IN ClientAddr;int Port = 5150; / Initialize

131、Winsock version 2.2 WSAStartup(MAKEWORD(2,2), &wsaData);ListeningSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); ServerAddr.sin_family = AF_INET; ServerAddr.sin_port = htons(Port); ServerAddr.sin_addr.s_addr = htonl(INADDR_ANY); bind(ListeningSocket, (SOCKADDR *)&ServerAddr, sizeof(ServerAddr);

132、listen(ListeningSocket, 5); int ClientAddrLen = sizeof(ClientAddr);NewConnection = accept(ListeningSocket, (SOCKADDR *) &ClientAddr,&ClientAddrLen); closesocket(NewConnection); closesocket(ListeningSocket); WSACleanup(); 客户机程序实例#include void main(void) WSADATA wsaData; SOCKET s; SOCKADDR_IN ServerAd

133、dr; int Port = 5150; WSAStartup(MAKEWORD(2,2), &wsaData); s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); ServerAddr.sin_family = AF_INET; ServerAddr.sin_port = htons(Port); ServerAddr.sin_addr.s_addr = inet_addr(136.149.3.29); connect(s, (SOCKADDR *) &ServerAddr, sizeof(ServerAddr); closesocket(s);

134、WSACleanup(); 6.5 Winsock API基本函数数据传输6.5.1 6.5.1 带外数据的概念带外数据的概念 有有时时我我们们可可能能要要传传输输一一些些相相对对来来说说比比较较重重要要的的数数据据,如如果果按按普普通通数数据据进进行行传传送送,那那么么在在传传输输过过程程中中要要受受流量、拥挤等控制的影响。流量、拥挤等控制的影响。对对于于带带外外数数据据,从从逻逻辑辑上上看看,好好像像用用户户进进程程使使用用了了一一个个独独立立的的通通道道发发送送这这些些带带外外数数据据,位位于于连连接接另另一一端端的的应应用用进进程程可可通通过过一一个个独独立立的的逻逻辑辑信信道道来来接

135、接收收和和处处理理带带外外数数据据。这这样样对对于于标标记记成成带带外外数数据据的的数数据据流流,在在传传输输时时就就可减少传输系统对数据的干预。可减少传输系统对数据的干预。在在TCPTCP协协议议中中,OOBOOB数数据据由由一一个个紧紧急急位位(URG)(URG)和和TCPTCP段段头头中中的的一一个个1616位位的的紧紧急急数数据据指指针针标标记记,把把指指定定的的数数据据流流当当作作紧紧急数据来处理。急数据来处理。 在在WinsockWinsock中中,要要查查看看待待发发数数据据中中是是否否包包含含紧紧急急数数据据,必必须须通通过过SIOCATMARKSIOCATMARK选选项项调调

136、用用ioctlsocketioctlsocket函函数数来来实实现现。WinsockWinsock提提供供了了获获得得紧紧急急数数据据的的方方法法:一一是是紧紧急急数数据据一一旦旦在在线线插插入入,它它就就会会出出现现在在普普通通数数据据流流中中;二二是是可可以以关关闭闭在在线线插插入入,这这样样,不不连连续续调调用用接接收收函函数数就就会会只只返返回回紧紧急急数数据据。控控制制OOBOOB数据行为的套接口选项是数据行为的套接口选项是SO_OOBINLINE(SO_OOBINLINE(见见8.48.4节节) )。不不同同的的系系统统对对带带外外数数据据可可能能有有不不同同的的解解释释,所所以以

137、用用户户在在编编写写应应用用程程序序时时为为了了增增强强程程序序的的通通用用性性,应应该该尽尽量量不不用用带带外外数据。数据。6.5.2 6.5.2 在在已已建建立立连连接接的的套套接接口口上上发发送送数数据据send()send()或或WSASendWSASend()()在在已已经经建建立立连连接接的的套套接接口口上上发发送送数数据据,可可以以使使用用send()send()或或WSASendWSASend()()函数。函数。1 1函数格式函数格式 send()send()函数在函数在Winsock 1Winsock 1中提供的格式是:中提供的格式是: intint send( send(

138、SOCKET s, SOCKET s, const char FAR* const char FAR* bufbuf, , intint lenlen, , intint flags flags ); );在Winsock 2中提供的WSASend()函数的扩展格式是: int WSASend( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount, LPDWORD lpNumberOfBytesSent, DWORD dwFlags, LPWSAOVERLAPPED lpOverlapped, LPWSAOVERLAPPED_COMPLETION

139、_ROUTINE lpCompletionRoutine );2 2函数参数说明函数参数说明send()send()函数中函数中4 4个参数的含义是:个参数的含义是: s s:用于标识已建立连接的套接口描述字。用于标识已建立连接的套接口描述字。 bufbuf:它是一个字符缓冲区,内有将要发送的数据。它是一个字符缓冲区,内有将要发送的数据。 lenlen:即将发送的缓冲区中的字符数即将发送的缓冲区中的字符数。 flagsflags:用用于于控控制制数数据据传传输输方方式式,它它可可以以是是0 0、宏宏定定义义MSG_DONTROUTEMSG_DONTROUTE或或MSG_OOBMSG_OOB。0

140、 0表表示示按按正正常常方方式式发发送送数数据据;MSG_DONTROUTEMSG_DONTROUTE标标志志说说明明系系统统目目标标主主机机就就在在直直接接连连接接的的本本地地网网络络中中,无无需需路路由由选选择择,但但如如果果传传输输协协议议的的实实现现不不支支持持该该选选项项,则则该该标标志志被被忽忽略略;MSG_OOBMSG_OOB标标志志指指出数据是按带外数据发送的。出数据是按带外数据发送的。在在Winsock Winsock 2 2中中,WSASendWSASend()()函函数数的的第第一一个个参参数数s s和和第第五五个参数个参数dwFlagsdwFlags与与send()se

141、nd()函数一样。其他参数的含义如下:函数一样。其他参数的含义如下:lpBufferslpBuffers:一一个个指指向向WSABUFWSABUF结结构构数数组组的的指指针针。每每个个WSABUFWSABUF结结构构包包含含缓缓冲冲区区的的指指针针和和缓缓冲冲区区的的大大小小。在在一一个个已已建建立立连连接接的的套套接接口口上上利利用用多多缓缓冲冲来来发发送送数数据据时时,顺顺序序是是从从第第一个到最后一个一个到最后一个WSABUFWSABUF结构。结构。dwBufferCountdwBufferCount:lpBufferslpBuffers数组中数组中WSABUFWSABUF结构的数目。结

142、构的数目。 lpNumberOfBytesSentlpNumberOfBytesSent:如如果果发发送送操操作作立立即即完完成成,则则为为一一个个指向所发送数据字节数的指针。指向所发送数据字节数的指针。 lpOverlappedlpOverlapped:指指向向WSAOVERLAPPEDWSAOVERLAPPED结结构构的的指指针针( (用于重叠套接口,见第用于重叠套接口,见第8 8章章) )。lpCompletionRoutinelpCompletionRoutine:一一个个指指向向发发送送操操作作完完成成后后调调用的完成例程的指针用的完成例程的指针( (用于重叠套接口用于重叠套接口)

143、)。3 3函数返回信息函数返回信息若若无无错错误误发发生生,send()send()函函数数和和WSASendWSASend()()函函数数都都返返回回 所所 发发 送送 数数 据据 的的 字字 节节 数数 , 连连 接接 结结 束束 , 函函 数数 返返 回回0(WSASend0(WSASend()) )。在在发发生生错错误误的的情情况况下下,函函数数返返回回SOCKET_ERRORSOCKET_ERROR错错误误,应应用用程程序序可可通通过过WSAGetLastErrorWSAGetLastError() ()获获取取相相应应错错误误代代码码。下下面面是是可可获获取取的的各各种种错错误误代

144、代码码的的含义:含义: WSANOTINITIALISEDWSANOTINITIALISED:在在使使用用此此APIAPI之之前前应应成成功调用功调用WSAStartupWSAStartup()(); WSAENETDOWNWSAENETDOWN:WindowsWindows套套接接口口实实现现检检测测到到网络子系统失效;网络子系统失效; WSAEACESSWSAEACESS:要要求求地地址址为为广广播播地地址址,但但相相关关标志未能正确设置;标志未能正确设置; WSAEINTRWSAEINTR:通过一通过一WSACancelBlockingCallWSACancelBlockingCall(

145、)()来取消一个来取消一个( (阻塞的阻塞的) )调用;调用; WSAEINPROGRESSWSAEINPROGRESS:一一个个阻阻塞塞的的WindowsWindows套套接接口调用正在运行中;口调用正在运行中; WSAEFAULTWSAEFAULT:bufbuf或或lpBuffer(WSASendlpBuffer(WSASend) )参参数数不不在用户地址空间中的有效位置;在用户地址空间中的有效位置; WSAENETRESETWSAENETRESET:由由于于WindowsWindows套套接接口口实实现现放放弃了连接,故该连接必须被复位;弃了连接,故该连接必须被复位; WSAENOBUF

146、SWSAENOBUFS:WindowsWindows套套接接口口实实现现报报告告一一个个缓冲区死锁;缓冲区死锁; WSAENOTCONNWSAENOTCONN:套接口未被连接;套接口未被连接; WSAENOTSOCKWSAENOTSOCK:描述字不是一个套接口;描述字不是一个套接口; WSAEOPNOTSUPPWSAEOPNOTSUPP:已已设设置置了了MSG_OOBMSG_OOB,但但套套接接口非口非SOCK_STREAMSOCK_STREAM类型;类型; WSAESHUTDOWNWSAESHUTDOWN:套套接接口口已已被被关关闭闭,一一个个套套接接口口以以1 1或或2(WSASend2(

147、WSASend:对对一一个个套套接接口口以以SD_SENDSD_SEND或或SD_BOTH)SD_BOTH)的的howhow参数调用参数调用shutdown()shutdown()关闭后,无法再用关闭后,无法再用send()send()函数;函数; WSAEWOULDBLOCKWSAEWOULDBLOCK:太多的重叠输入太多的重叠输入/ /输出操作;输出操作; WSAEMSGSIZEWSAEMSGSIZE:套套接接口口为为SOCK_DGRAMSOCK_DGRAM类类型型,且且数据报大于数据报大于WindowsWindows套接口实现所支持的最大值;套接口实现所支持的最大值; WSAEINVAL

148、WSAEINVAL:套套接接口口未未用用bind()bind()捆捆绑绑,或或者者套套接口未用重叠标志位创建;接口未用重叠标志位创建; WSAECONNABORTEDWSAECONNABORTED:由由于于超超时时或或其其他他原原因因引起虚电路的中断;引起虚电路的中断; WSAECONNRESETWSAECONNRESET:虚电路被远端复位;虚电路被远端复位; WSA_IO_PENDINGWSA_IO_PENDING:成成功功启启动动重重叠叠操操作作,过过后后将有完成指示;将有完成指示; WSA_OPERATION_ABORTEDWSA_OPERATION_ABORTED:重重叠叠操操作作由由

149、于于套套接接口口的的关关闭闭而而被被取取消消,或或者者在在WSAIoctlWSAIoctl()()调调用用中中执执行了行了SIO_FLUSHSIO_FLUSH。4 4函数使用说明函数使用说明send()send()适适用用于于已已建建立立连连接接的的数数据据报报或或流流式式套套接接口口发发送数据。送数据。对对于于数数据据报报类类套套接接口口,必必须须注注意意发发送送数数据据长长度度不不应应超超 过过 通通 信信 子子 网网 的的 IPIP包包 最最 大大 长长 度度 。 IPIP包包 最最 大大 长长 度度 在在WSAStartupWSAStartup()()调调用用返返回回的的WSAData

150、WSAData结结构构量量的的iMaxUdpDgiMaxUdpDg元元素素中中(WinSock (WinSock 2 2 忽忽略略,参参见见 msdnmsdn) )。如如果果数数据据太太长长无无法法自自动动通通过过下下层层协协议议,则则返返回回WSAEMSGSIZEWSAEMSGSIZE错错误误,数数据不会被发送。据不会被发送。请请注注意意,成成功功地地完完成成send()send()调调用用并并不不意意味味着着数数据据已已可靠传送到目标。可靠传送到目标。如如果果传传送送系系统统的的缓缓冲冲区区空空间间不不够够保保存存需需传传送送的的数数据据,除除非非套套接接口口处处于于非非阻阻塞塞I/OI/

151、O方方式式,否否则则send()send()将将阻阻塞塞。对对于于非非阻阻塞塞SOCK_STREAMSOCK_STREAM类类型型的的套套接接口口,实实际际写写的的数数据据数数目目可可能能在在1 1到到所所需需大大小小之之间间,其其值值取取决决于于本本地地和和远远端端主主机机的的缓缓冲冲区区大大小小。可可用用select()select()调调用用来来确确定定何何时时能能够够进进一一步发送数据。步发送数据。在在相相关关套套接接口口的的选选项项之之上上,还还可可通通过过标标志志位位flagflag来来影影响响函函数数的的执执行行方方式式。也也就就是是说说,本本函函数数的的语语义义既既取取决决于于

152、套接口的选项,又取决于标志位。套接口的选项,又取决于标志位。6.5.3 在已建立连接的套接口上接收数据recv()或WSARecv()对对于于已已建建立立连连接接的的套套接接口口来来说说,要要从从套套接接口口上上接接收收数数据,就要使用据,就要使用recvrecv()()函数或函数或WSARecvWSARecv()()。1 1函数格式函数格式 在在Winsock 1Winsock 1中提供的中提供的recvrecv()()函数的格式是:函数的格式是: intint recvrecv( ( SOCKET s,SOCKET s, char FAR* char FAR* bufbuf, , inti

153、nt lenlen, , intint flags flags); ); 在Winsock 2中提供的WSARecv()函数扩展格式是: int WSARecv( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount, LPDWORD lpNumberOfBytesRecvd, LPINT lpFlags, LPWSAOVERLAPPED lpOverlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine );2 2函数参数说明函数参数说明recvrecv()()函数中各参数说明

154、如下:函数中各参数说明如下: s s:已建立连接的套接口描述字。已建立连接的套接口描述字。 bufbuf:用于接收数据的缓冲区。用于接收数据的缓冲区。 lenlen:缓冲区长度缓冲区长度。 flagsflags:指指定定调调用用方方式式。flagsflags参参数数可可以以是是下下面面的的值值:0 0、 MSG_PEEKMSG_PEEK或或MSG_OOBMSG_OOB。0 0表表示示接接收收的的是是正正常常数数据据,无无特特殊殊行行为为。MSG_PEEKMSG_PEEK表表示示会会使使有有用用的的数数据据复复制制到到所所提提供供的的接接收收端端缓缓冲冲区区内内,但但是是没没有有从从系系统统缓缓

155、冲冲区中将数据删除。区中将数据删除。但但要要注注意意,把把数数据据留留在在系系统统缓缓冲冲区区中中,则则系系统统缓缓冲冲区区中中可可容容纳纳的的接接收收数数据据的的系系统统空空间间就就会会越越来来越越少少,其其结结果果是是系系统统减减少少各各发发送送端端的的TCPTCP窗窗口口的的容容量量,用用户户的的应应用用程程序序就就不不能能获获得得最最大大的的数数据据流流通通量量,因因此此,最最好好把把所所有有数数据据都都复复制制到到自自己己的的缓缓冲冲区区中中,并并在在那那里里处处理理数数据据。MSG_OOBMSG_OOB标标志志表表示示处处理理带外数据。带外数据。WSARecvWSARecv()()

156、函函数数在在recvrecv()()函函数数的的基基础础上上新新增增加加了了一一些些特特性,比如重叠性,比如重叠I/OI/O和部分数据报通知。它的参数含义如下:和部分数据报通知。它的参数含义如下: s s:已建立连接的套接口描述字。已建立连接的套接口描述字。 lpBufferslpBuffers:一一个个指指向向WSABUFWSABUF结结构构数数组组的的指指针针。每每一一个个WSABUFWSABUF结构包含一个缓冲区的指针和缓冲区的长度。结构包含一个缓冲区的指针和缓冲区的长度。 dwBufferCountdwBufferCount:lpBufferslpBuffers数组中数组中WSABUF

157、WSABUF结构的数目。结构的数目。 lpNumberOfBytesRecvdlpNumberOfBytesRecvd:如如果果接接收收操操作作立立即即结结束束,一一个指向本调用所接收的字节数的指针。个指向本调用所接收的字节数的指针。 lpFlagslpFlags:一个指向标志位的指针。一个指向标志位的指针。 lpOverlappedlpOverlapped:一一个个指指向向WSAOVERLAPPEDWSAOVERLAPPED结结构构的的指指针针( (对于非重叠套接口则忽略对于非重叠套接口则忽略) )。 lpCompletionRoutinelpCompletionRoutine:一一个个指指

158、向向接接收收操操作作结结束束后后调调用用的例程的指针的例程的指针( (对于非重叠套接口则忽略对于非重叠套接口则忽略) )。 3 3函数返回信息函数返回信息在在无无错错误误发发生生时时,这这两两个个函函数数都都返返回回所所接接收收的的字字节节数数,函函数数在在连连接接结结束束时时返返回回0 0。如如果果发发生生错错误误,则则函函数数返返回回SOCKET_ERRORSOCKET_ERROR错错误误信信息息,应应用用程程序序可可通通过过WSAGetLastErrorWSAGetLastError()()获获取取相相应应错错误误代代码码。下下面面是是可可获获取取的各种错误代码的含义:的各种错误代码的含

159、义: WSANOTINITIALISEDWSANOTINITIALISED:在在调调用用本本APIAPI之之前前应应成成功调用功调用WSAStartupWSAStartup()(); WSAENETDOWNWSAENETDOWN:网络子系统失效;网络子系统失效; WSAENOTCONNWSAENOTCONN:套接口未连接;套接口未连接; WSAEINTRWSAEINTR:通通过过WSACancelBlockingCallWSACancelBlockingCall()()函函数取消数取消( (阻塞阻塞) )调用;调用; WSAEINPROGRESSWSAEINPROGRESS:一一个个阻阻塞塞的

160、的WinsockWinsock调调用用正在进行中,或者服务提供者仍在处理一个回调函数;正在进行中,或者服务提供者仍在处理一个回调函数; WSAENETRESETWSAENETRESET:由由于于远远端端的的复复位位造造成成连连接接的的中止;中止; WSAENOTSOCKWSAENOTSOCK:描述字不是一个套接口;描述字不是一个套接口; WSAEOPNOTSUPPWSAEOPNOTSUPP:设置了设置了MSG_OOB,MSG_OOB,但是但是该套接口不是该套接口不是SOCK_STREAMSOCK_STREAM流类型的,与套接口相流类型的,与套接口相关的通信域不支持带外数据,或者套接口是单向的,

161、关的通信域不支持带外数据,或者套接口是单向的,只支持发送操作;只支持发送操作; WSAESHUTDOWNWSAESHUTDOWN:套套接接口口已已经经关关闭闭;一一个个套套接接口口以以 SD_RECEIVE(0)SD_RECEIVE(0)或或 SD_BOTH(2)SD_BOTH(2)的的 howhow参参 数数 调调 用用shutdown()shutdown()后后,就就再再无无法法进进行行WSARecvWSARecv()()或或recvrecv()()函函数数的的调调用了;用了; WSAEWOULDBLOCKWSAEWOULDBLOCK:对对于于重重叠叠套套接接口口来来说说, ,有有太太多多

162、重重叠叠的的输输入入/ /输输出出请请求求,对对于于非非重重叠叠套套接接口口来来说说,套套接接口口被标志为非阻塞,但是操作不能立即完成;被标志为非阻塞,但是操作不能立即完成; WSAEINVALWSAEINVAL:套套接接口口未未用用bind()bind()捆捆绑绑,或或者者套套接接口口未用重叠标志创建;未用重叠标志创建; WSAECONNABORTEDWSAECONNABORTED:由由于于超超时时或或其其他他错错误误导导致致虚虚电路中止;电路中止; WSAECONNRESETWSAECONNRESET:虚电路被远端复位;虚电路被远端复位; WSAEDISCONWSAEDISCON:远端远端

163、“ “优雅优雅” ”地结束了连接;地结束了连接; WSA_IO_PENDINGWSA_IO_PENDING:成成功功启启动动一一个个重重叠叠操操作作,过过后将有完成指示;后将有完成指示; WSAEMSGSIZEWSAEMSGSIZE:数数据据报报太太大大无无法法全全部部装装入入缓缓冲冲区,故被剪切。区,故被剪切。4 4函数使用说明函数使用说明本本函函数数用用于于在在已已建建立立连连接接的的数数据据报报或或流流式式套套接接口口s s上进行数据的接收。上进行数据的接收。对对SOCK_STREAMSOCK_STREAM类类型型的的套套接接口口来来说说,本本函函数数将将返返回回所所有有可可用用的的信信

164、息息,最最大大可可达达缓缓冲冲区区的的大大小小。如如果果套套 接接 口口 被被 设设 置置 为为 在在 线线 接接 收收 带带 外外 数数 据据 ( (选选 项项 为为SO_OOBINLINE)SO_OOBINLINE),且且有有带带外外数数据据未未读读入入,则则返返回回带带外外数数 据据 。 应应 用用 程程 序序 可可 通通 过过 调调 用用 ioctlsocketioctlsocket()()的的SIOCATMARKSIOCATMARK命令来确定是否有带外数据待读入。命令来确定是否有带外数据待读入。对对于于数数据据报报类类套套接接口口,队队列列中中第第一一个个数数据据报报中中的的数数据据

165、被被解解包包,但但最最多多不不超超过过缓缓冲冲区区的的大大小小。如如果果数数据据报报大大于于缓缓冲冲区区,那那么么缓缓冲冲区区中中只只有有数数据据报报的的前前面面部部分分,其其他他的的数数据据都都丢丢失失了了,并并且且recvrecv()()函函数数返返回回WSAEMSGSIZEWSAEMSGSIZE错错误。误。对对于于流流式式套套接接口口,不不会会碰碰到到WSAEMSGSIZEWSAEMSGSIZE这这个个错错误误。如如果果没没有有数数据据待待读读,在在阻阻塞塞模模式式下下,套套接接口口将将一一直直等等 待待 数数 据据 的的 到到 来来 。 在在 非非 阻阻 塞塞 模模 式式 下下 , 将

166、将 返返 回回SOCKET_ERRORSOCKET_ERROR错错误误,错错误误代代码码是是WSAEWOULDBLOCKWSAEWOULDBLOCK。用用select()select()或或WSAAsynSelectWSAAsynSelect()()可以获知数据何时到达。可以获知数据何时到达。如如果果套套接接口口为为SOCK_STREAMSOCK_STREAM类类型型,并并且且远远端端“ “优优雅雅” ”地地中中止止了了连连接接,那那么么recvrecv()()一一个个数数据据也也不不读读取取,立立即即返返回回。如如果果连连接接被被强强制制中中止止,那那么么recvrecv()()将将以以WS

167、AECONNRESETWSAECONNRESET错错误误失失败败返返回回。在在套套接接口口所所设设的的选选项项之之上上,还还可可用用标标志志位位flagflag来来影影响响函函数数的的执执行行方方式式。也也就就是是说说,本本函函数数的的语语义义既既取取决决于于套套接接口口选选项项,也也取取决决于标志位参数。于标志位参数。如果有大量数据涌入接收端,滑动窗口大小会被设置为0,此时不能再发送数据,因此,可能无法一次将所有字节发送出去,要将所有字节发送出去,必须重传剩余字节。char sendbuff2048; int nBytes = 2048, nLeft, idx; nLeft = nBytes

168、; idx = 0; while (nLeft 0) ret = send(s, &sendbuffidx, nLeft, 0); if (ret = SOCKET_ERROR) / Error nLeft - = ret; idx += ret; 发送流示例发送流示例接收流示例接收流示例如果消息长度一样,则比较容易处理。如果消息长度不同,则应用自己的协议通知接收端即将到来的消息长度是多少。char recvbuff1024; int ret, nLeft, idx; nLeft = 512; idx = 0; while (nLeft 0) ret = recv(s, &recvbuffid

169、x, nLeft, 0); if (ret = SOCKET_ERROR) / Error idx += ret; nLeft -= ret; 6.5.4 在无连接的套接口上接收数据recvfrom()或WSARecvFrom()对对于于无无连连接接的的套套接接口口来来说说,要要从从套套接接口口上上接接收收一一个个 数数 据据 报报 并并 保保 存存 发发 送送 数数 据据 的的 源源 地地 址址 , 就就 要要 使使 用用recvfromrecvfrom()()函数或函数或WSARecvfromWSARecvfrom()()函数。函数。1 1函数格式函数格式在在Winsock 1Winsoc

170、k 1中提供的中提供的recvfromrecvfrom()()函数的格式是:函数的格式是:intint recvfromrecvfrom( (SOCKET s,SOCKET s, char FAR* char FAR* bufbuf, ,intint lenlen, ,intint flags, flags,structstruct sockaddrsockaddr FAR* from, FAR* from,intint FAR* FAR* fromlenfromlen); );在在Winsock 2Winsock 2中提供的中提供的WSARecvFromWSARecvFrom()()函数的扩

171、展格式是:函数的扩展格式是:intint WSARecvFromWSARecvFrom( (SOCKET s,SOCKET s,LPWSABUF LPWSABUF lpBufferslpBuffers, ,DWORD DWORD dwBufferCountdwBufferCount, ,LPDWORD LPDWORD lpNumberOfBytesRecvdlpNumberOfBytesRecvd, ,LPINT LPINT lpFlagslpFlags, ,LPVOID LPVOID lpFromlpFrom, ,LPINT LPINT lpFromlenlpFromlen, ,LPWSAO

172、VERLAPPED LPWSAOVERLAPPED lpOverlappedlpOverlapped, ,LPWSAOVERLAPPED_COMPLETION_ROUTINELPWSAOVERLAPPED_COMPLETION_ROUTINElpCompletionRoutinelpCompletionRoutine ); );2 2函数参数说明函数参数说明recvfromrecvfrom()()函数中各参数说明如下:函数中各参数说明如下: s s:标识一个套接口的描述字;标识一个套接口的描述字; bufbuf:接收数据缓冲区;接收数据缓冲区; lenlen:缓冲区长度;缓冲区长度; flag

173、sflags:调用操作方式,同调用操作方式,同recvrecv()()中的中的flagsflags; fromfrom:( (可可选选) )指指针针,指指向向装装有有源源地地址址的的缓缓冲冲区区,对对监监听听 套套 接接 字字 的的 具具 体体 协协 议议 来来 说说 , fromfrom参参 数数 是是 一一 个个 指指 向向SOCKADDRSOCKADDR结结构构的的指指针针,它它的的长长度度由由指指针针fromlenfromlen指指向向的的数数确确定定,这这个个APIAPI调调用用返返回回数数据据时时,SOCKADDRSOCKADDR结结构构内内便便填填入发送数据的那个工作站的地址;入

174、发送数据的那个工作站的地址; fromlenfromlen:( (可选可选) )指针,指向指针,指向fromfrom缓冲区长度值;缓冲区长度值; WSARecvFromWSARecvFrom()()函数参数的含义如下:函数参数的含义如下: s s:一个标识套接口的描述字;一个标识套接口的描述字; lpBufferslpBuffers:一一个个指指向向WSABUFWSABUF结结构构数数组组的的指指针针,每每个个WSABUFWSABUF结构包含缓冲区的指针和缓冲区的大小;结构包含缓冲区的指针和缓冲区的大小; dwBufferCountdwBufferCount:lpBufferslpBuffer

175、s数数组组中中WSABUFWSABUF结结构构的的数数目;目; lpNumberOfBytesRecvdlpNumberOfBytesRecvd:如如果果接接收收操操作作立立即即完完成成,则为一个指向所接收数据字节数的指针;则为一个指向所接收数据字节数的指针; lpFlagslpFlags:一个指向标志位的指针;一个指向标志位的指针; lpFromlpFrom:( (可可选选) )指指针针,指指向向重重叠叠操操作作完完成成后后存存放放源源地址的缓冲区;地址的缓冲区; lpFromlenlpFromlen:指指向向fromfrom缓缓冲冲区区大大小小的的指指针针,仅仅当当指指定定了了lpFrom

176、lpFrom时才需要;时才需要; lpOverlappedlpOverlapped:指指向向WSAOVERLAPPEDWSAOVERLAPPED结结构构的的指指针针( (对于非重叠套接口则忽略对于非重叠套接口则忽略) ); lpCompletionRoutinelpCompletionRoutine:一一个个指指向向接接收收操操作作完完成成后后调调用的完成例程的指针用的完成例程的指针( (对于非重叠套接口则忽略对于非重叠套接口则忽略) )。3 3函数返回信息函数返回信息在在无无错错误误发发生生时时,这这两两个个函函数数都都返返回回所所接接收收的的字字节节数数,函函数数在在连连接接结结束束时时返

177、返回回0 0;否否则则返返回回SOCKET_ERRORSOCKET_ERROR错错误误,应应用用程程序序可可通通过过WSAGetLastErrorWSAGetLastError()()获获取取相相应应错错误误代代码码。可可获取的各错误代码的含义如下:获取的各错误代码的含义如下: WSANOTINITIALISEDWSANOTINITIALISED:在在调调用用本本APIAPI之之前前应应成成功功调调用用WSAStartupWSAStartup()(); WSAENETDOWNWSAENETDOWN:网络子系统失效;网络子系统失效; WSAEFAULTWSAEFAULT:lpFromlenlpF

178、romlen参参数数非非法法,lpFromlpFrom缓缓冲冲区区太太小小,无无法法容容纳纳远远端端地地址址( (对对recvfromrecvfrom()()来来说说,fromlenfromlen参参数数非非法,法,fromfrom缓冲区大小无法装入端地址缓冲区大小无法装入端地址) ); WSAEINTRWSAEINTR:通通过过WSACancelBlockingCallWSACancelBlockingCall()()函函数数取消取消( (阻塞阻塞) )调用;调用; WSAEINPROGRESSWSAEINPROGRESS:一一个个阻阻塞塞的的WinsockWinsock调调用用正正在进行中

179、,或者服务提供者仍在处理一个回调函数;在进行中,或者服务提供者仍在处理一个回调函数; WSAEINVALWSAEINVAL:套套接接口口未未用用bind()bind()捆捆绑绑,或或者者套套接接口未用重叠标志创建;口未用重叠标志创建; WSAENETRESETWSAENETRESET:由由于于远远端端的的复复位位造造成成连连接接中中止;止; WSAENOTCONNWSAENOTCONN:套套接接口口未未连连接接( (仅仅适适用用于于面面向向连接的套接口连接的套接口) ); WSAENOTSOCKWSAENOTSOCK:描述字不是一个套接口;描述字不是一个套接口; WSAEOPNOTSUPPWS

180、AEOPNOTSUPP:设置了设置了MSG_OOB,MSG_OOB,但是该套但是该套接口不是接口不是SOCK_STREAMSOCK_STREAM流类型的,与套接口相关的通信流类型的,与套接口相关的通信域不支持带外数据,或者套接口是单向的,只支持发送操域不支持带外数据,或者套接口是单向的,只支持发送操作;作; WSAESHUTDOWNWSAESHUTDOWN:套套接接口口已已经经关关闭闭,一一个个套套接接口口以以SD_RECEIVESD_RECEIVE或或SD_BOTH(SD_BOTH(对对recvfromrecvfrom()()来来说说,0 0或或2)2)的的howhow参参数数调调用用shu

181、tdown()shutdown()后后,就就无无法法进进行行WSARecvFromWSARecvFrom()()调用了;调用了; WSAEWOULDBLOCKWSAEWOULDBLOCK:对对于于重重叠叠套套接接口口来来说说, ,有有太太多多重重叠叠的的输输入入/ /输输出出请请求求,对对于于非非重重叠叠套套接接口口来来说说,套套接接口被标志为非阻塞,但是操作不能立即完成。口被标志为非阻塞,但是操作不能立即完成。 WSAEMSGSIZEWSAEMSGSIZE:消消息息太太大大无无法法全全部部装装入入指指定定的的缓缓冲区,故被修剪;冲区,故被修剪; WSAECONNABORTEDWSAECONN

182、ABORTED:由由于于超超时时或或其其他他错错误误导导致致虚电路中止;虚电路中止; WSAECONNRESETWSAECONNRESET:虚电路被远端复位;虚电路被远端复位; WSAEDISCONWSAEDISCON:远端远端“ “优雅优雅” ”地中止了连接;地中止了连接; WSA_IO_PENDINGWSA_IO_PENDING:成成功功启启动动一一个个重重叠叠操操作作,过过后后将有完成指示;将有完成指示; WSA_OPERATION_ABORTEDWSA_OPERATION_ABORTED:由由于于套套接接口口的的关关闭闭,重叠操作已经被取消。重叠操作已经被取消。4 4函数使用说明函数使

183、用说明该该函函数数的的用用法法与与有有连连接接时时recvrecv()()或或WSARecvWSARecv()()函函数数的的用用法法类类似似,要要注注意意的的是是该该函函数数也也可可以以用用于于有有连连接接时时数据的接收。数据的接收。 接收端实例接收端实例#include void main(void) WSADATA wsaData; SOCKET ReceivingSocket; SOCKADDR_IN ReceiverAddr; int Port = 5150; char ReceiveBuf1024; int BufLength = 1024; SOCKADDR_IN SenderA

184、ddr; int SenderAddrSize = sizeof(SenderAddr); WSAStartup(MAKEWORD(2,2), &wsaData); ReceivingSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); ReceiverAddr.sin_family = AF_INET; ReceiverAddr.sin_port = htons(Port); ReceiverAddr.sin_addr.s_addr = htonl(INADDR_ANY); bind(ReceivingSocket, (SOCKADDR *)&

185、ReceiverAddr, sizeof(ReceiverAddr); recvfrom(ReceivingSocket, ReceiveBuf, BufLength, 0, (SOCKADDR *)&SenderAddr, &SenderAddrSize); closesocket(ReceivingSocket); WSACleanup(); 6.5.5 在无连接的套接口上发送数据sendto()或WSASendTo() 对于无连接的套接口来说,要从套接口上发送一个数据报,就要使用sendto()函数或WSASendTo()函数。1 1函数格式函数格式在在Winsock 1Winsock

186、1中提供的中提供的sendtosendto()()函数的格式是:函数的格式是:intint sendtosendto( (SOCKET s,SOCKET s,const char FAR* const char FAR* bufbuf, ,intint lenlen, ,intint flags, flags,const const structstruct sockaddrsockaddr FAR* to, FAR* to,intint tolentolen); );在在Winsock 2Winsock 2中提供的中提供的WSASendToWSASendTo()()函数的扩展格式是:函数的扩

187、展格式是: intint WSASendToWSASendTo( (SOCKET s,SOCKET s,LPWSABUF LPWSABUF lpBufferslpBuffers, ,DWORD DWORD dwBufferCountdwBufferCount, ,LPDWORD LPDWORD lpNumberOfBytesSentlpNumberOfBytesSent, ,intint iFlagsiFlags, ,LPVOID LPVOID lpTolpTo, ,intint iToLeniToLen, ,LPWSAOVERLAPPED LPWSAOVERLAPPED lpOverlapp

188、edlpOverlapped, ,LPWSAOVERLAPPED_COMPLETION_ROUTINE LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutinelpCompletionRoutine ); );2 2函数参数说明函数参数说明sendtosendto()()函数中各参数的说明如下:函数中各参数的说明如下: s s:一个标识套接口的描述字;一个标识套接口的描述字; bufbuf:待发送数据的缓冲区;待发送数据的缓冲区; lenlen:指明指明bufbuf缓冲区中要发送的数据长度;缓冲区中要发送的数据长度; flagsflags:调

189、调用用方方式式标标志志位位,同同send()send()中中该该参参数数的的含含义相同;义相同; toto:( (可可选选) )指指针针,指指向向接接收收数数据据的的目目的的套套接接口口的的地址;地址; tolentolen:toto所指地址的长度。所指地址的长度。WSASendToWSASendTo()()函数中各参数的含义如下:函数中各参数的含义如下: s s:用用于于标标识识一一个个已已连连接接的的套套接接口口,该该套套接接口口以以WSA_FLAG_OVERLAPPEDWSA_FLAG_OVERLAPPED标标志志调调用用WSASocketWSASocket()()函函数;数; lpBu

190、fferslpBuffers:一一个个指指向向WSABUFWSABUF结结构构数数组组的的指指针针,每个每个WSABUFWSABUF结构包含缓冲区的指针和缓冲区的大小;结构包含缓冲区的指针和缓冲区的大小; dwBufferCountdwBufferCount:lpBufferslpBuffers数数组组中中WSABUFWSABUF结结构构的数目;的数目; lpNumberOfBytesSentlpNumberOfBytesSent:如如果果发发送送操操作作立立即即完完成成,则为一个指向所发送数据字节数的指针;则为一个指向所发送数据字节数的指针; iFlagsiFlags:标志位;标志位; lp

191、TolpTo:( (可选可选) )指针,指向目标套接口的地址;指针,指向目标套接口的地址; lpTolenlpTolen:lpTolpTo中地址的大小;中地址的大小; lpOverlappedlpOverlapped:指指向向WSAOVERLAPPEDWSAOVERLAPPED结结构构的的指针指针( (对于非重叠套接口则忽略对于非重叠套接口则忽略) )。 lpCompletionRoutinelpCompletionRoutine:一一个个指指向向发发送送操操作作完完成成后后调用的完成例程的指针调用的完成例程的指针( (对于非重叠套接口则忽略对于非重叠套接口则忽略) )。3 3函数返回信息函数

192、返回信息在在无无错错误误发发生生时时,这这两两个个函函数数都都返返回回所所发发送送的的字字节节数数 , 函函 数数 在在 连连 接接 结结 束束 时时 返返 回回 0 0; 否否 则则 返返 回回SOCKET_ERRORSOCKET_ERROR错错 误误 , 应应 用用 程程 序序 可可 通通 过过WSAGetLastErrorWSAGetLastError()()获获取取相相应应错错误误代代码码。可可获获取取的的错错误误代码的含义说明如下:代码的含义说明如下: WSANOTINITIALISEDWSANOTINITIALISED:在在调调用用本本APIAPI之之前前应应成成功调用功调用WSA

193、StartupWSAStartup()(); WSAENETDOWNWSAENETDOWN:网络子系统失效;网络子系统失效; WSAEACCESWSAEACCES:请请求求的的地地址址为为广广播播地地址址,但但未未设设置相应的标志位;置相应的标志位; WSAEINTRWSAEINTR:通通过过WSACancelBlockingCallWSACancelBlockingCall()()函函数数取消取消( (阻塞阻塞) )调用。调用。 WSAEINPROGRESSWSAEINPROGRESS:一一个个阻阻塞塞的的WinsockWinsock调调用用正正在进行中,或者服务提供者仍在处理一个回调函数;

194、在进行中,或者服务提供者仍在处理一个回调函数; WSAEFAULTWSAEFAULT:lpBufferlpBuffer或或lpTolpTo参参数数不不是是用用户户地地址址空空间间的的一一部部分分,或或者者lpTolpTo参参数数太太小小( (小小于于sockaddrsockaddr结结构构的的大大小小) ); WSAENETRESETWSAENETRESET:远端主机复位造成连接中止;远端主机复位造成连接中止; WSAENOBUFSWSAENOBUFS:WinsockWinsock提提供供者者报报告告了了一一个个缓缓冲冲区区死锁;死锁; WSAENOTCONNWSAENOTCONN:套套接接口

195、口未未连连接接( (仅仅适适用用于于面面向连接的套接口向连接的套接口) ); WSAENOTSOCKWSAENOTSOCK:描述字不是一个套接口;描述字不是一个套接口; WSAEOPNOTSUPPWSAEOPNOTSUPP:设设置置了了MSG_OOBMSG_OOB,但但是是该该套套接接口口不不是是SOCK_STREAMSOCK_STREAM流流类类型型的的,与与套套接接口口相相关关的的通通信信域域不不支支持持带带外外数数据据,或或者者套套接接口口是是单单向向的的,只支持接收操作;只支持接收操作; WSAESHUTDOWNWSAESHUTDOWN:套套接接口口已已经经关关闭闭,一一个个套套接接

196、口口 以以 SD_SENDSD_SEND或或 SD_BOTHSD_BOTH的的 howhow参参 数数 调调 用用shutdown()shutdown()后,就无法进行后,就无法进行WSASendToWSASendTo()()调用了;调用了; WSAEWOULDBLOCKWSAEWOULDBLOCK:套套接接口口被被标标志志为为非非阻阻塞塞,但该调用会产生阻塞,有太多重叠的输入但该调用会产生阻塞,有太多重叠的输入/ /输出请求;输出请求; WSAEMSGSIZEWSAEMSGSIZE:套套接接口口是是面面向向消消息息的的,且且消消息息大大于底层传送所支持的最大长度;于底层传送所支持的最大长度;

197、 WSAEINVALWSAEINVAL:套套接接口口未未用用bind()bind()捆捆绑绑,或或者者套套接接口口未用重叠标志位创建;未用重叠标志位创建; WSAECONNABORTEDWSAECONNABORTED:由由于于超超时时或或其其他他错错误误导导致致虚电路中止;虚电路中止; WSAECONNRESETWSAECONNRESET:虚电路被远端复位;虚电路被远端复位; WSAEADDRNOTAVAILWSAEADDRNOTAVAIL:本地主机无法获取所指定本地主机无法获取所指定的地址;的地址; WSAEAFNOSUPPORTWSAEAFNOSUPPORT:指指定定地地址址族族中中的的地

198、地址址无无法法与本套接口一起使用;与本套接口一起使用; WSAEDESTADDRREQWSAEDESTADDRREQ:需要目标地址;需要目标地址; WSAENETUNREACHWSAENETUNREACH:当当前前无无法法从从本本主主机机联联系系网网络;络; WSA_IO_PENDINGWSA_IO_PENDING:成成功功启启动动一一个个重重叠叠操操作作,过过后将有完成指示;后将有完成指示; WSA_OPERATION_ABORTEDWSA_OPERATION_ABORTED:重重叠叠操操作作由由于于套套接接口口的的关关闭闭而而被被取取消消,或或者者在在WSAIoctlWSAIoctl()(

199、)调调用用中中执执行行了了SIO_FLUSHSIO_FLUSH。4 4函数使用说明函数使用说明这两个函数的使用方法类似于这两个函数的使用方法类似于send()send()和和WSASendWSASend()()函数。当用于无连接的套接口时,调函数。当用于无连接的套接口时,调用函数之前要设置,用函数之前要设置,指出目标指出目标指出目标指出目标IPIP地址和目标端口地址和目标端口地址和目标端口地址和目标端口号号号号。如果用于有连接的套接口时,则不能指定目。如果用于有连接的套接口时,则不能指定目标地址和端口,应将标地址和端口,应将toto设置为空,地址长度设置设置为空,地址长度设置为为0 0。当然在

200、有连接的情况下很少使用该函数。当然在有连接的情况下很少使用该函数。 发送端实例发送端实例#include void main(void) WSADATA wsaData; SOCKET SendingSocket; SOCKADDR_IN ReceiverAddr; int Port = 5150; char SendBuf1024; int BufLength = 1024;WSAStartup(MAKEWORD(2,2), &wsaData); SendingSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); ReceiverAddr.si

201、n_family = AF_INET; ReceiverAddr.sin_port = htons(Port); ReceiverAddr.sin_addr.s_addr = inet_addr(136.149.3.29); sendto(SendingSocket, SendBuf, BufLength, 0, (SOCKADDR *)&ReceiverAddr, sizeof(RecieverAddr); closesocket(SendingSocket); WSACleanup(); 6.6 Winsock API基本函数基本函数连接与套接连接与套接口的关闭口的关闭 6.6.1 6.6

202、.1 关闭读写通道关闭读写通道shutdown()shutdown()在在一一个个套套接接口口上上的的读读写写操操作作完完成成后后,应应该该首首先先使使用用shutdown()shutdown()函函数数来来关关闭闭套套接接口口的的读读通通道道、写写通通道道或或读读写写通通道道。这这样样做做的的好好处处是是当当通通信信的的双双方方不不再再有有数数据据要要发发送送或或接接收收时时,它它可可以以通通知知对对方方,以以防防止止数数据据丢丢失失,并并能能“ “优优雅雅” ”地关闭连接。地关闭连接。1 1函数格式函数格式 shutdown()shutdown()函数的格式如下:函数的格式如下: inti

203、nt shutdown( shutdown( SOCKET s, SOCKET s, intint how how ); ); 2 2函数参数说明函数参数说明 shutdown()shutdown()函数中各参数说明如下:函数中各参数说明如下: s s:标识一个套接口的描述字;标识一个套接口的描述字; howhow:标标志志,用用于于描描述述禁禁止止哪哪些些操操作作,howhow参参数数可可以以取取表表6-36-3所示的任何一个值。所示的任何一个值。 表6-3 读写关闭方式选择 3. 3. 函数返回信息函数返回信息如如果果没没有有错错误误发发生生,shutdown()shutdown()返返回

204、回0 0;否否则则返返回回SOCKET_ERRORSOCKET_ERROR错错 误误 , 应应 用用 程程 序序 可可 通通 过过WSAGetLastErrorWSAGetLastError()()获获取取相相应应错错误误代代码码。错错误误代代码码说说明明如下:如下: WSANOTINITIALISEDWSANOTINITIALISED:在在使使用用此此APIAPI之之前前应应成成功调用功调用WSAStartupWSAStartup()(); WSAENETDOWNWSAENETDOWN:WindowsWindows套套接接口口实实现现检检测测到到网络子系统失效;网络子系统失效; WSAEIN

205、VALWSAEINVAL:howhow参数非法;参数非法; WSAEINPROGRESSWSAEINPROGRESS:一一个个阻阻塞塞的的WindowsWindows套套接接口调用正在运行中;口调用正在运行中; WSAENOTCONNWSAENOTCONN:套套接接口口未未连连接接( (仅仅适适用用于于SOCK_STREAMSOCK_STREAM类型的套接口类型的套接口) ); WSAENOTSOCKWSAENOTSOCK:描述字不是一个套接口。描述字不是一个套接口。4 4函数使用说明函数使用说明请请注注意意,shutdown()shutdown()函函数数并并不不关关闭闭套套接接口口,且且套

206、套接接口所占有的资源将被一直保持到口所占有的资源将被一直保持到closesocketclosesocket()()调用之前。调用之前。6.6.2 6.6.2 关闭套接口关闭套接口closesocketclosesocket()()一一个个套套接接口口不不再再使使用用时时一一定定要要关关闭闭这这个个套套接接口口,以以释释放放与该套接口关联的所有资源,包括等候处理的数据。与该套接口关联的所有资源,包括等候处理的数据。1. 1. 函数格式函数格式closesocketclosesocket()()函数的格式如下:函数的格式如下:intint closesocketclosesocket( (SOCK

207、ET sSOCKET s); );2 2函数参数说明函数参数说明closesocketclosesocket()()函数中的参数函数中的参数s s标识一个将被关闭的套接口。标识一个将被关闭的套接口。 3 3函数返回信息函数返回信息如如果果没没有有错错误误发发生生,closesocketclosesocket()()返返回回0 0;否否则则返返回回 SOCKET_ERRORSOCKET_ERROR错错 误误 , 应应 用用 程程 序序 可可 通通 过过WSAGetLastErrorWSAGetLastError()()获获取取相相应应错错误误代代码码。错错误误代代码码说说明明如下:如下: WSA

208、NOTINITIALISEDWSANOTINITIALISED:在在使使用用此此APIAPI之之前前应应首首先成功调用先成功调用WSAStartupWSAStartup()(); WSAENETDOWNWSAENETDOWN:WindowsWindows套套接接口口实实现现检检测测到到网络子系统失效;网络子系统失效; WSAEINPROGRESSWSAEINPROGRESS:一一个个阻阻塞塞的的WindowsWindows套套接接口调用正在运行中;口调用正在运行中; WSAEINTRWSAEINTR:通过一个通过一个WSACancelBlockingCallWSACancelBlockingC

209、all()()来来取消一个取消一个( (阻塞的阻塞的) )调用;调用; WSAENOTSOCKWSAENOTSOCK:描述字不是一个套接口;描述字不是一个套接口; WSAEWOULDBLOCKWSAEWOULDBLOCK:该套接口设置为非阻塞方该套接口设置为非阻塞方式且式且SO_LINGERSO_LINGER设置为非零超时间隔。设置为非零超时间隔。 4 4函数使用说明函数使用说明对对一一个个有有连连接接的的TCPTCP来来说说,closesocketclosesocket()()调调用用还还要要关关闭闭TCPTCP连接。连接。使使用用closesocketclosesocket()()函函数数

210、关关闭闭一一个个连连接接时时,如如果果在在套套接接口口的的数数据据队队列列中中还还有有未未发发送送的的数数据据,对对这这些些数数据据的的处处理理方方式式要要受受套套接接口口选选项项SO_LINGERSO_LINGER和和SO_DONTLINGERSO_DONTLINGER的的影影响响,有关这方面的详细内容将在有关这方面的详细内容将在8.48.4节介绍。节介绍。6.6.3 终止使用WinsockWSACleanup()当在应用程序中不再使用当在应用程序中不再使用Winsock APIWinsock API中的任何函数中的任何函数时,必须调用时,必须调用WSACleanupWSACleanup()

211、()将其从将其从Windows SocketsWindows Sockets的实的实现中注销,以释放为应用程序或现中注销,以释放为应用程序或DLLDLL分配的任何资源。因分配的任何资源。因此,对应于一个任务进行的每一次此,对应于一个任务进行的每一次WSAStartupWSAStartup()()调用,必调用,必须有一个须有一个WSACleanupWSACleanup()()调用,因为每次调用,因为每次WSAStartupWSAStartup()()函函数的启动调用都会增加对加载数的启动调用都会增加对加载Winsock DLLWinsock DLL的引用次数,的引用次数,它要求调用同样多次的它要

212、求调用同样多次的WSACleanupWSACleanup()()调用,以此抵消引调用,以此抵消引用次数。用次数。 1 1函数格式函数格式WSACleannpWSACleannp()()函数的格式为函数的格式为intint WSACleanupWSACleanup (void); (void);2 2函数参数说明函数参数说明该函数是一个无参函数。该函数是一个无参函数。3 3函数返回信息函数返回信息该该函函数数调调用用成成功功返返回回0 0。调调用用失失败败时时,返返回回的的错错误误信信息息有下面几类:有下面几类: WSANOTINITIALISEDWSANOTINITIALISED:使使用用本本

213、APIAPI前前必必须须要要进进行行一一次成功的次成功的WSAStartupWSAStartup()()调用;调用; WSAENETDOWNWSAENETDOWN:Windows Windows SocketsSockets的的实实现现已已经检测到网络子系统故障;经检测到网络子系统故障; WSAEINPROGRESSWSAEINPROGRESS: 一一 个个 阻阻 塞塞 的的 Windows Windows SocketsSockets操作正在进行。操作正在进行。Winsock Winsock APIAPI函函 数数 调调 用用 的的 错错 误误 信信 息息 可可 以以 用用WSAGetLas

214、tErrorWSAGetLastError()()函函数数来来检检查查( (在在Unix Unix SocketSocket中中是是存存入入errnoerrno变量中的变量中的) )。4 4函数使用说明函数使用说明WSACleanupWSACleanup()()函函数数是是任任何何一一个个WinsockWinsock应应用用程程序序在在最最后后必必须须要要调调用用的的函函数数。在在一一个个多多线线程程的的环环境境下下,WSACleanupWSACleanup()()函函数数中中止止了了Windows Windows SocketsSockets在在所所有有线线程程上的操作。上的操作。只有在一次

215、成功调用只有在一次成功调用WSAStartupWSAStartup()()函数后,才能函数后,才能调用调用WSACleanupWSACleanup()()函数,否则,函数,否则,WSACleanupWSACleanup()()函数函数返回返回WSANOTINITIALISEDWSANOTINITIALISED错误信息。错误信息。 习题1下载并安装一个NetXRay软件,学习它的操作使用方法,总结它有哪些功能。2根据截获的数据包说明TCP/IP协议的四个协议层是怎样联系的?3说明应用层数据是如何被封装传输的? 4根据截获的数据包说明IP和TCP协议头信息各字段的含义。5说明TCP连接的建立和关闭是如何进行的?6应用层的命令和响应是如何被传输的?

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

最新文档


当前位置:首页 > 高等教育 > 研究生课件

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