通信网络程序设计(王晓东西电版)第5章IPXSPX网络编程.ppt_第1页
通信网络程序设计(王晓东西电版)第5章IPXSPX网络编程.ppt_第2页
通信网络程序设计(王晓东西电版)第5章IPXSPX网络编程.ppt_第3页
通信网络程序设计(王晓东西电版)第5章IPXSPX网络编程.ppt_第4页
通信网络程序设计(王晓东西电版)第5章IPXSPX网络编程.ppt_第5页
已阅读5页,还剩99页未读 继续免费阅读

下载本文档

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

文档简介

,第5章 IPX/SPX网络编程,5.1 概述 5.2 套接字 5.3 IPX/SPX协议结构 5.4 IPX程序设计 5.5 SPX程序设计 小结,Internet分组交换/顺序分组交换协议(即IPX/SPX协议)是Novell公司为了适应网络的发展而开发的通信协议,具有很强的适应性,且安装方便,同时还具有路由功能,可以实现多网段间的通信,是一种早期的网络通信协议。IPX/SPX协议是三大协议中重要的一种,虽然已经渐渐淡出历史舞台,但是对其编程思想的学习有利于对后续TCP/IP学习思维的形成。 本章从IPX/SPX的概念入手,介绍套接字编程接口及IPX/SPX协议结构,最后,结合实践对IPX/SPX的编程方法进行了介绍。,IPX/SPX是IPX与SPX协议的组合,IPX协议负责数据包的传送;SPX负责数据包传输的完整性。在微软的NT操作系统中,一般使用NWLink IPX/SPX兼容协议和NWLink NetBIOS两种IPX/SPX的兼容协议,即NWLink协议,该兼容协议继承了IPX/SPX协议的优点,更适应Windows的网络环境。,5.1 概 述,IPX/SPX协议一般可以应用于大型网络(比如Novell)和局域网游戏环境中(比如反恐精英、星际争霸)。不过,如果不是在Novell网络环境中,一般不使用IPX/SPX协议,而是使用IPX/SPX兼容协议,尤其是在Windows 9x/2000组成的对等网中。,IPX是互联网分组交换协议(Internetwork Packet Exchange Protocol)的简称,是 Novell NetWare 操作系统所支持的互联网络中路由数据包的早期网络协议。IPX是一种面向无连接通信的数据报协议,类似于TCP/IP协议组中的网际协议(即IP),其高层协议,如SPX和NCP,主要提供差错恢复服务。在局域网中传输数据包时,如果接收节点在同一网段内,则通过IPX协议就直接按该节点的ID将数据传给报收节点;如果接收节点不在同一网段内,那么通过IPX协议可以将数据包交给NetWare服务器,再继续传输。,为了选择最佳路径,IPX使用动态距离矢量(distance vector)路由选择协议,如路由信息协议(Routing Information Protocol,RIP)或链路状态协议(NetWare Link-State Protocol,NLSP)。 SPX是顺序包交换协议(Sequences Packet Exchange Protocol)的简称,是基于施乐的Xerox SPP(Sequences Packet Protocol,顺序包协议)协议提出的,同样是由Novell公司开发的一种用于局域网的网络协议。在局域网中,SPX协议主要负责对整个传输的数据进行无差错处理,即纠错。SPX协议一般和上面介绍的IPX协议组合成IPX/SPX协议来使用,多用于Netware网络环境以及联网游戏。,如前所述,在本书Windows操作系统中实现IPX/SPX协议编程要使用IPX/SPX兼容协议(NWLink IPX/SPX/NetBIOS Compatible Transport Protocol),此外,该协议是通过套接字(Socket)调用实现的。Socket是一种通用叫法,在Windows操作系统下,微软对Socket的封装就是WinSock。,5.2 套 接 字,5.2.1 基本概念 1套接字的概念 从网络程序设计的角度来说,套接字就是一个指向传输提供者的句柄。在以太网网络通信环境下,套接字数据传输是一种特殊的I/O,它也相当于一种文件描述符,用一个类似于打开文件的函数Socket()。调用Socket()可以这样理解:建立了一个通信端点,通过它,用户的套接字程序可以通过网络和其他的套接字应用程序通信。套接字存在于一个“通信域”(为描述一般的线程如何通过套接字进行通信而引入的一种抽象概念)里,并且与另一个域的套接字交换数据。,Windows Sockets规范简称WinSock,是一套开放的、支持多协议的Windows下的网络编程接口,在Intel、Microsoft、Sun、SGI、Informix、Novell等公司的全力支持下,已经成为Windows网络编程的事实上的标准。Windows Sockets API是Microsoft Windows的网络程序接口,它包括一个标准的Berkeley Sockets功能调用的集合,以及为Windows所做的重要扩充。扩充的功能调用都用WSA(Windows Sockets Asynchronous)作前缀,表明它们允许异步的I/O操作,并采用了符合Windows消息机制的网络事件异步选择机制。这些扩充有利于应用程序开发者更好地利用Windows的消息驱动特性,设计出高性能的网络程序。,WinSock的实现一般都由两部分组成:开发组件和运行组件。开发组件是供程序员开发Windows Sockets应用程序使用的,包括介绍WinSock实现的文档、WinSock应用程序接口(API)引入库和一些头文件。WinSock最重要的头文件就是WinSock.h(或WinSock2.h),它包括了WinSock实现所定义的宏、常数值、数据结构和函数调用接口原型。运行组件是WinSock应用程序接口的动态连接库(.dll),文件名为WinSock.dll(对于32位机的WinSock2而言还有WS2_32.dll,它是通过将WS2_32.lib加入编译器中的工程的,否则需要动态载入WS2_32.dll,加载方法见9.3.2节),应用程序在执行时通过装入它来实现网络通信功能。,2协议支持 WinSock编程接口是一个与协议无关的接口,在Win32平台下支持许多种通信协议,如IPX/SPX、NetBIOS、TCP/IP、AppleTalk、ATM、红外线套接字(Windows CE下的WinSock只支持TCP/IP协议)等,并且还可以扩展。不管使用哪一种协议,它们的操作基本是类似的。 虽然WinSock不是一种网络协议(其本身与协议无关),但是它可以访问很多种网络协议。可以把它当作一些协议的封装,使用WinSock来调用多种协议的功能。,通过调用WinSock的接口函数来调用操作系统提供的协议。例如:若是基于IPX/SPX协议发送数据,就可以通过创建一个封装IPX/SPX协议的套接字,然后使用WinSock的接口函数Send()调用IPX/SPX的发送数据功能,这步工作在WinSock2中由服务提供者接口(Service Provider Interface,SPI)实现(详见9.4.2节)。对照表5-1中的Windows实现OSI七层模型对应的文件类型及文件实例示意,即能够理解只要绑定不同的协议驱动文件,就可以实现WinSock对多种通信协议的调用。,表5-1 WinSock网络编程OSI各层的实现,不同协议的 .sys文件(如tcpip.sys、netbios.sys、nwlnkipx.sys等)都可以在Windows系统文件夹C:WINDOWSsystem32drivers中找到。 要想获得系统中安装的网络协议的相关信息,还可以通过调用WSAENumProtocols函数来实现,其原型为 int WSAENumProtocols(LPINT lpiProtocols, /协议标识号数组 LPWSAPROTOCOL_INFO lpProtocolBuffer, /缓冲区 LPDWORD lpdwBufferLength ); / lpProtocolBuffer缓冲区长度其中,参数lpiProtocols是一个以NULL结尾的协议标识号数组,该参数可选。,如果lpiProtocols为NULL,则返回所有可用协议的信息;否则返回数组中所列的协议信息。参数lpProtocolBuffer是一个用PROTOCOL_INFO结构填充的缓冲区,该结构用来存取和获得给定协议的完整信息。参数lpdwBufferLength在输入时,用于保存传递给WSAENumProtocols()函数的lpProtocolBuffer缓冲区长度;在输出时,存有获取所有请求信息需传递给WSAENumProtocols()函数的最小缓冲区长度。 PROTOCOL_INFO的结构如下: typedef struct _WSAPROTOCOL_INFO,DWORD dwServiceFlags1; /描述协议提供的服务的位掩码 DWORD dwServiceFlags2; /保留为另外的协议属性定义 DWORD dwServiceFlags3; /保留为另外的协议属性定义 DWORD dwServiceFlags4; /保留为另外的协议属性定义 DWORD dwServiceFlags5; /提供协议在协议目录中如何表示的信息,GUID ProviderId; /供应商给服务提供者赋予的全局唯一标识 DWORD dwCatalogEntryId; /WS_32.dll对WSAPROTOCOL_INFO结构的唯一标识 WSAPROTOCOLCHAIN ProtocolChain; /一个包含构成协议链的目录入口号计数列的结构 int iVersion; /协议版本标识符 int iAddressFamily; /作为地址族参数传递给socket()/WSAsocket()函数, /以便为此协议打开一个套接字,此值也唯一地定义了 /使协议用的协议地址结构,int iMaxSockAddr; /最大的地址长度,单位为B(字节) int iMinSockAddr; /最小的地址长度,单位为B(字节) int iSocketType; /作为类型参数传递给socket()函数 int iProtocol; /作为协议参数传递给socket()函数 int iProtocolMaxOffset; /最大协议偏移值 int iNetworkByteOrder; /网络字节顺序,int iSecurityScheme; /指示使用的安全方案类型 DWORD dwMessageSize; /协议支持的最大消息长度 DWORD dwProviderReserved; /为服务提供者保留 TCHAR szProtocolWSAPROTOCOL_LEN+1; /标识此协议的字符串,如“SPX” WSAPROTOCOL_INFO, *LPWSAPROTOCOL_INFO;,通常需要调用WSAENumProtocols()函数两次以获取特定的协议信息。第一次调用时,指定lpProtocolBuffer()为NULL,调用失败,返回WSAENOBUFS错误,但参数lpdwBufferLength包含了所有协议信息需要的缓冲区长度。分配了恰当的缓冲区长度后,便可利用这个缓冲区进行第二次调用了,协议的信息将包含在WSAPROTOCOL_INFO结构中。这样,就可以对该结构进行分析,从而获得所需要的协议信息了。,3使用方式 在VC中进行WinSock的API编程开发,需要使用到下面三个文件: (1) Winsock.h:这是WinSock API的头文件。 (2) WSock32.lib:WinSock API链接库文件。在使用中,一定要把它作为项目的非缺省的链接库而包含到项目文件中去。 (3) WinSock.dll:WinSock的动态链接库,位于Windows的安装目录下。Winsock.dll位于通信协议栈和应用程序之间,即WinSock管理与通信协议的接口。,4创建与关闭 可以选择使用socket或WSAsocket函数之一来建立一个套接字,它们主要完成的功能是给指定的地址族、数据类型和协议分配一个套接字描述符以及相关的资源。根据这三个参数(WSAsocket以及其他辅助参数)建立一个套接字,并将相应的资源分配给它,同时返回一个整型套接字号,实际上指定了全相关五元组(1.3.3节)中的“协议”这一元。socket的原型函数如下: SOCKET WSAAPI socket(int af, int type, int protocol); 其中:,af:是一种地址格式描述,代表不同网络的寻址方法,可以是AF_INET、AF_IPX、AF_NETBIOS、AF_APPLETALK、AF_ATM、AF_IRDA、AF_UNIX中的一种,分别代表不同的寻址方式。这个参数对后面的套接字类型有影响,例如使用AF_ATM时,套接字的类型只有原始套接字类型。 type:描述要建立的套接字的类型,可以有五种选择:SOCK_STREAM、SOCK_,DGRAM、SOCK_SEQPACKET、SOCK_RDM和SOCK_RAW,分别标识流式、数据报式、定序分组式、可信赖数据包连接式和原始套接字。在各种协议下,对五种类型的支持不完全相同。 protocol:说明该套接字使用的特定协议,如果调用者不希望特别指定使用的协议,则置为0,即使用默认的连接模式。 如果没有错误产生,socket()函数返回一个与建立的套接字相关的描述符;否则,返回INVALID_SOCKET。,套接字使用完后需关闭,可使用closesocket()函数。closesocket()函数关闭套接字s,并释放分配给该套接字的资源。如果s涉及一个打开的TCP链接,则该链接被释放。 closesocket()的原型函数如下: int WSAAPI closesocket(SOCKET s); 其中,s是待关闭的套接字的描述符。返回值为:如果没有错误产生,closesocket()返回0;否则,返回SOCKET_ERROR。 除了closesocket()函数外,shutdown()函数也可以暂停一个Socket。,5使用过程 总的来说,使用套接字接口(面向连接或无连接)进行网络通信时,必须按下面四步进行处理: (1) 程序必须建立一个Socket。 (2) 程序必须按要求配置此Socket。也就是说,程序或者将此Socket连接到远方的主机上建立全相关,或者给此Socket指定一个本地协议端口,建立半相关。 (3) 程序需按要求通过此Socket发送和接收数据。 (4) 通信完毕后,程序必须关闭此Socket。 在通信过程中,还可以对该套接字的I/O进行管理(详见6.6节),以实现更加复杂的应用。,5.2.2 WinSock的启动与终止 WinSock是一种服务,这种服务在使用前要启动,使用后要终止。 1WinSock的启动 由于WinSock的服务是以动态链接库WinSock dll形式实现的,因此必须先调用WSAStartup()函数对WinSock dll进行初始化,协商WinSock的版本支持,并分配必要的资源。如果在调用WinSock()函数之前,没有加载WinSock库,则返回SOCKET_ERROR错误,错误信息是WSANOTINITIALISED。启动套接字服务的WSAStartup函数原型如下:,int WSAStartup(WORD wVersionRequested, LPWSADATA lpWSAData); 其中:参数wVersionRequested为调用者可以使用的Windows Sockets API支持的最高版本号。参数lpWSAData指向接收Windows Sockets实现细节的数据结构WSADATA的指针。返回值是:如果调用成功,返回0;否则,返回错误码。 此函数初始化WinSock dll时,必须被应用程序或dll第一个调用的Windows Sockets()函数所允许。,应用程序或dll指定Windows Sockets API要求的版本,以获取指定的Windows Sockets()实现的细节。应用程序或dll只有在一次成功的WSAStartup()执行后才能发布后续的WinSock()函数。,2WinSock的终止 在应用程序关闭套接字后,还应调用WSACleanup()函数终止对WinSock dll的使用,并释放资源,以备下一次使用。 WSACleanup函数的原型如下: int WSACleanup(void); 该函数不带任何参数,若调用成功则返回0,否则返回错误。,5.2.3 WinSock的主要函数 WinSock虽然封装了各种协议,但各种通信协议的主要操作函数基本一致,下面进行简要介绍。 1连接函数 连接函数:accept()、bind()、connect()。 accept()函数用于面向连接服务器。bind()函数用于未连接的数据报或流套接字,将一个本地地址与套接字相连接,即建立半相关。connect()函数用于与对等方建立一个连接。如果套接字s没有绑定,则系统赋予本地相关的唯一值,并且将套接字表示为已绑定的。,2传输函数 传输函数:recv()、recvfrom()、send()、sendto()。 recv()函数用于在参数s指定的已连接的数据报或流套接字上读取输入数据。recvfrom()函数用于在参数s指定的套接字(可能已连接)上读取输入数据,并捕获发送数据的地址,存入源地址缓冲区。send()函数用于在参数s指定的已连接的数据报或流套接字上发送输出数据。sendto()函数用于在参数s指定的数据报或流套接字上向指定的目的地址发送输出数据。,3I/O函数 WinSock提供了一系列套接字I/O控制函数控制套接字的I/O行为,并获取套接字I/O操作的有关信息。其中最常用的是ioctlsocket()函数,它可用于任一状态的任一套接字,而与具体协议或通信子系统无关。其原型为 int ioctlsocket(SOCKET s,long cmd,u_long FAR* argp); 其中:参数s是一个标识套接字的描述字。参数cmd用于指定对套接字s的操作命令,标准的I/O控制命令如表5-2所示。,除了上述标准I/O控制命令外,WinSock2还提供其他一些控制命令,以及安全套接字层、ATM I/O控制命令等,这里就不做过多介绍了。需要特别掌握的是WinSock2的SIO_RECVALL命令,它可以将网卡设置成混杂模式,通过被设置的原始套接字接收网络中所有的数据包。 与ioctlsocket()功能类似的函数还有WSAIoctl(),它提供了更多的命令选项,可参考MSDN中的有关说明。,表5-2 标准的I/O控制命令,4套接字选项函数 套接字建立后,可通过套接字选项函数获得与设置套接字相关的信息。这样的函数有两个,即getsockopt()和setsockopt(),二者的结构非常相似,下面进行联合讲解。 getsockopt()函数可以获得套接字选项,它的常见用法是获得与指定套接字相关的信息,其原型为 int getsockopt ( SOCKET s, int level, int optname, char FAR* optval, int FAR* optlen ); setsockopt()函数可以设置套接字选项,它的常见用法是设置与指定套接字相关的信息,其原型为,int setsockopt ( SOCKET s, int level, int optname, const char FAR * optval, int optlen); 其中:参数s是一个标识套接字的描述字。参数level用于指定套接字选项的级别,大多数选项都是一种特定的协议和套接字类型专有的,而其他选项适用于所有类型的套接字。参数optname表示需要设置的选项。参数optval为指向存放选项值缓冲区的指针。参数optlen为optval缓冲区的长度。 getsockopt()和setsockopt()的optval和optlen的形式稍有区别,在getsockopt()函数中将它们的值传出,而在setsockopt()函数中将它们的值传入。,套接字的相关信息众多,是要获得还是设置哪一个选项,则必须使用level和optname两个参数指明。level和optname的取值有严格的对应关系,请参考附录6。 下面函数可设置原始套接字(详见7.3.1节)的IP包的TTL值,是后面实现tracert程序的关键。 setsockopt(s, IPPROTO_IP, IP_TTL, (char*),5错误检查和控制 错误检查和控制对于WinSock应用程序是至关重要的。事实上,对WinSock API函数来说,返回错误是很常见的,但多数情况下,通信仍可在套接字上进行。尽管返回的值并非一成不变,但不成功的WinSock调用返回的最常见的值是SOCKET_ERROR。SOCKET_ERROR是值为 -1的常量。如果返回了错误,则可用WSAGetLastError()(或GetLastError()函数获得一段代码,这段代码明确表明产生错误的原因。WSAGetLastError()函数的原型如下:,int WSAAPI WSAGetLastError(void); 函数返回值指示当前线程最近执行的Windows Sockets API()函数产生的错误,可以在附录3中进行查阅,了解出错原因,也可以使用编译器提供的“Error Lookup”工具查询出错原因。,本节介绍使用WinSock实现IPX/SPX编程的方法。 5.3.1 IPX协议结构 IPX是Novell 公司最基本的通信协议。在NetWare环境下,工作站、服务器和网桥之间的通信都建立在以IPX为基础的IPX协议上,即网间数据包交换协议,其作用是帮助一个数据包选择路径、交换寻址,并将它送到目的地。因此,在ISO的开放互连(OSI)模型中,IPX协议处于网络层的位置,它也被称做是一种无连接的数据包规程。,5.3 IPX/SPX协议结构,IPX协议具有以下三个特点: 采用IPX协议通信的双方不用事先建立连接,因而通信速度快、效率高。虽然Netware不能保证数据一定能够到达目标地址,但可以保证IPX发送成功率达95%。因为IPX协议具有CRC的校验功能,可以保证数据包本身的正确性。 如果接收方在规定的时限内不响应,IPX将会自动重发。 IPX路由信息全部包括在数据包中,因此IPX包路由选择灵活,可方便地向多个工作站进行广播。IPX协议下的数据传输采用固定结构、可变长的数据包。 一个IPX协议数据包包含地址、路由、数据等字段信息,其结构如表5-3所示。,表5-3 IPX协议数据包结构,下面对表5-3中的几个关键字段进行进一步介绍。 (1) 数据包类型,即数据包第5个字节,代表这个IPX数据包所传输的种类,类型取值可以是表5-4中所定义的类型。,表5-4 IPX数据包的类型,(2) 目标地址部分,即数据包第617个字节,这部分用于说明IPX数据包发往何方,目标地址组成:目标网络地址 + 目标节点地址 + 目标套接口地址。 (3) 源地址部分,即数据包第1829个字节,源地址部分用于说明IPX数据包从何处发出,源地址组成:源网络地址 + 源节点地址 + 源套接口地址。 (4) 数据,即数据包第30个字节。IPX数据包的数据部分通过IPX数据包所传送的数据存放在IPX数据从结构第30个字节起的单元内,数据长度不超过547个字节。,5.3.2 协议地址 1地址结构 要用IPX进行WinSock客户机或服务器通信,必须使用结构为SOCKADDR_IPX的地址。在wsipx.h文件中规定了IPX/SPX协议地址结构SOCKADDR_IPX如下: typedef struct sockaddr_ipx short sa_family; char sa_netnum4; char sa_nodenum6; unsigned short sa_socket; SOCKADDR_IPX, *PSOCKADDR_IPX,FAR *LPSOCKADDR_IPX;,其中,sa_family字段应设为AF_IPX值;sa_netnum字段是4字节的地址,代表IPX网络上的网段号;sa_nodenum字段是6字节的地址,代表节点计算机的物理地址;sa_socket字段代表一个节点区分IPX通信的套接字或接口。 Novell IPX 网络地址是唯一的,以十六进制表示。它由两部分组成:网络号和节点号。IPX网络号由网络管理员分配,地址长32位;节点号通常是系统网络接口卡(NIC)的介质访问控制(MAC)地址,地址长48位。通过MAC地址作为节点号,系统可以通过发送节点以判断数据链路使用的MAC地址。,如果节点地址为0xFFFFFFFFFFFF(六个字节全为0xFF),则该数据包以广播方式发往网络上的所有节点工作站。 IPX的用户套接字号为4000HFFFFH,由NetWare SHELL动态分配。 IPX数据包数据部分的长最小为30个字节(只有头部分),最大值不定,这主要取决于使用的低层MAC协议(以太网或令牌环)。,2地址转换 由于IPX地址是十六进制数,不适宜键盘输入,因此要进行数据的转换,下面代码提供转换功能。 十六进制数转换为ASCII码的代码如下: UCHAR BtoH(char ch) if (ch = 0) ,printf(“Illegal characters in IPX address!n“); / Illegal values in the IPX address will not be accepted ExitProcess(-1); ASCII码转换为十六进制数的代码如下: void AtoH(char *szDest, char *szSource, int iCount) while (iCount-) *szDest+ = (BtoH(*szSource+) 4) + BtoH(*szSource+); return; ,3本地地址枚举 为了方便编程,还可以对本地IPX地址进行枚举,程序代码如下: #include “stdafx.h“ #include #include #include #include #pragma comment(lib,“wsock32.lib“) SOCKET sock = INVALID_SOCKET; int CreateIPXSocket() 略,int main(int argc, char* argv) SOCKADDR_IPX sa_ipx; IPX_ADDRESS_DATA ipx_data; int ret, cb, nAdapters, i=0, j=0; WSADATA wsd;,if (WSAStartup(MAKEWORD(2,2), ,ret = bind(sock, (SOCKADDR *) ,ret = getsockopt(sock, NSPROTO_IPX, IPX_MAX_ADAPTER_NUM,(CHAR *) printf(“Total number of adapters - %dn“,nAdapters); for(i=0; i nAdapters ;i+) /Get the address of each adapter memset ( if (ret = SOCKET_ERROR), printf(“getsockopt(IPX_ADDRESS) failed: %dn“, WSAGetLastError(); return 0; / Print each address for (j=0; j 4; j+)printf(“%02X“, (UCHAR)ipx_numj);/ Print the net number printf(“.“); for (j=0; j 6; j+)printf(“%02X“,(UCHAR)ipx_data.nodenumj);/ Print the node number printf(“n“); return 0; 本程序若要获取本地IPX地址,首先要创建一个IPX套接字;接着,将该套接字绑定(bind)到任意一个AF_IPX类型的地址上;然后通过调用getsockopt()函数分别得到适配器的数量和每个适配器上设置的IPX地址;最后用ASCII码的格式打印出来。,5.3.3 SPX协议结构 SPX是一个面向连接的协议,其格式在IPX之上又增加了12个字节,用于定义SPX的特殊信息,即其前面29个字节的字段含义与IPX完全一样,其结构如表5-5所示。,表5-5 SPX协议数据包结构,连接控制SPX使用该字节的高4位,用于控制通过“连接”传输的数据流,存在四种取值,即10H表示对方连接结束,20H表示保留,40H表示要求确认的包,80H表示本包为系统包。数据流类型用于指示SPX数据包中的数据类型或数据作用,可能的取值分三种情况,即取值0FDH表示由客户程序自定义的数据类型;取值FEH表示当客户程序结束一个有效连接时,SPX产生“连接结束”标志,并将本包发送往对方;取值FFH表示SPX自动产生“连接响应结束”标志,但不发往对方。,IPX程序是非面向连接的,与NetBIOS的数据报类似,这里将IPX的收发集成到一个程序中。,5.4 IPX程序设计,5.4.1 IPX套接字创建 IPX封装的套接字采用如下方法进行创建,代码如下: int CreateIPXSocket() sock = socket(AF_IPX, SOCK_DGRAM, NSPROTO_IPX); if (sock = INVALID_SOCKET) printf(“socket() failed: %dn“, WSAGetLastError(); return 0;, return 1; IPX是一种非面向连接的通信方式,因此其类型只有SOCK_DGRAM一种。,5.4.2 IPX数据收发 下面程序演示了IPX数据接收与发送的实现过程: #include “stdafx.h“ #include #include #include #include #pragma comment(lib,“wsock32.lib“) #define MAX_DATA_LEN 64000 / Global Variables,SOCKET sock = INVALID_SOCKET; void CreateIPXSocket() 略,见5.4.1节 / SendDatagram() is generic rotuine to send a datagram to a specifid host. int SendDatagram(SOCKET s, char *pchBuffer, SOCKADDR_IPX *psa) int ret;,ret=sendto(s,pchBuffer,strlen (pchBuffer ), 0, (SOCKADDR *)psa, sizeof(SOCKADDR_IPX); if (ret = SOCKET_ERROR) printf(“sendto() failed: %dn“, WSAGetLastError(); return -1; ,return ret; / ReceiveDatagram() is generic rotuine to receive a datagram from a specifid host. int ReceiveDatagram(SOCKET s, char *pchBuffer, SOCKADDR_IPX *psa, int *pcb) int ret; ret = recvfrom(s, pchBuffer, MAX_DATA_LEN, 0,(SOCKADDR *) psa,pcb); if (ret = SOCKET_ERROR) printf(“recvfrom() failed: %dn“, WSAGetLastError(); return -1; return ret; int main(int argc, char *argv) ,WSADATA wsd; SOCKADDR_IPX sa_ipx_sender; / sender address char chBufferMAX_DATA_LEN; / Data buffer int ret, cb, j; if (WSAStartup(MAKEWORD(2,2), &wsd) != 0) printf(“WSAStartup() failed: %dn“,GetLastError(); return -1; CreateIPXSocket(); sa_ipx_sender.sa_family = AF_IPX; ret = bind(sock,(SOCKADDR *),return 0; while (1) cb = sizeof (sa_ipx_sender); printf(“Waiting for Message comes. n“); ret = ReceiveDatagram(sock, chBuffer, ,/ Print the contents of received datagram and the senders address printf(“Message Received from Address - “); for (j=0; j4 ;j+)printf(“%02X“,(UCHAR)sa_ipx_sender.sa_netnumj); / Print the net number printf(“.“); for (j=0;j6;j+)printf(“%02X“,(UCHAR)sa_ipx_sender.sa_nodenumj);,/Print the node number printf(“n“); printf(“%d bytes of data received-%sn“, ret, chBuffer); / Echo the datagram on the bound socket to the client ret = SendDatagram(sock, chBuffer, , closesocket(sock); WSACleanup(); return 0; 该程序首先对网络中的IPX数据报进行接收,如果接收到IPX报文则打印报文源IPX地址和报文内容;再向源IPX地址发送一个响应报文。IPX数据的接收前,需要将IPX套接字绑定到任意一个IPX地址上。报文的接收调用ReceiveDatagram()函数,报文的发送使用SendDatagram()函数。,SPX程序是面向连接的,与NetBIOS的会话很类似,这里使用服务器端与客户端程序对SPX的会话两端的程序进行分别实现。,5.5 SPX程序设计,5.5.1 SPX套接字创建 SPX封装的套接字采用如下方法进行创建,代码如下: int CreateSPXSocket(int type) sock = socket(AF_IPX, type, NSPROTO_SPX); if (sock = INVALID_SOCKET) printf(“socket() failed: %dn“, WSAGetLastError(); return 0; ,return -1; type的取值可以是SOCK_STREAM或SOCK_SEQPACKET,分别对应流套接字和序列包流。,5.5.2 SPX服务器端 SPX是面向连接的通信服务。本程序首先创建一个SPX封装的套接字,然后将该套接字绑定到任意一个IPX本地地址上,之后调用监听函数(最多可以监听5个连接)。当有连接到达时,创建一个新的套接字与客户端进行数据的收发。地址可以通过5.3.2中的枚举函数获得。 #include “stdafx.h“ #include #include #include #include ,#pragma comment(lib,“wsock32.lib“) #define MAX_DATA_LEN 64000 / Global Variables SOCKET sock = INVALID_SOCKET, newsock = INVALID_SOCKET; DWORD dwNumBytes=512, / Number of bytes to send dwNumToSend=5; / Number of times to send int CreateSPXSocket(int type) /略,详见5.5.1节,/ SendData() sends some data over a connection-oriented IPX socket. int SendData(SOCKET s, char *pchBuffer) int ret; ret = send(s, pchBuffer, strlen(pchBuffer), 0); if (ret = SOCKET_ERROR) printf(“send() failed: %dn“, WSAGetLastError();,return -1; return ret; / ReceiveData() receives some data over a connection-oriented IPX socket. int ReceiveData(SOCKET s, char *pchBuffer) int ret, iTotal=0,iLeft=dwNumBytes; while(iLeft 0) ret = recv(s, ,printf(“recv() failed: %dn“, WSAGetLastError(); return -1; if (ret = 0) break; iTotal += ret; iLeft -= ret; return iTotal;, int main(int argc, char* argv) WSADATA wsd; SOCKADDR_IPX sa_ipx, / Server address sa_ipx_client; / Client address char chBufferMAX_DATA_LEN; / Data buffer int ret, cb, j,type=SOCK_STREAM; if (WSAStartup(MAKEWORD(2,2), ,ret = bind(sock, (SOCKADDR *) if (ret = SOCKET_ERROR), printf(“listen() failed: %dn“, WSAGetLastError(); return 0; printf(“Waiting for a Connection.n“); while (1) / Wait for a connection cb = sizeof(sa_ipx_client);,newsock = accept(sock, (SOCKADDR *) for,(j=0;j4;j+)printf(“%02X“,(UCHAR)sa_ipx_client.sa_netnumj); / Print the net number printf(“.“); for (j=0; j6;j+)printf(“%02X“, (UCHAR)sa_ipx_client.sa_nodenumj); /Print the node number printf(“n“); while (1) ,ret = ReceiveData(newsock, chBuffer); if (ret = 0)break; else if (ret = -1)return 0; / Print the contents of received data chBufferret = 0; printf(“%d bytes of data received-%sn“, ret, chBuffer); / Send data on newly created socket ret = SendData(newsock, chBuffer); if (ret = 0)break;,else if (ret = -1)

温馨提示

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

评论

0/150

提交评论