这在 C/C++ 套接字通信中是不是合理?
Posted
技术标签:
【中文标题】这在 C/C++ 套接字通信中是不是合理?【英文标题】:Is this plausible in C/C++ socket communication?这在 C/C++ 套接字通信中是否合理? 【发布时间】:2011-06-05 17:35:37 【问题描述】:我目前有一个基本的客户端/服务器设置。服务器需要接受来自客户端的请求,并且需要响应不同的请求消息类型。客户端请求的示例可以是获取可用文件列表、有多少其他客户端连接到服务器等。
我显然必须想办法从发件人收到的消息中确定消息的类型。我想知道,如果我有一个定义了必要数据的结构,是否可以将结构转换为 void*,通过 send(sockfd, message, length, flags) 系统调用发送它,而不是在接收方,转换它回到结构。这当然假设我在同一环境中运行客户端和服务器。
例如,如果我有以下结构:
struct message
enum messageType GET_FILES, GET_CLINET_NUMBER messageType,
并使用此结构以下列方式发送消息
struct message msg;
msg.messageType = GET_FILES;
send(server_sockfd, (void*)&msg, sizeof(struct), 0)
在接收器上,
recv(,msg_buffer);
struct message received = (struct message*)msg_buffer;
忽略一些小的语法问题,谁能告诉我这个方案是否可行?如果没有,有没有其他方法可以在不发送原始字符 * 的情况下传递消息?
【问题讨论】:
【参考方案1】:这是完全可能的。不过不推荐,因为现在您为客户端和服务器使用相同的环境,但您将来可能会更改,并且您必须更改此代码以更加独立于平台/实现。
选项? boost::serialization、XML-RPC,甚至是 HTTP/REST 或任何其他适合您的高级协议、Google Protocol Buffers、CORBA 等。
【讨论】:
【参考方案2】:有两件事你需要非常注意:
Endianness。如果您的客户端和服务器的字节顺序各不相同,您将处于无法通信的情况。鉴于今天对 x86 系统的高度重视,您可能会说服自己对这种限制感到满意。如果我是你,我至少会建立一个验证。例如,在每个通信会话开始时发送一个已知的校验和,例如0xdeadbeef
。这将允许您断言客户端和服务器之间的字节序是相同的,希望避免会话继续和各种潜在的错误。
Word Size。这是你不应该做你想做的事的更阴险和更强有力的理由。除非您可以强烈断言发送者和接收者的字长永远不会不同,否则您的方法充满危险。考虑你有一个结构如下:
struct some_msg long payload; ;
当 32 位 gcc/linux 系统将该消息发送到 gcc/linux 64 位系统时会发生什么?好吧,在 32 位系统上,它会愉快地发送 4 个字节的数据。但是,64 位系统会将结构覆盖到 8 个字节的数据上。坏消息熊。
虽然您可能不太可能从 x86 切换到 sparc,但几乎可以肯定的是,随着时间的推移,您的系统将成为 64 位。我不知道你是否有旧的 32 位系统,但如果没有对客户端和服务器进行非常严格的控制,几乎可以保证你将拥有一个混合字长的环境。
如果您非常明确地定义和控制所使用的平台,我相信它可以工作。此外,您可以通过使用固定大小的 typedef(例如 int32_t
和 uint64_t
)来限制风险。 IMO,如果你这样做,你就是在玩火。将您的设计高度锁定到系统中会很快降低任何可以想象的优势。
【讨论】:
另一个可能更糟糕的问题:填充字节。 C++ 编译器有时会在结构的成员之间添加“不可见”的填充字节,以提高目标 CPU 的内存访问效率。填充不是标准化的,因此它可以在一个编译器和另一个编译器之间,或者在同一编译器的两个版本之间,甚至在来自同一编译器版本的构建之间(特别是如果它们是使用不同的优化级别构建的)不同地完成。因此,除非连接的两端都运行完全相同的可执行二进制文件,否则事情可能会中断。 对齐在给定的 ISA ABI 上是标准化的,在任何实字机器上,填充是对齐所需的最小值。此外,对于现实世界机器上的几乎所有类型,对齐是类型的大小。对齐方式必须始终均分类型的大小(由于 C 数组表示语义),因此,如果您设计的结构使得在没有填充的情况下,每个元素将以它的大小,那么您基本上可以确定不会有填充。【参考方案3】:'可以将结构转换为 void*,通过 send(sockfd, message, length, flags) 系统调用将其发送,然后在接收方将其转换回结构' - 请参阅 Diego 的答案。请注意,如果流中插入/删除/更改一个额外的随机字节不够安全,无论是否通过 TCP 传输,任何无法恢复或更糟的协议实际上都会使服务器崩溃。
'如果没有,有没有其他方法可以在不发送原始字符*的情况下传递消息?'可以可靠且正确地从字节(八位字节)strean 重新组合消息的协议的唯一替代方案是在每条消息之后断开/重新连接,从而终止流。该方案的性能/延迟正是您所期望的 - 非常非常糟糕。
Rgds, 马丁
【讨论】:
以上是关于这在 C/C++ 套接字通信中是不是合理?的主要内容,如果未能解决你的问题,请参考以下文章
Apple 是不是允许使用套接字在两个 iOS 应用程序之间进行通信?