我正在做一个通过socket传递结构的C程序
这是我的结构
typedef struct{
char type; //message type
char* sender; //sender
char* receiver; //receiver
unsigned int msglen; //msg length
char* msg; //text
} msg_t;这是我的发送功能:
void send_message(int socket, char* msg)
{
msg_t message;
bzero(&message,sizeof(message));
message.msg = msg;
if(send(socket,&message,sizeof(msg_t),0) < 0)
{
perror("ERROR: send fail\n");
}
}这是我的接收功能:
msg_t rec_message(int socket)
{
msg_t buff;
bzero(&buff,sizeof(buff));
if(recv(socket,&buff,sizeof(buff),0) < 0)
{
perror("ERROR: receive failed\n");
}
return buff;}
当我像发送字符串一样发送消息时,一切正常,但是当我切换到结构时,客户端似乎发送了消息,然后给我以下内容:
ERROR: receive failed: connection reset by peer而服务器这个:
ERROR: receive failed: invalid argument我做错了什么?
发布于 2014-05-13 08:00:12
这个问题有几个问题需要解决。也许最好首先关注msg_t结构本身。这是一个模型,它看起来可能是什么样子;无论是在内存中,还是在传输时的“连线上”:

根据以上所述,msg_t的长度为40字节。这可以通过打印出它的大小来确认:
printf("sizeof(msg_t): %zd\n", sizeof(msg_t));“那么,这些空白砖是怎么回事呢?”
为了使事情在运行时快速,编译器‘对齐’在'msg_t‘结构中的每个字段在CPU寻址体系结构的“自然/本地”偏移。在我的64位系统上,这意味着每个structure字段将在一个8字节偏移量上对齐;即使它意味着在结构中留下空的未使用的空间。注意,结构字段的偏移量是: 0、8、16、24、32;所有8字节的倍数。
在32位系统上,您可能会发现这些偏移量是4个字节的倍数。
虽然结构字段的8字节对齐是内存访问的最佳方式,但当结构通过导线发送时,就不是很好了。线/协议结构最好以1字节对齐,从而消除了结构中未使用的“填充”字节。
更改结构对齐(支持我的许多编译器,但可能不是C语言本身定义的)的一种方法是‘#杂注包();它用于如下所示:
#pragma pack(1)
typedef struct{
char type; //message type
char* sender; //sender
char* receiver; //receiver
unsigned int msglen; //msg length
char* msg; //text
} msg_t;
#pragma pack()在上面的结构定义中,第一个‘#杂注包(1)’导致以下结构对齐1字节。下一个‘#杂注包()’将编译器返回到默认的8字节对齐默认值。这种“打包”的结构如下所示:

接下来,检查结构中的字段。“发件人”字段是“char*”。char*是一个地址,发送者字符串可以在“发送”机器(或端点)上找到。坦率地说,这个“地址”对“接收者”机器(或端点)毫无价值;因为“接收方”无法访问“发件人”的内存。
“接收者”字段和“msg”字段也是如此。所有这些都是“发件人”机器上字符串的地址,对“接收者”机器没有任何价值。
最有可能的是,“意图”是发送实际的“发送方”、“接收方”和“msg”字符串。为此,可以使用类似于以下结构的结构:
#pragma pack(1)
typedef struct{
char type; //message type
char sender[15]; //sender
char receiver[15]; //receiver
char msg[30]; //text
} msg_t;
#pragma pack()这个结构看起来如下:

现在,实际的字符串在结构中,而不仅仅是它们在内存中的地址。这样就能达到预期的效果。
不幸的是,它确实限制了每个字符串的长度;它还包含大量未使用/浪费的空间。也许最好能消除这一限制,允许更多的灵活性。最好这样发送这些字段:

请注意,每个“可变长度”字符串都以一个字节作为前缀,该字节指示后面字符串的长度。(这就是如何在PASCAL语言中存储字符串)。此字节允许以下字符串从0-255字节长.电线上没有浪费空间。
不幸的是,这种“线格式”不能直接使用C结构生成。
现在让我们看一下问题中定义的结构;稍作修改:
typedef struct{
char type; //message type
char* sender; //sender
char* receiver; //receiver
char* msg; //text
} msg_t;请注意,我通过删除‘#杂注包()’的内容,将结构返回到它的自然/本地8字节对齐。我还删除了“msgLength”字段(它并不是真正需要的)。
最有可能的情况是,结构的发送方、接收者和msg字段将被初始化为指向字符串(可能是使用malloc()等分配的)。使用上面高效的布局,通过导线发送这个结构的方法是将每个字段单独发送出去。
首先,发送一个字节“type”。然后发送发送方'string‘的一个字节长度[即:strlen(发送方)+ 1)。然后发送‘发件人’字符串,然后是接收方字符串的一个字节长度,然后是‘接收者’字符串,然后是'msg‘字符串的一个字节长度,然后是'msg’字符串。
在“接收方”端点上,您首先读取一个字节的“type”(这将提示您,后面将有三个“长度优先”字符串)。读取下一个字节将告诉您以下字符串的大小(并允许您将malloc()内存转到接收端点的msg_t结构的“发送方”字段)。然后将“发件人”字符串读入正确大小的malloc()ed内存中。同样读取接收方字符串长度和接收方字符串;最后,读取msg长度和字符串。
如果发现PASCAL字符串(限制在255个字节以内)有点紧,请将长度-前缀值从一个字节更改为多个字节。
https://stackoverflow.com/questions/23612062
复制相似问题