我必须通过网络传输一些值以用作命令,并且我希望使其尽可能高效和健壮,即我需要对这些命令使用什么提出意见,#defines 或 enums?
命令的范围不应超过 20 个命令(假设每个定义的命令响应为 40 个),因此根据我听到的大多数内容,它非常适合 char 限制。
到目前为止,我假设最好的方法是使用枚举。
我必须通过网络传输一些值以用作命令,并且我希望使其尽可能高效和健壮,即我需要对这些命令使用什么提出意见,#defines 或 enums?
命令的范围不应超过 20 个命令(假设每个定义的命令响应为 40 个),因此根据我听到的大多数内容,它非常适合 char 限制。
到目前为止,我假设最好的方法是使用枚举。
在互联网上传输数值时,您需要记住两件事。
第一个是字节序,即字节(或有时位)出现的顺序。假设您有 32 位值 0xAABBCCDD。Intel CPU 是 little-endian 机器,这意味着这些字节将存储为 { 0xDD, 0xCC, 0xBB, 0xAA }。换句话说,最低有效字节存储在最低地址。在大端机器中,字节将存储为 { 0xAA, 0xBB, 0xCC, 0xDD },最低有效字节位于最高地址。
在两台机器之间传输多字节整数时,您必须确保它们都正确解释彼此的数据,即使它们具有不同的字节顺序。值得庆幸的是,有一个称为网络字节顺序的标准,它是大端序,并且有 4 个有用的函数可以在主机顺序和网络顺序之间进行转换:
ntohl(网络到主机,长)
ntohs(网络到主机,短)
htonl(主机到网络,长)
htons(主机到网络,短)
长版本使用 32 位整数,短版本使用 16 位整数。只要您在通过网络传输数据之前始终调用 *hton** 并在从网络读取时调用 *ntoh** ,数据就会以正确的字节顺序排列。
当然,解决这个问题的最简单方法,特别是因为你只有 20 个命令,是只使用单个字节或char s。
您必须处理的第二个问题是编码。有符号整数如何表示?使用符号位?二进制补码?同样,当网络上的不同平台使用不同的表示时,您会遇到问题。如果您坚持使用无符号类型,那么您应该没有问题。
你在程序中使用什么来表示你的命令完全取决于你。只需确保您定义好协议并在传输和读取数据时遵守该协议。
例如:
enum command_t { one, two, three }
void send_command(command_t c) {
send((unsigned char)c);
}
command_t read_command() {
return (command_t)recv();
}
void send(unsigned char c) { ... }
unsigned char recv() { ... }
从效率的角度来看,它没有任何区别。#define 或 enum 只是分配数值的一种方式……真正的诀窍是如何将该值打包到网络上。
也就是说,我同意我在这里看到的其他答案,而且我认为无论如何你都在担心错误的事情。设计网络协议需要深思熟虑,使其在许多系统中可移植和可用通常应该优先考虑效率问题(当然,该规则也有例外)。
我还建议使用基于行分隔的基于文本的协议。除了不必担心enum
-vs。#define
值,还有其他一些好处:
为基于文本的协议手动生成一组命令非常容易。考虑在 HTTP 服务器上测试错误情况:
$ telnet www.yahoo.com 80
Trying 69.147.76.15...
Connected to www-real.wa1.b.yahoo.com.
Escape character is '^]'.
GOAT / HTTP/1.1
我不需要任何花哨的东西来理解服务器是如何响应的:
HTTP/1.1 400 Bad Request
Date: Sat, 11 Jul 2009 16:20:59 GMT
Cache-Control: private
Connection: close
Transfer-Encoding: chunked
Content-Type: text/html; charset=iso-8859-1
这非常适合调试。您可以创建一组测试脚本来输入telnet
/ nc
,它们将比任何二进制协议测试脚本更容易维护。
如果您根据 ASCII 文本(或者可能是 UTF-8)来定义您的协议,那么您永远不必担心新平台上的低级别问题。处理二进制协议时,字节序、结构对齐和字长都是问题。ASCII 可能需要一个额外的序列化/反序列化步骤,但在通常需要的网络协议中。
如果您想与其他人一起在一个项目上工作,能够将网络操作描述为纯文本是很棒的。如果其他人想开发自己的客户端,则不需要他们使用您的头文件或任何东西,他们只需要遵守类似 RFC 的标准。这对于宠物项目没有用处,但对于任何可能变得更大的项目来说,这是一件好事。
你要意见吗?我的意见是您应该使用基于文本的协议,其中每个命令都是一个关键字。是否以及如何将它们转换为程序中的枚举取决于您,但在网络级别上,使用基于文本的命令意味着您的协议更具可扩展性。
许多现实生活中的协议都是基于文本的,我敢说它们的工作效率很高。例如,HTTP、FTP、SMTP 等都是基于文本的。