网络编程技术最新编辑_第1页
网络编程技术最新编辑_第2页
网络编程技术最新编辑_第3页
网络编程技术最新编辑_第4页
网络编程技术最新编辑_第5页
已阅读5页,还剩21页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、Windows网络编程Microsoft技术丛书目录第1章 NetBIOS2第2章 重定向器5第3章 邮槽7第4章 命名管道9第5章 网络原理和协议15第6章 地址家族和名字解析21第7章 WinSock基础28第8章 WinSock I/O方法41第9章 套接字选项和I/O控制命令71第11章 多播81第1章 NetBIOSNetBIOSNetwork Basic Input/Output System,网络基本输入输出系统。1.1 Microsoft NetBIOS两个NetBIOS应用要通过网络进行正常通信,各自运行的机器至少安装一种两者通用的协议。NetBEUI是一种不可路由协议。但T

2、CP/IP和IPX/SPX均属可路由协议。1.1.1 LANA编号每个LANA编号对应于网卡及传输协议的唯一组合。LANA编号的范围通常在0到9之间,除LANA 0代表默认LANA之外,操作系统并不按某种固定的顺序来分配这些编号。1.1.2 NetBIOS名字一个NetBIOS名字长度为16个字符。针对每个LANA能够添加的名字的最大数量是254(编号从1到254,0和255由系统保留)。NetBIOS名字共有两种类型:唯一名字和组名。1.1.3 NetBIOS特性NetBIOS提供了“面向连接”与“无连接”服务。面向连接(面向会话)的服务允许两个客户机相互间建立一个会话 一种双向的通信数据流

3、。面向连接的服务可确保两个端点之间的任何数据都能准确无误地顺序传送。“无连接”(数据报)服务中,事前不必先建立任何连接。数据报服务既不能保证数据传输的可靠性,也不能保证数据包的传送顺序正确无误,但节省了建立连接所需的开销。1.2 NetBIOS编程基础UCHAR Netbios(PNCB pNCB );用于NetBIOS的所有函数声明、常数等均在头文件nb30.h内定义。需要连接的库是netapi32.lib。pNCB对应于指向某个网络控制块(NCB)的指针。typedef struct _NCB UCHAR ncb_command; UCHAR ncb_retcode; UCHAR ncb_

4、lsn; UCHAR ncb_num; PUCHAR ncb_buffer; WORD ncb_length; UCHAR ncb_callnameNCBNAMSZ; UCHAR ncb_nameNCBNAMSZ; UCHAR ncb_rto; UCHAR ncb_sto; void(*ncb_post)(struct _NCB *); UCHAR ncb_lana_num; UCHAR ncb_cmd_cplt; UCHAR ncb_reserve10; HANDLE ncb_event; NCB;进行任何Netbios调用之前,应先将这个NCB结构清零!ncb_command:指定命令编码

5、以及表明NCB结构体是否被异步处理的标识。ncb_retcodef:指定命令的返回编码。ncb_lsn:表示本地会话编号,在指定环境中此编号唯一标识一个会话。ncb_num:指定本地网络名字编号。ncb_buffer:指定消息缓冲区。(有发送信息、接收信息、接收请求状态信息三个缓冲区)。ncb_length:指定消息缓冲区的大小(字节)。ncb_callname:指定远程端应用程序的名字。ncb_name:指定应用程序可以识别的名字。ncb_rto:指定会话执行接收操作的超时时间。ncb_sto:设定发送操作的超时期限。该值应设为500毫秒的一个整数倍数。若为0,表示不存在超时限制。该值是为N

6、CBCALL和NCBLISTEN命令设置的,它们会影响后续的NCBSEND和NCBCHAINSEND命令。ncb_post:指定异步命令完成后需要调用的后例程的地址。函数定义为:void CALLBACKPostRoutine(PNCBpncb);其中,pncb指向已完成命令的网络控制块。ncb_lana_num:指定LANA编号。ncb_cmd_cpl:指定命令完成标识。ncb_reserve:保留字段,必须为0。ncb_event:指向事件对象的句柄。调用Netbios函数既可同步调用也可异步调用。要异步调用命令,需要让NetBIOS命令同ASYNCH标志进行逻辑或运算。如果指定了ASYN

7、CH标志,就必须在ncb_post字段中指定一个后例程(Post Routine),或必须在ncb_event字段中指定一个事件句柄。1.3 常规NetBIOS例程在程序清单1-1中,LanaEnum函数列举指定系统上可用的LANA编号。第二个函数是ResetAll。重设只要求函数将ncb_command设为NCBRESET,并将ncb_lana_num 设为它需要重设的LANA。AddName函数的作用是将名字加入本地名字表。AddGroupName的工作原理与AddName大致相同,但执行的命令则是NCBADDGRNAME。DelName函数用于从名字表中删除一个NetBIOS名字。Sen

8、d与Recv函数用于数据的收发。ncb_command可设为NCBSEND或NCBRECV。Send和Recv还需要映射到ncb_buffer和ncb_length的参数。函数Hangup和Cancel分别用于关闭已经建立的会话或取消一个尚未进行的命令。可调用NetBIOS命令NCBHANGUP来从容地关闭一个建立的会话。1.3.1 会话服务器:异步回调模型程序清单1-2展示了服务器代码,利用了异步回调函数。首先用LanaEnum列举所有可用的LANA编号,然后用ResetAll重设每个LANA。服务器将自己的进程名TEST-SERVER-1增加到每个LANA编号。服务器最关键的步骤是执行大量

9、NCBLISTEN命令。在程序清单1-2中,Listen函数会将ncb_post 字段设成回调函数。Listen函数将把ncb_name字段设为服务器进程的名字。1.3.2 会话服务器:异步事件模型事件模型更有效率。事件模型服务器程序最开头的几步与回调服务器一致:1) 列举LANA编号。2) 重设每个LANA。3) 为每个LANA增加服务器的名字。4) 为每个LANA投放一个监听命令。1.3.3 NetBIOS会话客户机程序清单1-4展示了客户机程序使用的源代码。客户机首先采取一系列初始化步骤,为每个LANA编号的名字表增添自己的名字,然后执行一个异步连接命令。主循环等候某个事件进入传信状态。

10、随后,代码遍历与执行连接命令对应的所有NCB结构。它检查ncb_cmd_cplt的状态,如发现它设为NRC_PENDING(待决),代码就会取消异步命令;若命令完成,但NCB并不与传信的那个NCB相符,代码便会断开连接。如果服务器正在对每个LANA进行监听扫描,同时客户机正在尝试在其每个LANA上建立连接,那么就可能出现成功建立多个连接的情况。此时,代码会用NCBHANGUP命令关掉多余的连接。1.4 数据报的工作原理“数据报”(Datagram)属于“无连接”通信。发送方只需用目标NetBIOS名字为发出的每个包定址。发送数据报有三种方式: 让数据报抵达一个唯一名。 将数据报发至一个组名。

11、将数据报广播到整个网络。用NCBDGSEND命令将数据报发给一个唯一名或一个组名;广播要用NCBDGSENDBC命令。 将ncb_num字段设为从NCBADDNAME 或NCBADDGRNAME命令返回的名字编号。 将ncb_buffer设为包含了需要发出数据的缓冲区的地址,将ncb_lana_num字段设为一个特定的LANA编号。 将ncb_callname设为目标NetBIOS名字(唯一名或组名)。(发送广播数据报无此步骤)当数据报抵达了某个客户机,但该客户机没有处在“待决”状态的接收命令,数据被抛弃,客户机也没有办法恢复未接收的数据。这正是数据报通信最大的缺点。但与面向连接相比,数据报的

12、传送速度要快得多,因为没有错误检查、连接设置之类的开销。数据报的接收也有三种方法。头两种方法要用到NCBDGRECV命令。可用NCBDGRECVBC命令接收广播数据报。1.5 其他NetBIOS命令适配器状态命令 NCBASTAT查找名字命令 NCBFINDNAME第2章 重定向器I/O重定向:通过网络访问某一设备,I/O请求必须通过网络转发给对应的远程设备。在Windows中可将一个本地磁盘标识符映射或重定向到远程计算机上的一个目录。应用程序要访问映射盘时,操作系统便将I/O请求自动重定向至一个设备,该设备叫作“重定向器”。2.1 通用命名规范服务器共享名路径例:MyServerMyShar

13、eSample.mp32.2 多UNC提供者MUP是一种资源定位器,负责选择具体的网络提供者以满足UNC连接请求。MUP需要通过网络提供者,在以UNC名字为基础的文件及打印机I/O请求上提供服务。2.3 网络提供者网络提供者是一种服务,通过网络硬件来访问位于远程计算机上的共享资源。2.4 重定向器简介“重定向器”需要格式化服务请求消息,再将其发给远程计算机的重定向器服务器服务。远程机器的重定向器服务器服务收到这个请求之后,会以本地I/O请求的方式满足这一请求。2.5 服务器消息块在SMB数据结构中,包含三个基本组件:命令代码、命令特有的以及用户数据。2.6 安全问题Windows对像文件和目录

14、这样的资源提供了本地和远程访问控制的能力。若应用程序试图访问这些资源,操作系统便会检查该程序,看它是否有“访问权限”。访问权限分为几种,最基本的包括读、写以及执行。Windows是通过“安全描述符”以及“访问令牌”实现访问控制的。2.6.1 安全描述符在安全描述符内包含了一个SECURITY_DESCRIPTOR结构,以及对应的安全信息: 所有人安全标识符(Security Identifier,SID) 组SID 授权访问控制列表(Discretionary Access Control List,DACL) 系统访问控制列表(System Access Control List,SACL)

15、2.6.2 访问令牌用户登录WinNT系统成功,系统就会创建相应的访问令牌,并将该用户的SID分配给它。2.7 网络安全MSNP重定向器负责不同计算机之间的资源访问,通过创建用户会话凭据的形式,在客户机与服务器之间建立一条安全通信链路。2.8 一个实例使用MSNP重定向器,通过网络,Win32应用程序可分别使用CreateFile、ReadFile和WriteFile函数创建、访问以及修改文件。第3章 邮槽通过邮槽,客户机进程可将消息传送或广播给一个或多个服务器进程。邮槽最大的缺点是只允许从客户机到服务器建立单向数据通信。邮槽最大的优点是它使客户机应用能够非常容易地将广播消息发送给一个或多个服

16、务器应用。3.1 邮槽实施细节邮槽是围绕Windows文件系统接口设计出来的。邮槽必须依赖Windows重定向器,通过“邮槽文件系统”(Mailslot File System, MSFS)创建及标识邮槽。3.1.1 邮槽的名字邮槽的命名规则:ServerMailslotpathname服务器字符串部分可表示成一个小数点(.)、一个星号(*)、一个域名或一个服务器名字。邮槽通过网络与计算机进行远程通信时,Windows 文件系统服务依赖Windows重定向器,使用“服务器消息块”(SMB)协议,将数据从客户机传给服务器。3.1.2 消息的长度表3-1 邮槽消息的长度限制传输方向通过数据报进行“

17、无连接”传输进行“面向连接”的传输Win9x è Win9x消息长度高达64KB不支持WinNT或Win2000 è WinNT或Win2000消息长度必须424字节消息长度必须>426个字节WinNT或Win2000 è Win9x消息长度必须424字节不支持Win9x è WinNT或Win2000消息长度必须424;多余的会被截去不支持3.1.3 应用程序的编译包含winbase.h,链接Kernel32.lib。3.1.4 错误代码调用失败时,CreateFile和CreateMailslot返回INVALID_HANDLE_VALUE。3

18、.2 基本客户机服务器服务器进程负责创建一个邮槽。邮槽客户机进程则负责打开邮槽的实例。3.2.1 邮槽服务器的详情编写一个基本服务器应用的步骤:1) 用函数CreateMailslot创建一个邮槽句柄。2) 调用函数ReadFile,使用已有的邮槽句柄从任何客户机接收数据。3) 用函数CloseHandle关闭邮槽句柄。3.2.2 邮槽客户机的详情编写基本的客户机应用的步骤:1) 使用函数CreateFile打开指向用于传送数据邮槽的引用句柄。2) 调用函数WriteFile向邮槽写入数据。3) 数据的写入完成后,用函数CloseHandle关闭打开的邮槽句柄。3.3 其他邮槽APIGetMa

19、ilslotInfo、SetMailslotInfo。3.4 平台和性能问题在Win9x平台上,邮槽存在着一些限制:“8.3字符名字限制”、不能取消“凝结”的I/O请求以及由于超时引起的内存废弃。第4章 命名管道命名管道实际上建立起一个简单的客户机服务器数据通信体系。4.1 命名管道的实施细节4.1.1 命名管道命名规范命名管道的标识采用UNC格式:serverPipepathname4.1.2 字节模式与消息模式字节模式:消息以连续的字节流的形式在客户机与服务器之间流动。消息模式:客户机和服务器通过一系列不连续的数据单位进行数据的收发。4.1.3 应用程序的编译必须在程序文件中包含winba

20、se.h头文件,并链接Kernel32.lib库。4.1.4 错误代码CreateFile和CreateNamedPipe失败时返回INVALID_HANDLE_VALUE。4.2 客户机与服务器的基础4.2.1 服务器的细节创建命名管理服务器的步骤:1) 用CreateNamedPipe创建一个命名管道实例句柄;2) 用ConnectNamedPipe在命名管道实例上监听客户机连接请求;3) 分别使用ReadFile和WriteFile从客户机接收数据或将数据发给客户机;4) 用DisconnectNamedPipe关闭命名管道连接;5) 用CloseHandle关闭命名管道实例句柄。程序清

21、单4-1 简单的命名管道服务器(Server.cpp)。4.2.2 高级服务器的细节要想同时控制多个管道实例,服务器必须使用多线程或使用异步Win32 I/O机制。1. 线程程序清单4-2 在Win32环境中使用线程技术开发的高级命名管道服务器(Threads.cpp)。2. 重叠式I/O工作原理:向函数传递一个OVERLAPPED结构,然后使用函数GetOverlappedResult,从原来那个OVERLAPPED结构中取得I/O请求的结果。程序清单4-3 使用Win32重叠式I/O技术开发的高级命名管道服务器(Overlap.cpp)。3. 安全模拟服务器的线程要在客户机的安全环境中执行

22、,需要设置一个安全模拟级别。4.2.3 客户机的细节1) 调用WaitNamedPipe等候一个命名管道实例可被使用。2) 调用CreateFile建立与命名管道的连接。3) 调用WriteFile和ReadFile分别向服务器发送数据或从服务器接收数据。4) 调用CloseHandle关闭打开的命名管道。程序清单4-4 简单的命名管道客户机(Client.cpp)。4.3 其他API调用CallNamedPipe、TransactNamedPipe、GetNamedPipeHandleState、SetNamedPipeHandleState、GetNamedPipeInfo、PeekNam

23、edPipe。第5章 网络原理和协议5.1 协议的特征5.1.1 面向消息面向消息:传输协议把每个离散的写命令当作一条独立的消息在网上传送。5.1.2 面向连接和无连接面向连接的服务在进行数据交换之前,必须在通信双方建立一条通信信道。无连接协议并不关心接收端是否正在收听。5.1.3 可靠性和次序性可靠性保证了发送端发出的每个字节都能到达既定的接收端。次序性是指数据到达接收端的顺序。5.1.4 从容关闭在从容关闭的过程中,一方开始关闭通信会话,但另一方仍然可以读取线上或网络堆栈上挂起的数据。如果使用TCP协议,连接双方都必须执行一次关闭,以便完全中断连接。5.1.5 广播数据一般情况下,路由器不

24、会传送广播包。5.1.6 多播数据多播发送的数据有一个或多个接收端接收。IP协议下,多播是广播的一种变形。视频会议应用常常使用多播。5.1.7 服务质量QoS是用来解决网络延迟和阻塞等问题的一种技术。5.1.8 部分消息多数不支持部分消息的协议都会丢弃不完整的数据报。5.1.9 路由选择的考虑可路由或不可路由。5.1.10 其他特征字节序和最大传输单元。5.2 支持的协议5.2.1 支持的Win32网络协议表 5-1提供了大部分实用协议及各协议支持的一些行为。5.2.2 WinCE网络协议WinCE只支持TCP/IP协议与WinSock 1.1规格。5.3 WinSock 2协议信息可调用WS

25、AEnumProtocols或EnumProtocols函数获得系统中安装的网络协议信息。通常需要两次调用WSAEnumProtocols函数才能获取特定协议的信息。启动WinSock库的函数:int WSAStartup(WORD wVersionRequested, LPWSADATA lpWSAData);卸载WinSock库的函数:int WSACleanup(void);5.4 Windows套接字套接字是一个指向传输提供者的句柄。在Win32中,套接字的类型为SOCKET。建立套接字的函数:SOCKET WSASocket( int af, int type, int protoc

26、ol, LPWSAPROTOCOL_INFO lpProtocolInfo, GROUP g, DWORD dwFlags);SOCKET socket( int af, int type, int protocol);5.5 具体平台的问题5.6 选择适当的协议如果从头开发应用程序,TCP/IP是首选协议。TCP/IP是最安全的选择。第6章 地址家族和名字解析6.1 IP6.1.1 TCPTCP能提供可靠的数据传输。在利用TCP进行通信时,源和目标之间会建立一个虚拟连接。6.1.2 UDPUDP 不保证可靠的数据传输。6.1.3 定址在WinSock中,可以通过SOCKADDR_IN结构来指

27、定IP地址和服务端口信息。struct sockaddr_in short sin_family; unsigned short sin_port;struct in_addr sin_addr; char sin_zero8; ;端口号分为三类:“已知”端口:01023已注册端口:102449151动态或私用端口:4915265535inet_addr函数可将一个点式IP地址转换成一个32位的无符号长整数:unsigned long inet_addr(const char FAR *cp );1. 特殊地址INADDR_ANY允许服务器应用监听每个网络接口上的客户机活动。INADDR_BR

28、OADCAST用于在一个IP网络中发送广播UDP数据报。2. 字节排序Little-Endian:低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。Big-Endian:高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。网络字节序:TCP/IP协议中使用的字节序。将一个数从主机字节顺序转换成网络字节顺序的4个函数:u_long htonl( u_long hostlong );int WSAHtonl( SOCKET s, u_long hostlong, u_long FAR * lpnetlong );u_short htons( u_short hostshort )

29、;int WSAHtons( SOCKET s, u_short hostshort, u_short FAR * lpnetshort );将网络字节顺序转换成主机字节顺序的4个函数:u_long ntohl( u_long netlong );int WSANtohl( SOCKET s, u_long netlong, u_long FAR * lphostlong );u_short ntohs( u_short netshort );int WSANtohs( SOCKET s, u_short netshort, u_short FAR * lphostshort );利用inet

30、_addr和htons函数来创建SOCKADDR_IN结构:SOCKADD_IN InternetAddr:INT nPortId = 5150;InternetAddr.sin_family = AF_INET;InternetAddr.sin_addr.s_addr = Inet_addr("136.149.3.29");InternetAddr.sin_port = htons(nPortId);6.1.4 创建套接字s = socket(AF_INET, SOCK_STREAM, 0);s = WSASocket(AF_INET,SOCK_STREAM, 0, NU

31、LL, 0, WSA_FLAG_OVERLAPPED);要利用UDP协议打开IP套接字,只须用SOCK_DGRAM代替函数中的SOCK_STREAM。6.1.5 名字解析gethostbyname、WSAAsyncGetHostByName函数从主机数据库中返回与指定的主机名对应的主机信息。gethostbyaddr、WSAAsynGetHostByName可获得与IP网络地址相应的主机信息。调用getservbyname或WSAAsyncGetServByName函数可从名为services的文件中获得已知服务的端口号。6.2 红外线套接字红外线套接字称为IrSock。6.2.1 定址IrS

32、ock地址结构中包含一个服务名和一个设备标识符。这里的服务名和设备标识符类似于传统TCP/IP套接字所用的IP地址和端口号字元组。6.2.2 名字解析6.2.3 红外线设备列举用于列举红外线设备的函数是带有IRLMP_ENUM_DEVICES选项的getsockopt函数。创建IrSock服务器的常见步骤:1) 建立一个地址家族为AF_IRDA、套接字类型为SOCK_STREAM的套接字。2) 用服务器的服务名填写SOCKADDR_IRDA结构。3) 用套接字句柄和SOCKADDR_IRDA结构调用bind。4) 用套接字句柄和等待连接队列的最大值调用listen。5) 锁定一个接入客户机的a

33、ccept调用。建立IrSock客户机的步骤:1) 建立地址家族为AF_IRDA、套接字类型为SOCK_STREAM的套接字。2) 以IRLMP_ENUM_DEVICES选项调用getsockopt函数,列举所有可用的红外线设备。3) 对返回的每个设备,用设备ID和准备连接的服务名填写SOCKADDR_IRDA结构。4) 用套接字句柄和SOCKADDR_IRDA结构调用connect函数。对步骤3)中所填的结构重复步骤4),直到连接成功。6.2.4 查询IAS6.2.5 创建套接字IrSock只支持面向连接的数据流。s = socket(AF_IRDA,SOCK_STREAM, 0);s =

34、WSASocket(AF_IRDA, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED);6.2.6 套接字选项6.3 IPX/SPXIPX 互联网包交换。SPX 顺序分组交换。6.4 NetBIOS从WinSock开始的NetBIOS定址需要得知NetBIOS名和LANA编号。6.5 AppleTalk如果不与苹果公司的MAC机通信,就不必选择AppleTalk协议。6.6 ATMATM 异步传输模式。ATM是一种媒体类型,而不是一个真正的协议。ATM类似于直接在以太网上写入以太帧。第7章 WinSock基础7.1 WinSock的初始化int WSA

35、Startup( WORD wVersionRequested, LPWSADATA lpWSAData );7.2 错误检查和控制不成功的WinSock调用返回的值通常是SOCKET_ERROR。int WSAGetLastError(void);7.3 面向连接的协议7.3.1 服务器函数为建立一个通信信道,服务器和客户机必须执行的基本调用如下:WinSock服务器:socket/WSASocket è bind è listen è accept/WSAAcceptWinSock客户机:socket/WSASocket è 地址解析 è

36、connect/WSAConnect1. bindint bind(SOCKET s, const struct sockaddr FAR * name, int namelen);例:SOCKET s;struct sockaddr_in tcpaddr;int port = 5150;s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);tcpaddr.sin_family = AF_INET;tcpaddr.sin_port = htons(port);tcpaddr.sin_addr.s_addr = htonl(INADDR_ANY);bind(

37、s,(SOCKADDR *)&tcpaddr, sizeof(tcpaddr);2. listenint listen( SOCKET s, int backlog );3. accept和WSAAcceptSOCKET accept(SOCKET s, struct sockaddr FAR* addr, int FAR* addrlen);SOCKET WSAAccept(SOCKET s, struct sockaddr FAR * addr, LPINT addrlen, LPCONDITIONPROC lpfnCondition, DWORD dwCallbackData);

38、7.3.2 客户机API函数客户机建立连接只需三步:1) 用socket或WSASocket创建一个套接字。2) 解析服务器名。3) 用connect或WSAConnect初始化连接。连接是通过调用connect或WSAConnect函数完成的。int connect(SOCKET s, const struct sockaddr FAR* name, int namelen);int WSAConnect(SOCKET s, const struct sockaddr FAR * name, int namelen, LPWSABUF lpCallerData, LPWSABUF lpCal

39、leeData, LPQOS lpSQOS, LPQOS lpGQOS);7.3.3 数据传输1. send和WSASendint send(SOCKET s, const char FAR * buf, int len, int flags);int WSASend(SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount, LPDWORD lpNumberOfBytesSent, DWORD dwFlags, LPWSAOVERLAPPED lpOverlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCom

40、pletionROUTINE );2. WSASendDisconnect3. recv和WSARecvint recv( SOCKET s, char FAR* buf, int len, int flags );int WSARecv(SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount, LPDWORD lpNumberOfBytesRecvd, LPDWORD lpFlags, LPWSAOVERLAPPED lpOverlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionROUTI

41、NE);4. WSARecvDisconnect5. WSARecvEx7.3.4 流协议在流套接字上收发数据所用的函数不能保证请求的数据量。7.3.5 中断连接1. shutdownint shutdown( SOCKET s, int how );2. closesocketint closesocket( SOCKET s );7.3.6 综合分析程序清单7-1 回应服务器代码(Server.c)程序清单7-2 回应客户机代码(Client.c)7.4 无连接协议7.4.1 接收端先用socket或WSASocket 建立套接字,再把这个套接字与准备接收数据的端口通过bind函数绑定在一

42、起,不必调用listen和accept,只需等待接收数据。int recvfrom(SOCKET s, char FAR* buf, int len, int flags, struct sockaddr FAR* from, int FAR * fromlen);int WSARecvFrom(SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount, LPDWORD lpNumberOfBytesRecvd, LPDWORD lpFlags, struct sockaddr FAR * lpFrom, LPINT lpFromlen, LPWSAO

43、VERLAPPED lpOverlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionROUTINE);7.4.2 发送端通过无连接的套接字发送数据有两种方法:一是建立套接字,调用sendto或WSASendTo函数。int sendto(SOCKET s, const char FAR * buf, int len, int flags, const struct sockaddr FAR * to, int tolen);int WSASendTo(SOCKET s, LPWSABUF lpBuffers, DWORD dwBuffe

44、rCount, LPDWORD lpNumberOfBytesSent, DWORD dwFlags, const struct sockaddr FAR * lpTo, int iToLen, LPWSAOVERLAPPED lpOverlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionROUTINE);7.4.3 基于消息的协议由于面向消息的协议对数据边界有保护,所以提交给发送函数的数据在被发送完之前可能累积成块。在数据的接收端,对接收函数的调用必须提供足够大的缓冲空间,否则接收调用就会失败,出现WSAEMSGSIZE。出现这种情

45、况时,缓冲会尽力接收,但未接收完的数据会被丢弃。但支持部分消息的协议不在此例。7.4.4 释放套接字资源调用closesocket函数。7.4.5 综合分析程序清单7-3 无连接的接收端(Receiver.c)程序清单7-4 无连接的发送端(Sender.c)7.5 其他函数1. getpeername2. getsockname3. WSADuplicateSocket4. TransmitFile7.6 WinCE由于WinCE 是建立在WinSock 1.1规格基础上的,不能用WinSock 2中专有的函数。WinCE 平台上可用的WSA函数只有WSAStartup、WSACleanup

46、、WSAGetLastError和WSAIoctl。7.7 其他地址家族7.7.1 AppleTalk7.7.2 IrDA红外线协议只提供一个协议类型,是一个面向连接的、流式的、可靠的协议。7.7.3 NetBIOS7.7.4 IPX/SPX7.7.5 ATM第8章 WinSock I/O方法8.1 套接字模式8.1.1 锁定模式在处于锁定模式的套接字上调用任何一个WinSock 函数,都会耗费或长或短的时间“等待”。要防止因为缺乏数据而造成应用程序完全陷于“冻结”状态,一个办法是使用多线程。8.1.2 非锁定模式nRet = ioctlsocket(s, FIOBIO, (unsigned

47、long *)&ul);将套接字置于非锁定模式之后,WinSock API调用会立即返回。8.2 套接字I/O模型8.2.1 select模型int select( int nfds, fd_set FAR * readfds, fd_set FAR * writefds, fd_set FAR * exceptfds, const struct timeval FAR * timeout);用select对套接字进行监视之前,必须将套接字句柄分配给某个集合,再调用select。用select操作一个或多个套接字句柄的步骤:1) 使用FD_ZERO宏,初始化fd_set。2) 使用FD

48、_SET宏,将套接字句柄分配给fd_set。3) 调用select函数。4) 根据select的返回值,使用FD_ISSET宏,对每个fd_set集合进行检查。5) 对I/O进行处理,然后返回步骤1)。8.2.2 WSAAsyncSelect要使用WSAAsyncSelect模型,必须首先创建一个窗口(或对话框),再为该窗口提供一个窗口例程(或对话例程)。int WSAAsyncSelect( SOCKET s, HWND hWnd, unsigned int wMsg, long lEvent );WSAAsyncSelect(s, hwnd, WM_SOCKET, FD_CONNECT |

49、 FD_READ | FD_WRITE | FD_CLOSE);在成功调用了WSAAsyncSelect之后,应用程序会在与hWnd窗口句柄参数对应的窗口例程中,以Windows消息的形式接收网络事件通知。窗口例程通常有如下定义:LRESULT CALLBACK WindowProc( HWND hWnd, UINT uMsg, WPARAM wPram, LPARAM lParam);8.2.3 WSAEventSelect必须先创建事件对象:WSAEVENT WSACreateEvent(void);然后调用WSAEventSelect函数:int WSAEventSelect( SOCK

50、ET s, WSAEVENT hEventObject, long lNetworkEvents);为WSAEventSelect创建的事件拥有两种工作状态和两种工作模式:两种工作状态:已传信和未传信。两种工作模式:人工重设和自动重设。在套接字与事件对象关联后,调用WSAWaitForMultipleEvents函数等待网络事件触发事件对象句柄的工作状态。8.2.4 重叠模型要在套接字上使用重叠I/O模型,必须先用WSA_FLAG_OVERLAPPED这个标志创建套接字。s = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERL

51、APPED);成功创建了一个套接字、并将其与一个本地接口绑定到一起后,便可开始重叠 I/O操作,方法是调用下列Winsock函数,同时指定一个WSAOVERLAPPED结构(可选): WSASend WSASendTo WSARecv WSARecvFrom WSAIoctl AcceptEx TrnasmitFile若随WSAOVERLAPPED结构一起调用这些函数,无论套接字是否设为锁定模式,函数都会立即完成并返回。管理重叠I/O请求的主要方法有两个:等待“事件对象通知”或通过“完成例程”。1. 事件通知重叠I/O的事件通知方法要求将Win32事件对象与WSAOVERLAPPED结构关联在

52、一起。重叠I/O操作完成之后,在事件通知中,WinSock会更改与WSAOVERLAPPED结构对应的事件对象的事件传信状态。需要调用WSAGetOverlappedResult函数,判断重叠调用是否成功。2. 完成例程如果用完成例程为重叠I/O请求提供服务,必须为I/O定制WinSock函数,指定一个完成例程,同时指定WSAOVERLAPPED结构。8.2.5 完成端口模型完成端口模型要求创建Win32完成端口对象,通过指定数量的线程,对重叠I/O请求进行管理。创建I/O完成端口对象的函数:CreateCompletionPort。1. 工作者线程与完成端口将套接字句柄与完成端口对象关联起来

53、之前,必须首先创建一个或多个“工作者线程”。2. 完成端口和重叠I/O在完成端口模型中,需要使用GetQueuedCompletionStatus函数,让一个或多个工作者线程在完成端口上等待。3. 单句柄数据和单I/O操作数据工作者线程从GetQueuedCompletionStatus调用收到I/O完成的通知后,在其参数lpCompletionKey和lpOverlapped中包含一些必要的套接字信息。利用这些信息,通过完成端口继续在一个套接字上的I/O处理。通过这些参数,可获得单句柄数据与单I/O操作数据。8.3 I/O模型的问题1. 客户机的开发如果客户机应用要同时管理一个或多个套接字,

54、建议采用重叠I/O或WSAEventSelect模型。如果开发以Windows为基础的应用程序,要进行窗口消息的管理,WSAAsyncSelect模型是一种最好的选择。2. 服务器的开发如果服务器应用要在一个给定的时间同时控制多个套接字,应采用重叠I/O模型。如果预计到服务器在任何给定的时间,都会为大量I/O请求提供服务,就应考虑使用I/O完成端口模型。第9章 套接字选项和I/O控制命令通过套接字选项和I/O控制命令对各种属性进行操作,便可影响套接字的行为。9.1 套接字选项getsockopt函数的作用是获得与指定套接字相关的信息。int getsockopt( SOCKET s, int

55、level, int optname, char FAR* optval, int FAR* optlen );setsockopt函数用于设置套接字选项。int setsockopt( SOCKET s, int level, int optname, const char FAR * optval, int optlen );9.1.1 SOL_SOCKET选项级别1. SO_ACCEPTCONN 如果为TRUE,表明套接字处于监听模式2. SO_BROADCAST 如为TRUE,表明套接字已配置成对广播消息进行发送要想接收广播消息,首先必须启用广播选项,然后使用某个数据报接收函数。也可以把套接字与广播地址连接起来,调用connect或WSAConnect,再调用recv或WSARecv。对UDP广播来说,必须指定一个端口号;类似地,接收端也必须请求在这个端口上接收广播数据。SOCKET s;BOOL bBroadcast = TRUE;char *sMsg = "This is a test"SOCKADDR_IN bcast;s = WSASocket(AF_INET, SOCK_DGRAM, 0,

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论