C++ C/C++;从字符缓冲区读取以填充结构

C++ C/C++;从字符缓冲区读取以填充结构,c++,c,sockets,struct,scanf,C++,C,Sockets,Struct,Scanf,我有一条通过UDP套接字发送的消息。消息的类型为RPCMessage typedef struct { enum {Request, Reply} messageType; unsigned int RPCId; unsigned int procedure; int arg1; int arg2; } RPCMessage; 当我发送或准备发送消息时,我按如下方式构造消息: RPCMessage toSend = {RPCMessage::Reply,

我有一条通过UDP套接字发送的消息。消息的类型为RPCMessage

typedef struct
{
    enum {Request, Reply} messageType;
    unsigned int RPCId;
    unsigned int procedure;
    int arg1;
    int arg2;
} RPCMessage;
当我发送或准备发送消息时,我按如下方式构造消息:

RPCMessage toSend = {RPCMessage::Reply, htonl(rpcId), htonl(procedureId), htonl(int1), htonl(int2);
当我收到消息时,它被接收到一个char[]I call缓冲区中。有人建议,与其将整个缓冲区强制转换为一个RPCMessage,不如让我从缓冲区中逐个读取每个参数,然后将第一个参数作为正确的枚举类型,并在每个参数上使用ntohl。这样做的最佳方式是:

RPCMessage::messageType type;
unsigned int id, procedure;
int int1, int2;
sscanf(buffer, %d%d%d%d%d, type, id, procedure, int1, int2);
RPCMessage received = {type, ntohl(id), ntohl(procedure), ntohl(int1), ntohl(int2));

或者有其他/更好的方法吗?

最好的方法是使用健壮的序列化框架,如boost序列化


这取决于消息的复杂程度。

我建议强制转换为结构。主要原因-性能

几乎总是可以在结构布局和缓冲区中的数据之间实现二进制兼容性。有一些控件可以控制填充和对齐等。C++中有专门的对齐规范。 我不想说只要施放,问题就会消失。您仍然需要处理字节顺序,字符repr可以不同,等等


当您希望对结构进行不同的重复时,或者当您的数据结构很复杂(如结构树)时,应该使用序列化。

消息不会那么复杂(请参见上面对RPCMessage的定义…它是1个枚举和几个整数)。是否有任何公共图书馆设施或任何可能工作的东西?我觉得对于像我这样一个相当小的程序来说,学习/使用整个序列化框架可能有点过头了。如果没有指针或非POD类型,那么是的,使用boost可能有点过头了。我看到的使用sscanf的唯一问题是,信息是通过文本发送的,这对于带宽来说不是最优的。同样,如果消息很小且数量不多,那也没关系。我不同意你所说的
你几乎总能实现二进制兼容性
-从什么时候开始?您是否曾在多拱门环境中工作过?将其转换为结构很快,但非常不适合。在机器和编译器之间存在不同的结构打包问题、字节交换问题、边界要求等。有
#if
来说明这一点。在不同的平台之间移动二进制结构总是一项额外的工作。如果读取它们的代码被编写为可移植的,就不需要这样做。如果操作得当,您可以编写仍能执行的可移植代码,但这比“平台定义”带来的更谨慎和自律。我个人曾观察过塔塔if的承包商在“移植”代码时在七个平台上进行深度拦截,而你从中得到的只是一团混乱。做对了,做一次,它就会一直起作用。“做对了”太抽象了
#if
很容易被滥用。然而,这并不是停止使用它的理由。结构的二进制布局是不可移植的。