本文以及另外两篇相关文章解释 windows sockets 编程方面的一些问题。本文介绍字节排序。其他问题在文章 windows sockets:阻塞和 windows sockets:转换字符串中介绍。
如果使用 casyncsocket 类或从其派生,则您需要自己管理这些问题。如果您使用 csocket 类或从其派生,则由 mfc
管理它们。
不同的计算机结构有时使用不同的字节顺序存储数据。例如,基于 intel 的计算机存储数据的顺序与 macintosh
(motorola) 计算机相反。intel 字节顺序称为“little-endian”,与网络标准“big-endian”顺序也相反。下表解
释这些术语。
big-endian 和 little-endian 字节排序
| 字节排序 | 含义 |
|---|---|
| big-endian | 最重要的字节在词的左端。 |
| little-endian | 最重要的字节在词的右端。 |
通常,您不必为在网络上发送和接收的数据的字节顺序转换担心,但在有些情况下,您必须转换字节顺序。
在下列情况中需要转换字节顺序:
必须为网络理解。
排序,则需要字节顺序转换。
在下列情况下可以免去转换字节顺序的工作:
使用 casyncsocket 时,您必须自己管理任何必需的字节顺序转换。windows sockets 将“big-endian”字节顺
序模型标准化,并提供在该顺序和其他顺序之间转换的函数。然而,与 csocket 一起使用的 carchive 使用相
反的顺序(“little-endian”),但 carchive 为您管理字节顺序转换的细节。通过在应用程序中使用这种标准
排序,或通过使用 windows sockets 字节顺序转换函数,可增强代码的可移植性。
最适合使用 mfc 套接字的情况是当编写通信的两端时:在两端都使用 mfc。如果正在编写将与非 mfc 应用程序
通信的应用程序(如 ftp 服务器),则在向存档对象传递数据前,您可能需要使用 windows sockets 转换例程
ntohs 、 ntohl 、 htons 和 htonl 自己管理字节交换。本文稍后将给出这些用于与非 mfc 应用程序通信的函数
示例。
注意 当通信的另一端不是 mfc 应用程序时,也必须避免将从 cobject 派生的 c++ 对象以流的形式输入存
档,因为接收端无法处理它们。请参见 windows sockets:使用带存档的套接字中的说明。
有关字节顺序的更多信息,请参见 platform sdk 中的 windows sockets 规范。
下面的示例显示使用存档的 csocket 对象的一个序列化函数。它还阐释了在 windows sockets api 中如何使用
字节顺序转换函数。
该示例显示这样的情形:您正在编写与非 mfc 服务器应用程序通信的客户程序,而您没有访问该服务器应用程序
源代码的权限。在这种情况下,必须假设非 mfc 服务器使用标准的网络字节顺序。相反,mfc 客户端应用程序对
csocket 对象使用 carchive 对象,而 carchive 使用与网络标准相反的“little-endian”字节顺序。
假设要与之通信的非 mfc 服务器具有如下已建立的消息包协议:
struct message { long magicnumber; unsigned short command; short param1; long param2; }; 上述内容用 mfc 术语表示则为:
struct message { long m_lmagicnumber; short m_ncommand; short m_nparam1; long m_lparam2; void serialize
( carchive& ar ); }; 在 c++ 中, struct 和类在本质上是一回事。 message 结构可以有成员函数,如以上声明的 serialize 成员函数。
serialize 成员函数可能为如下形式:
void message::serialize(carchive& ar)
{
if (ar.isstoring())
{
ar < < (dword)htonl(m_lmagicnumber);
ar < < (word)htons(m_ncommand);
ar < < (word)htons(m_nparam1);
ar < < (dword)htonl(m_lparam2);
}
else
{
word w;
dword dw;
ar > > dw;
m_lmagicnumber = ntohl((long)dw);
ar > > w ;
m_ncommand = ntohs((short)w);
ar > > w;
m_nparam1 = ntohs((short)w);
ar > > dw;
m_lparam2 = ntohl((long)dw);
}
}
该示例要求进行数据字节顺序转换,因为一端的非 mfc 服务器应用程序的字节排序与另一端在 mfc 客户端应用程序中使用的 carchive 明显不匹配。该示例阐释了 windows sockets 提供的几个字节顺序转换函数。下表描述了这些函数。
windows sockets 字节顺序转换函数
| 函数 | 作用 |
|---|---|
| ntohs | 将 16 位数量从网络字节顺序转换为主机字节顺序(从 big-endian 转换为 little-endian)。 |
| ntohl | 将 32 位数量从网络字节顺序转换为主机字节顺序(从 big-endian 转换为 little-endian)。 |
| htons | 将 16 位数量从主机字节顺序转换为网络字节顺序(从 little-endian 转换为 big-endian)。 |
| htonl | 将 32 位数量从主机字节顺序转换为网络字节顺序(从 little-endian 转换为 big-endian)。 |
此示例的另一个要点是,当通信另一端的套接字应用程序为非 mfc 应用程序时,必须避免出现如下列语句的操作:
ar pmsg;
这里的 pmsg 是指向从 cobject 类派生的 c++ 对象的指针。这将发送多余的与对象关联的 mfc 信息,而服务器并不理解这些信息,因为只有服务器是 mfc 应用程序时才理解。
有关更多信息,请参见:
Java Asp PHP .Net XML C/C++ CGI VB Jsp J2ee J2se J2me EJB Servlet Tomcat Resin Struts Weblogic Eclipse ANT GUI JMS Web servise IDEA Webphere Hibernate Spring Jboss Applet Swing Socket Javamail Perl Ajax P2P 安全 模式 框架 测试 开源 游戏
Windows XP Windows 2000 Windows 2003 Windows Me Windows 9.x Linux UNIX 注册表 操作系统 服务器 应用服务器