第16章 Windows套接字编程
C++实例(简单的Windows套接字(Socket)例子)

Server.exe PortNumber,例如Server 8000 Client.exe IPAddress PortNumber,例如Client 127.0.0.1 8000 然后在客户端的命令⾏输⼊字符串并回车,客户端将会把消息发送到服务器,考试.⼤提⽰服务器再把消息传回客户端。
服务器端,Server.cpp //Server.cpp #include #include #include #pragma comment(lib,"ws2_32.lib") int main(int argc, char* argv[]){ //判断是否输⼊了端⼝号 if(argc!=2){ printf("Usage: %s PortNumber\n",argv[0]); exit(-1); } //把端⼝号转化成整数 short port; if((port = atoi(argv[1]))==0){ printf("端⼝号有误!"); exit(-1); } WSADATA wsa; //初始化套接字DLL if(WSAStartup(MAKEWORD(2,2),&wsa)!=0){ printf("套接字初始化失败!"); exit(-1); } //创建套接字 SOCKET serverSocket; if((serverSocket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP))==INVALID_SOCKET){ printf("创建套接字失败!"); exit(-1); } struct sockaddr_in serverAddress; memset(&serverAddress,0,sizeof(sockaddr_in)); serverAddress.sin_family=AF_INET; serverAddress.sin_addr.S_un.S_addr = htonl(INADDR_ANY); serverAddress.sin_port = htons(port); //绑定 if(bind(serverSocket,(sockaddr*)&serverAddress,sizeof(serverAddress))==SOCKET_ERROR){ printf("套接字绑定到端⼝失败!端⼝: %d\n",port); exit(-1); } //进⼊侦听状态 if(listen(serverSocket,SOMAXCONN)==SOCKET_ERROR){ printf("侦听失败!"); exit(-1); } printf("Server %d is listening......\n",port); SOCKET clientSocket;//⽤来和客户端通信的套接字 struct sockaddr_in clientAddress;//⽤来和客户端通信的套接字地址 memset(&clientAddress,0,sizeof(clientAddress)); int addrlen = sizeof(clientAddress); //接受连接 if((clientSocket=accept(serverSocket,(sockaddr*)&clientAddress,&addrlen))==INVALID_SOCKET){ printf("接受客户端连接失败!"); exit(-1); } printf("Accept connection from %s\n",inet_ntoa(clientAddress.sin_addr)); char buf[4096]; while(1){ //接收数据 int bytes; if((bytes=recv(clientSocket,buf,sizeof(buf),0))==SOCKET_ERROR){ printf("接收数据失败!\n"); exit(-1); } buf[bytes]='\0'; printf("Message from %s: %s\n",inet_ntoa(clientAddress.sin_addr),buf); if(send(clientSocket,buf,bytes,0)==SOCKET_ERROR){ printf("发送数据失败!"); exit(-1); } } //清理套接字占⽤的资源 WSACleanup(); return 0; } 客户端,Client.cpp //Client.cpp #include #include #include #pragma comment(lib,"ws2_32.lib") int main(int argc, char* argv[]){ //判断是否输⼊了IP地址和端⼝号 if(argc!=3){ printf("Usage: %s IPAddress PortNumber\n",argv[0]); exit(-1); } //把字符串的IP地址转化为u_long unsigned long ip; if((ip=inet_addr(argv[1]))==INADDR_NONE){ printf("不合法的IP地址:%s",argv[1]); exit(-1); } //把端⼝号转化成整数 short port; if((port = atoi(argv[2]))==0){ printf("端⼝号有误!"); exit(-1); } printf("Connecting to %s:%d......\n",inet_ntoa(*(in_addr*)&ip),port); WSADATA wsa; //初始化套接字DLL if(WSAStartup(MAKEWORD(2,2),&wsa)!=0){ printf("套接字初始化失败!"); exit(-1); } //创建套接字 SOCKET sock; if((sock=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP))==INVALID_SOCKET){ printf("创建套接字失败!"); exit(-1); } struct sockaddr_in serverAddress; memset(&serverAddress,0,sizeof(sockaddr_in)); serverAddress.sin_family=AF_INET; serverAddress.sin_addr.S_un.S_addr = ip; serverAddress.sin_port = htons(port); //建⽴和服务器的连接 if(connect(sock,(sockaddr*)&serverAddress,sizeof(serverAddress))==SOCKET_ERROR){ printf("建⽴连接失败!"); exit(-1); } char buf[4096]; while(1){ printf(">"); //从控制台读取⼀⾏数据 gets(buf); //发送给服务器 if(send(sock,buf,strlen(buf),0)==SOCKET_ERROR){ printf("发送数据失败!"); exit(-1); } int bytes; if((bytes=recv(sock,buf,sizeof(buf),0))==SOCKET_ERROR){ printf("接收数据失败!\n"); exit(-1); } buf[bytes]='\0'; printf("Message from %s: %s\n",inet_ntoa(serverAddress.sin_addr),buf); } //清理套接字占⽤的资源 WSACleanup(); return 0; }。
套接字编程

typedef struct WSAData {WORD wVersion;WORD wHighVersion;char szDescription[WSADESCRIPTION_LEN+1];char szSystemStatus[WSASYS_STATUS_LEN+1];unsigned short iMaxSockets;unsigned short iMaxUdpDg;char FAR * lpV endorInfo;} WSADATA, FAR * LPWSADATA;成员:wVersionWindows Sockets DLL期望调用者使用的Windows Sockets规范的版本。
高位字节存储副版本号, 低位字节存储主版本号,可以用WORD MAKEWORD(BYTE,BYTE ) 返回这个值,例如:MAKEWORD(1,1)wHighVersion这个DLL能够支持的Windows Sockets规范的最高版本。
通常它与wV ersion相同。
szDescription以null结尾的ASCII字符串,Windows Sockets DLL将对Windows Sockets实现的描述拷贝到这个字符串中,包括制造商标识。
文本(最多可以有256个字符)可以包含任何字符,但是要注意不能包含控制字符和格式字符,应用程序对其最可能的使用方式是把它(可能被截断)显示在在状态信息中。
szSystemStatus以null结尾的ASCII字符串,Windows Sockets DLL把有关的状态或配置信息拷贝到该字符串中。
Windows Sockets DLL应当仅在这些信息对用户或支持人员有用时才使用它们,它不应被作为szDescription域的扩展。
iMaxSockets单个进程能够打开的socket的最大数目。
Windows Sockets的实现能提供一个全局的socket池,可以为任何进程分配;或者它也可以为socket分配属于进程的资源。
华北电力大学 网络编程 2--Windows套接字.

Windows套接字规范
Microsoft以Berkeley Socket规范为范例定义了一 套Windows下的网络编程接口,它不仅包含了人 们很熟悉的Berkeley Socket风格的库函数,也包 含了一组针对Windows的扩展库函数,以使程序 员能充分利用Windows消息驱动机制进行编程。
在Windows 3.0之后,Socket渐渐地被引入到 Windows系统中,它不仅包含了人们所熟悉的 Berkeley Socket风格的库函数,也包含了一组 针对Windows的扩展库函数,以使程序员能充 分地利用Windows消息驱动机制进行编程。
套接字是通信的基础,是支持网络协议数据通 信的基本接口。
WORD
wVersion; 存储当前使用的版本信息
WORD
wHignVersion; Winsock库的最高版本
Char
szDescrition[WSADESCRIPTION_LEN+1];
Char
szSystemStatus[WSASYS_STATUS_LEN+1];
Unsigned short iMaxSockets; 可同时打开的套接字数目
在源码和二进制代码方面都作了向后兼容,实现了 Winsock应用程序和任何版本的Winsock实现之间最 大的互操作性,同时也减少了Winsock应用程序使 用者、网络协议栈提供者和服务提供者的许多烦恼。
Winsock编程一般基于客户机/服务器模型实现, 一般分为以下几类:
套接字编程的简单实现方法

套接字编程的简单实现方法套接字编程的简单实现方法通常包括以下几个步骤:1. 创建套接字:使用socket()函数创建一个套接字对象。
例如,在Python中可以使用socket模块的socket函数来创建套接字,如下所示:pythonimport socketsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)此处创建了一个TCP套接字,使用IPv4地址族(AF_INET)。
2. 绑定套接字:使用bind()函数将套接字绑定到一个特定的地址和端口号。
例如:pythonsock.bind(('localhost', 8000))此处将套接字绑定到本地主机的8000端口。
3. 监听连接请求:使用listen()函数监听连接请求,指定队列的最大长度。
例如:pythonsock.listen(1)此处指定最大连接数为1。
4. 接受连接请求:使用accept()函数接受客户端的连接请求,返回一个新的套接字和连接的地址。
例如:pythonclient_sock, address = sock.accept()此处接受连接请求并返回客户端的套接字对象和地址。
5. 发送和接收数据:使用send()和recv()函数发送和接收数据。
例如:pythonclient_sock.send('Hello, client!')data = client_sock.recv(1024)此处发送一条消息给客户端,并接收客户端返回的数据。
6. 关闭套接字:使用close()函数关闭套接字连接。
例如:pythonclient_sock.close()sock.close()此处关闭客户端和服务器的套接字连接。
这只是套接字编程的简单实现方法,实际应用中可能还需要处理异常、多线程或多进程等情况。
不同编程语言和操作系统的实现方式可能会有所不同,具体使用时需要根据实际情况进行相应的调整。
Windows套接字

有关套接字
一种是"Stream Sockets"(流格式),另外 一种是"Datagram Sockets"(数据包格式)。我 们以后谈到它们的时候也会用到 "SOCK_STREAM" 和 "SOCK_DGRAM"。数据报 套接字有时也叫“无连接套接字”(如果你确实要 连接的时候可以用connect()。) 流式套接字是可 靠的双向通讯的数据流。如果你向套接字按顺序 输出“1,2”,那么它们将按顺序“1,2”到达另 一边。它们是无错误的传递的,有自己的错误控 制。
绑定套接字──bind()
当一个套接字用socket()创建后,存在一个 名字空间(地址族),但它没有被命名。bind() 将套接字地址(包括本地主机地址和本地 端口地址)与所创建的套接字号联系起来, 即将名字赋予套接字,以指定本地半相关。 其调用格式如下:
int bind(SOCKET s, const struct sockaddr FAR * name, int namelen);
socket()函数 bind()函数 connect()函数 listen()函数 accept()函数 send()和recv()函数 sendto()和recvfrom()函数 close()和shutdown()函数
创建套接字──socket()
应用程序在使用套接字前,首先必须拥有一个套接字,系统调用 socket()向应用程序提供创建套接字的手段,其调用格式如下: SOCKET socket(int af, int type, int protocol); 该调用要接收三个参数:af、type、protocol。参数af指定通信发生的 区域,UNIX系统支持的地址族有:AF_UNIX、AF_INET、AF_NS等, DOS、WINDOWS中仅支持AF_INET,它是网际网区域。因此,地 址族与协议族相同。参数type 描述要建立的套接字的类型。参数 protocol说明该套接字使用的特定协议,如果调用者不希望特别指定 使用的协议,则置为0,使用默认的连接模式。根据这三个参数建立 一个套接字,并将相应的资源分配给它,同时返回一个整型套接字号。 因此,socket()系统调用实际上指定了相关五元组中的“协议”这一 元。
windows境下面向套接字编程实例

内容预览VC++环境下WinSock编程及实例分析王振江(华北电力大学,河北保定071003)摘要:Visual C++对网络应用程序开发的支持是十分强大和充分的。
为了简化WinSock网络编程,Microsoft的基本类库(Microsoft Foundation Class或MFC)提供了两种利用Windows Sockets进行网络通信的编程模式,这两种模式即为用CAsyncSocket类和派生于CAsyncSocket的CSocket类来编程。
通过创建一个比较简单的基于MFC WinSock类的应用程序,详细分析了WinSock编程。
关键词:WinSock;网络;CSocket最近几年,计算机网络的发展一日千里,人们对网络服务应用程序的要求也越来越高、越来越多。
现在虽然有很多的网络应用程序,但是在很多的情况下,需要开发适合自己使用的网络应用程序。
Microsoft公司的Visual C++平台是一个具有高度综合性的软件开发工具,它不仅具有很强的程序处理能力,而且还能提供多种的编程风格;与Visual C++捆绑的MFC(Microsoft Foundation Class)提供了大量的封装良好的类,使用户在使用Visual C++时有如虎添翼的感觉。
Visual C++对网络应用程序开发的支持是十分强大和充分的。
1WinSock编程原理直接采用WinSock API函数来编程对于初学者很不轻松,不但要记忆很多的WinSock API函数的调用格式,还要了解设计WinSock网络编程的算法。
对于编写Windows应用程序来说,还要涉及复杂的消息驱动机制,涉及事件处理函数来处理套接字发送、接收数据等事件。
为了简化WinSock网络编程,使用户专注于应用程序算法的设计,Microsoft的基本类库(MicrosoftFoundation Class或MFC)提供了两种利用WindowsSockets进行网络通信的编程模式,这两种模式即为用CAsyncSocket类和派生于CAsyncSocket的CSocket类来编程。
Windows套接字编程:基于TCP和UDP协议

Windows套接字编程:基于TCP和UDP协议使⽤T C P / I P协议的应⽤程序通常采⽤两种应⽤编程接⼝(A P I):s o c k e t和T L I(运输层接)。
前者有时称作“ Berkeley socket ”,表明它是从伯克利版发展⽽来的。
后者起初是由AT & T开发的,有时称作X T I(X / O p e n运输层接⼝),以承认X / O p e n这个⾃⼰定义标准的国际计算机⽣产商所做的⼯作。
X T I实际上是T L I的⼀个超集。
⽽在windows操作系统中,实现了windows版本的socketAPI,⼜称winsock。
⼤家都知道不管是TCP/IP还是OSI的ISO协议都是分层模式的,⽤层的概念屏蔽的下层的细节,只要完成⾃层的功能即可,因⽽程序员在做⽹络编程时并不需要去关⼼⽹络底层的具体实现,只需要关⼼软件的功能即可,极⼤的简化了程序的编写。
因⽽我们在学习⽹络socket 编程时并不⼀定要很多的⽹络⽅⾯的知识,甚⾄是TCP/IP协议的知识也不需要太多。
因⽽在着我就不介绍那⽅⾯的知识了,如果要了解⽹上也四处都有那些被别⼈应⽤了N遍的经典的介绍。
在这只介绍基于TCP和UDP的简单的编程实现。
现今的⽹络程序⼀般都是基于C/S模型,即客户机-服务器模型。
这种结构将主要运算操作放在中⼼计算机上。
同集中式⼤型计算系统⽐较,"客户-服务器"结构的主要优点是提供了良好的实⽤性、灵活性、交互性和可扩展性。
"客户-服务器"以数据库服务器取代集中式⽂件共享进⽽实现了计算机系统之间的松耦合。
"客户-服务器"(Client/Server)是典型的Web信息系统模式。
"客户-服务器"⼀词在20世纪80年代⾸先被提出,起初,主要指个⼈计算机和Web的连接,在互联⽹中,主要指计算机系统之间通过Web的信息交互传递模式;"客户"是指信息服务的索取⽅,"服务器"指服务的提供⽅,根据软件的不同设置,⼀台计算机可以是客户也可以是服务器。
Windows下的socket(套接字编程)

Windows下的socket(套接字编程)前一段时间研究了下模拟网页登陆的相关资料,在此记录防遗忘。
Socket 源于unix,Socket就像我们使用CDC作图一样,免去了程序直接和设备驱动程序打交道的麻烦。
就是提供给我们用来操作底层硬件的接口函数。
工作方式大概描述如下:Socket也即是我们通常所说的套接字,其存在于通信区域中。
通信区域也叫地址族,是一个抽象的概念,主要用于把所有通过套接字通信的进程共有的特性综合在一起,套接字通常之和同一区域的套接字交换数据(当然不同区域的通过转换也能实现)。
而Winsows平台下的socket只支持一个通信区域:AF_INET(网际域),这个域被使用网际协议的进程使用。
这在后面和socket有关的函数很有体现。
说到socket通信就不得不说下关于字节序的问题了。
我们知道现在的硬件平台,对于数据在内存的存储顺序都是低位先存(也就是我们通常所说的主机字节序)。
而在socket有关函数的参数都是要去以高位先存的存储方式的数据(网络字节序)。
那么就需要一个从主机字节需到网络字节序的转换过程。
套接字有三种类型:流式套接字(SOCK_STREAM),基于TCP传输协议,面向连接,可靠的传输方式。
数据报式套接字(SOCK_DGRAM),基于UDP,面向无连接,不可靠。
原始套接字(SOCK_RAW)。
Windows 的socket经历了众多版本的升级变迁,建议使用2以上的版本。
下面就是Windows Socket的编程实现了:客户端/服务端一,基于TCP(面向连接)的socket编程服务端:1,加载套接字库(WSAStartUp)2,创建套接字(socket)3,将套接字绑定到本机的一个地址和端口上(bind)4,将套接字设为监听模式,准备接收客户端请求(listen)5,等待客户请求到来;当请求到来后,接收连接请求,返回一个新的对应于此次连接的套接字(accept)6,返回等待另一客户端的请求。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
第16章Windows套接字编程--《Visual C++开发技术大全》Windows套接字是开放的网络编程接口,完成网络环境中的数据传输功能。
本章在介绍Windows Socket概念的基础上,介绍了套接字库函数和WinSocket API,并讲述了MFC对Windows套接字的封装。
最后,以一个实例演示了Windows 套接字的编程方法。
16.1 概述本节介绍Window套接字中用到的重要概念,包括套接字及其分类和Window Sockets采用的编程模型--客户端/服务器模型。
另外,还介绍了网络编程中的一个重要点--网络字节顺序,并且介绍了如何处理网络字节顺序与系统字节顺序之间的转换。
16.1.1 Windows Sockets规范Windows Sockets规范是Windows平台下定义的可以兼容二进制数据传输的网络编程接口,是基于伯克利加利福尼亚大学的BSD UNIX Sockets的实现,当前的版本是2.0。
此规范包括BSD格式的Sockets函数和Windows扩展函数。
使用Windows Sockets的应用程序可以与任何兼容Windows Sockets API的网络程序进行数据通信。
目前,市面上很多网络软件支持Windows Sockets,包括传输控制协议/Internet协议(TCP/IP)、Xerox网络系统(XNS)、DECNet协议、Novell公司的Internet包交换和顺序包交换协议(IPX/SPX)等。
虽然现在的Windows Sockets规范定义了提取TCP/IP的Sockets,但是,任何网络协议可以通过提供自己实现的Windows Sockets的DLL版本支持Windows Sockets。
终端仿真器和电子邮件系统都是使用Windows Sockets典型实例。
因为Windows Sockets是抽象于底层网络的,因此,开发人员不需要了解有关网络的知识,就可以编写运行在任何支持Sockets的网络上的应用程序。
因为Sockets编程模型使用Internet协议族的"通信域",所以它是编写支持Internet通信应用程序首选通信方式,这也是Socket长足发展的原因。
16.1.2 套接字及其分类在Windows Sockets规范中,使用套接字(socket)代表通信端点,在网络上通过Windows Sockets 应用程序发送或接收数据包的对象。
Socket具有类型和名称,并具有与其类型相关的运行过程。
当前,socket通常使用IP(Internet Protocol)与其他socket进行双向数据交换,所有数据流都可以同时在两个方向上进行通信。
Socket套接字分为两种类型,一种是数据报socket,一种是数据流socket。
1.数据报套接字数据报套接字,即无连接套接字,是不需要连接即可进行通信的套接字,可以向指定的socket发送数据报消息,也可以从指定的socket接收消息。
提供双向的面向记录的数据流,但是不能确保数据传输的顺序,也不能确保传输的可靠性,有时会出现传输失败。
通过数据报套接字传输的数据,到达目的端时,有可能打乱了发送时的字节顺序,并有可能复制传输数据,但是会控制数据的记录边界,记录小于接收端的内部大小限制。
开发人员需要管理数据的顺序和可靠性,在本地局域网中可靠性比在广域网或Internet 上高。
数据报套接字的一个典型应用是,保持系统时钟与网络同步,而且使用数据报套接字可以同时向大量的网络地址广播消息。
对于面向记录的数据使用数据报套接字比较合适。
2.数据流套接字数据流套接字是基于显式连接的套接字。
提供没有记录边界的双向字节数据流,具有可靠的发送顺序,没有复制数据。
数据流的接收也是可靠的,适合处理大量数据的传输。
客户端Socket请求到服务器Sockets,服务器Sockets可以接收连接请求,也可以拒绝连接请求。
如电话呼叫就是一个典型的数据流例子,首先呼叫方发起到被叫方的连接,被叫方可以接受连接,即接听,也可以拒绝连接,即挂断。
如果接听,则链路建立了,可以进行双向数据交换,即双方可以进行通话,并且听端会按照顺序听到说话方所说的内容,不会有重复,也不会丢失。
还有一个典型的数据流socket的例子是FTP(File Transfer Protocol,文件传输协议),可以用于传输任意大小的ASCII或二进制文件。
当需要保证数据到达的可靠性和数据量比较大时,数据流套接字比数据报套接字更合适。
在一些网络层协议下,如XNS,数据流是面向记录的记录流,而不是字节流。
在更通用的TCP/IP协议下,数据流是面向字节的字节流。
Windows Sockets提供独立于底层协议的抽象层。
16.1.3 客户端/服务器模型Sockets套接字可以用在多种架构模型下,可以用在点对点模型,如聊天程序,也可以用在远程过程调用RPC的通信中,但是最常用在客户端/服务器模型中。
客户端/服务器模型是常用的一种架构模型,将应用程序分成前端客户端组件和后台服务器组件。
客户端组件运行在工作站上,负责从用户处接收数据,为服务器处理数据,并形成到服务器的连接。
后台服务器会等待客户端的连接,当服务器接收到客户端的连接请求后,服务器会处理并返回给客户端响应信息。
客户端接收到响应消息,通过用户接口呈现给用户。
目前,很多项目都设计为分布式程序,用于提高应用程序的性能。
而分布式程序就是基于客户端/服务器模型的。
如数据库应用程序、通信应用程序都是基于客户端/服务器模型的。
在设计基于客户端/服务器模型的应用程序时,程序的性能和可扩展性是设计的关键要素。
还需要考虑程序的组件和基本处理,包括数据包设计、物理部署模型、远程服务器负载、网络带宽的分析等问题。
要提高程序性能,每个客户端应该按需处理,如果不控制客户端的连接和数据传输量,则会大大降低程序效率,因为在客户端/服务器模型下,系统瓶颈是在服务器端的处理,因此。
在设计此模型的程序时,应尽量将处理放在客户端中处理,减少服务器压力。
影响客户端/服务器模型正常运行有以下因素。
服务器平台硬件问题:当服务器平台的硬件出现问题时,会影响客户端/服务器模型应用程序的正常运行,这个问题包括服务器硬件出现故障,也包括服务器硬件升级而需要的短暂停止,都会中断程序的正常运行。
服务器平台软件问题:服务器软件平台问题包括服务器应用程序本身的问题也包括支持软件的问题,如操作系统的问题、杀毒软件的问题等,都会中断应用程序的运行,或降低服务器程序的运行效率。
网络问题:除了将客户端程序和服务器程序部署在同一台计算机上的情况外,当网络中断时,则应用程序就会中断运行;当网络出现阻塞时,应用程序运行效率会很低。
因此,在编写客户端/服务器模型的应用程序时,需要考虑事务的处理,如当进行银行交易处理时,如果柜台客户端提交了交易请求时,服务器在返回响应前,发生网络故障,则当网络恢复时,要进行此笔交易的后期处理,也就是事务的处理。
应用程序问题:客户端应用程序和服务器应用程序的可靠性,对于系统的稳定性是决定性的。
因此,要使系统稳定可靠的运行,需要在运行平台下进行彻底的测试。
无论哪种情况影响系统运行,应用程序服务器必须能够具有快速恢复并重新启动服务的能力。
另外,在客户端/服务器模型中,客户端通过连接到服务器访问服务器的功能和数据,因此,服务器需要增加身份认证,控制客户端对服务器资源的访问,如通过身份验证、IP地址限制等方式。
这是保证系统正常运行的基本处理。
总之,编写稳定、高效、安全的客户端/服务器程序可以实现资源共享和数据传输,进而完成世界互联的操作。
16.1.4 网络字节顺序不同机器架构使用不同的字节顺序存储数据,如基于Intel处理器的机器与Macintosh(Motorola)机器存储数据的字节顺序是相反的。
Intel采用的字节顺序称为"小头方式",即低字节在前,高字节在后的方式,而标准的网络顺序是"大头方式",即高字节在前,低字节在后的方式。
表示如下:将0x12345678写入到以0x0000开始的内存中,则结果为1.大头方式小头方式2.0x0000 0x12 0x343.0x0001 0x34 0x124.0x0002 0x56 0x785.0x0003 0x78 0x56其中,0x12、0x34、0x56、0x78各是一个字节,组合字节顺序时,是以字Word为单位的,每个字包括两个字节,低字节和高字节。
小头方式就是低字节在前,大头方式就是高字节在前。
字之间是按照正常顺序。
一般情况下,用户不需要处理在网络上发送和接收数据的字节顺序的转换,但是在下列情况下,需要用户手动转换字节顺序。
用户传输的信息需要网络解释,这与发送到其他机器的数据不一样。
如用户传输端口和地址时,必须由网络理解。
当与之通信的服务器应用程序不是MFC应用程序时,如果通信的两台机器使用的字节顺序不同,则需要调用字节转换。
而下列情况下,不需要用户手动调用字节转换。
两台机器使用相同的字节顺序,并且两端约定不进行字节交换。
与之通信的服务器是MFC应用程序。
用户有与之通信的服务器的源代码,因此,可以显式地说明是否转换字节顺序。
可以将服务器转换成MFC程序。
在后面会介绍到MFC的CAsyncSocket类,如果使用此类,用户必须自己管理需要的字节顺序转换。
Windows Socket标准化"大头方式"字节顺序模型,并提供与"小头方式"字节顺序的转换函数。
而CSocket使用的CArchive类使用"小头方式"字节顺序,但是CArchive类处理了字节顺序转换的细节。
通过在应用程序中使用标准的字节顺序,或使用Windows Sockets字节顺序转换函数,用户可以编写灵活的代码。
如果使用MFC Sockets编程,即客户端和服务器端都使用MFC,则不需要关心字节顺序的细节。
如果编写与非MFC应用程序进行通信的应用程序,如FTP服务器,则用户在将数据传入存档对象前,需要自己管理字节顺序转换。
Windows Sockets提供了4个转换函数,ntohs()、ntohl()、htons()和htonl(),如表16-1所示。
表16-1 字节转换函数下面以使用存档的CSocket对象的序列化函数为例,说明如何使用字节转换顺序。
假定与编写的程序通信的是非MFC服务器应用程序,并且没有源代码。
此时,非MFC服务器使用的是标准网络字节顺序"大头方式"。
编写的MFC客户端应用程序通过CSocket对象使用CArchive对象,而CArchive使用"小头方式"字节顺序。