通过用C套接字传递结构通过用C套接字传递结构(Passing a structure through

2019-05-06 14:53发布

我想整个结构传递从客户端到服务器或反之亦然。 让我们假设我的结构如下

struct temp {
  int a;
  char b;
}

我使用SENDTO和发送所述结构变量的地址,并使用recvfrom函数接收它在另一侧上。 但我没能获得在接收端发送的原始数据。 在SENDTO功能,我接收到的数据保存到类型结构温度的变化。

n = sendto(sock, &pkt, sizeof(struct temp), 0, &server, length);
n = recvfrom(sock, &pkt, sizeof(struct temp), 0, (struct sockaddr *)&from,&fromlen);

其中PKT是类型结构温度的变化。

Eventhough我接收数据的8个字节,但如果我尝试打印它只是显示垃圾值。 任何帮助就可以修复?

注: 没有第三方库都可以使用。

EDIT1:我真的很新的这系列化概念。但没有做系列化着我通过套接字发送结构?

EDIT2:当我尝试发送一个字符串或使用我正确接收在接收器端的数据SENDTOrecvfrom功能的整数变量。 为什么不能在一个结构的情况下? 如果我没有使用序列化功能的话,我应该把每单独结构的每个成员? 这确实是不适合的解决方案,因为如果有成员的“n”个号码,然后有加入的代码行的“n”个数目只是为了发送或接收数据。

Answer 1:

这是一个非常糟糕的主意。 二进制数据应该总是以一种发送:

  • 处理不同的字节顺序
  • 处理不同的填充
  • 在手柄的差异固有类型的字节大小

永远不要写一个整体结构以二进制的方式,而不是一个文件,而不是一个插座。

总是分开来写每个字段,并阅读他们以同样的方式。

你需要有类似的功能

unsigned char * serialize_int(unsigned char *buffer, int value)
{
  /* Write big-endian int value into buffer; assumes 32-bit int and 8-bit char. */
  buffer[0] = value >> 24;
  buffer[1] = value >> 16;
  buffer[2] = value >> 8;
  buffer[3] = value;
  return buffer + 4;
}

unsigned char * serialize_char(unsigned char *buffer, char value)
{
  buffer[0] = value;
  return buffer + 1;
}

unsigned char * serialize_temp(unsigned char *buffer, struct temp *value)
{
  buffer = serialize_int(buffer, value->a);
  buffer = serialize_char(buffer, value->b);
  return buffer;
}

unsigned char * deserialize_int(unsigned char *buffer, int *value);

或者等价,当然有几种方式与问候将此设为缓冲管理等。 然后,你需要做的序列化/反序列化整个结构更高级别的功能。

这是假定序列化是为了/从缓冲区,这意味着序列化并不需要知道,如果最终目的地是一个文件或插座。 这也意味着你付出一些内存开销,但它通常是出于性能方面的一个好的设计(你不想做的每个值的写入()到插座)。

一旦你有以上,这里是你如何序​​列化和传输结构实例:

int send_temp(int socket, const struct sockaddr *dest, socklen_t dlen,
              const struct temp *temp)
{
  unsigned char buffer[32], *ptr;

  ptr = serialize_temp(buffer, temp);
  return sendto(socket, buffer, ptr - buffer, 0, dest, dlen) == ptr - buffer;
}

有几点需要注意上述:

  • 要发送的结构是第一序列,逐个字段,进入buffer
  • 序列化程序返回缓冲区中的指针指向下一个空闲的字节,我们用它来计算它有多少字节序列化到
  • 显然,我的例子序列化程序不能防止缓冲区溢出。
  • 返回值是1,如果sendto()调用成功,否则这将是0。


Answer 2:

使用“附注”组选没有解决我的问题,但我不知道它是否有任何依赖?

#pragma pack(1)   // this helps to pack the struct to 5-bytes
struct packet {
int i;
char j;
};
#pragma pack(0)   // turn packing off

然后下面的代码行制定了罚款没有任何问题

n = sendto(sock,&pkt,sizeof(struct packet),0,&server,length);

n = recvfrom(sock, &pkt, sizeof(struct packet), 0, (struct sockaddr *)&from, &fromlen);


Answer 3:

如果你不想自己写的序列化代码,找到一个妥善的序列化框架,并使用它。

也许谷歌的协议缓冲区将是可能的?



Answer 4:

有没有必要写自己的序列化程序shortlong整数类型-使用htons() / htonl() POSIX功能。



Answer 5:

序列化是一个好主意。 您也可以使用Wireshark的监测交通并了解在实际的数据包通过。



Answer 6:

相反连载并根据第三方的库它很容易想出了使用标签,长度和值原始协议。

Tag: 32 bit value identifying the field
Length: 32 bit value specifying the length in bytes of the field
Value: the field

根据需要拼接。 使用枚举的标签。 并使用网络字节序...

易编码,便于进行解码。

此外,如果你使用TCP记住它是数据 ,如果你发送如3个数据包,所以你不一定会得到3个数据包。 他们也许可以“合并”成视NODELAY /格尔算法除其他事项外流,你可以让他们都在同一个recv的......你需要使用RFC1006来分隔数据的例子。

UDP是容易,您会收到我们发送的每个数据包不同的数据包,但它少了很多安全。



Answer 7:

如果要传输的数据格式是非常简单的,然后转换为和ANSI字符串是简单便携。



文章来源: Passing a structure through Sockets in C