2011-06-05 55 views
3

我目前有一个基本的客户端/服务器设置。服务器需要从客户端获取请求并需要响应不同的请求消息类型。客户端请求的一个例子可能是获取可用文件列表,还有多少其他客户端连接到服务器等。这在C/C++套接字通信中是否合理?

我显然必须找出一种方法来确定从接收到的消息中的消息类型发件人。我想知道,如果我有一个用必要数据定义的结构,那么我是否可以将结构强制转换为void *,通过发送(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; 

忽略这些小的语法问题,任何人都可以建议这个方案是否可行?如果没有,是否有任何其他方式来传递消息而不发送原始char *?

回答

4

这是完全可能的。不过,不建议这样做,因为现在你为客户端和服务器使用了相同的环境,但将来可能会更改,并且必须将此代码更改为更独立于平台/实现。

选项? boost :: serialization,XML-RPC,甚至HTTP/REST或任何其他适合您的高级协议,Google协议缓冲区,CORBA等。

1

有两点需要注意:

  1. Endianness。如果你的客户端和服务器的排列顺序各有差异,那么你将处于无法通信的状态。鉴于今天对x86系统的高度重视,您可能会说服自己对此限制感到满意。如果我是你,我至少会建立一个验证。例如,在每个通信会话开始时发送一个已知的校验和,例如0xdeadbeef。这将允许您声明客户端和服务器之间的字节序相同,希望避免会话的继续和各种潜在的错误。

  2. Word Size。这是你为什么不应该做你想做的事情的更阴险和更强大的原因。除非你强烈断言发送者和接收者的字数永远不会不同,否则你的方法充满了危险。考虑你有一个结构如下:

    struct some_msg { long payload; };

    当32位的gcc/linux系统发送该消息给一个gcc/Linux 64位系统,会发生什么?那么,在32位系统上,它将愉快地发送4个字节的数据。但是,64位系统会将结构覆盖到8个字节的数据上。坏消息是熊。

尽管从x86转换到sparc可能不太可能,但随着时间的推移,系统将会变为64位。不管你有没有传统的32位系统,我都不知道,但是对于客户端和服务器都没有严格的控制,它几乎可以保证你将拥有一个混合字大小的环境。

如果您非常明确地定义和控制正在使用的平台,我相信它可以工作。此外,您可以通过使用固定大小的类型定义(如int32_tuint64_t)来限制风险。如果你这样做,你正在玩火,海事组织。任何可想象的优势都可以通过将您的设计高度锁定到系统中而迅速降低。

+0

另一个,甚至可能更糟的问题:填充字节。 C++编译器有时会在结构的成员之间添加'不可见'填充字节,以便为目标CPU提高内存访问效率。填充不是标准化的,所以它可以在一个编译器和另一个编译器之间,或者在同一个编译器的两个版本之间,甚至在来自同一个编译器版本的构建之间(特别是如果它们使用不同的优化级别构建时)不同地完成。因此,除非连接的两端都运行完全相同的可执行二进制文件,否则事情可能会中断。 – 2011-06-05 18:35:48

+0

对齐在给定的ISA ABI上是标准化的,并且在任何实字机器上,填充是对齐所需的最小值。而且,对于真实世界机器上的几乎所有类型,对齐都是类型的大小。对齐必须总是*均匀地分割*类型的大小(由于C数组表示语义),所以如果设计的结构是这样的,那么在没有填充的情况下,每个元素将以其大小的倍数开始,那么你可以基本确定没有填充。 – 2011-06-05 18:52:55

0

'可以将结构强制转换为void *,通过发送(sockfd,message,length,flags)系统调用,并且在接收端将其转发回结构' - 参见迭戈的答案。请注意,如果在流中插入/删除/更改了一个额外的随机字节,则无法恢复或更糟糕的任何协议实际上会使服务器崩溃,但安全性不足,无法通过TCP传输。

'如果不是,有没有其他的方式来传递消息而不发送原始字符*?'一个协议的唯一替代方案是可以可靠地,合理地重新组合来自一个字节(八位字节),strean的消息,即在每条消息之后断开/重新连接以便终止流。这个方案的性能/延迟正是你所期望的 - 真的很差。

RGDS, 马丁