C套接字发送/接收缓冲区类型
C sockets send/recv buffer type
我正在使用unix套接字,当我的缓冲区为char类型时,我可以发送()和recv()数据。发送和接收字符串)。我使用Beej的套接字指南,使用的示例是用于发送/接收字符串。
现在我想在一条消息中发送/接收不同类型的数据。
例如,在一条消息中,我想发送一个整数,一个字符串,一个双精度和一个浮点数。我该怎么做呢?更具体地说,我的消息"缓冲区"应该是什么类型?
send和recv的原型:
int recv (int socket, void *buffer, size_t size, int flags)
int send (int socket, void *buffer, size_t size, int flags)
我对C/c++和指针没有太多的经验,所以这可能是一个新手问题。
如果有人能指引我正确的方向,我将非常感激。由于除非您计划发送大量数据(数千字节)并且经常(每秒几个数据包),否则我建议您将数据转换为字符串(又名"序列化数据")并以这种方式传递。它有几个好处:
- 它是可移植的-无论
int
或float
或double
是什么大小-或者字段之间的填充在结构中。 - 很容易调试(你可以看看数据,说它是对还是错)
- 发送/接收机器的字节顺序无关紧要。
double
如何以二进制表示,结构内数据字段的填充,不能传递指针,等等)。唯一的好处是二进制数据更加紧凑。但是,只有当您有很多kb和/或每秒发送大量数据包时,这才有意义。 您需要在发送端序列化对象,并在接收端反序列化。c++中有很多这样的库,比如Boost Serialization,如果你想重新发明轮子,你可以自己动手。
最好的方法是将想要传递的信息封装在一个结构中。然后传递结构的地址和长度。注意,buffer
是一个void*
,所以这允许你传递包含你的信息的结构的地址。
struct
的一小段代码,例如工具,
struct message
{
size_t total_len;
size_t filename_len;
char *filename;
size_t text_len;
char *text;
char *iv;
char *salt;
unsigned char *hmac;
};
然后在send_message()
中将message
和write
序列化为socket
bool send_message(const struct message *msg, const char *ip, const char *port)
{
...
connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
// Serialize to file
serialize(msg, "temp");
// Transfer the file over the network
fp = fopen("temp", "rb");
while((n = fread(buffer, 1, MAX_BUF_LEN, fp)) != 0)
{
write(sockfd, buffer, n);
}
fclose(fp);
remove("temp");
close(sockfd);
}
根据@vitaut的建议,您可以使用库来serialize
,我已经实现了它作为学习经验。
要回答这个问题("我如何发送结构体?"),你只需发送一个指向结构体的指针。
struct foo
{
int a;
int b;
};
struct foo s;
s.a = 10;
s.b = 20;
send(socket,&s,sizeof(s),0);
真的很简单。现在,另一边必须是相同的(也就是说,系统A内存中布局的结构必须与系统B内存中布局的结构匹配)。更好的方法是使用更具体的类型和一些函数来正确排序数据:
#ifndef __GNUC__
# define __attribute__(x)
#endif
#ifdef __SunOS
# pragma pack(1)
#endif
struct foo
{
uint32_t a;
uint32_t b;
} __attribute__((packed));
#ifdef __SunOS
# pragma pack()
#endif
struct foo s
/* to send */
s.a = htonl(10);
s.b = htonl(20);
send(socket,&s,sizeof(s),0);
/* to receive */
recv(socket,&s,sizeof(s),0);
s.a = ntohl(s.a);
s.b = ntohl(s.b);
你可以看到,当你想通过网络"可移植"地发送二进制数据时,它开始变得相当快地特定于系统,这就是为什么人们说要转换为文本,或者很可能使用已经编写好的序列化库。
这取决于它的可移植性。
最简单的方法是将所有内容转换为用逗号或分号分隔的ASCII,然后在接收端再次解析。
您也可以将其转换为网络字节顺序并以二进制形式发送。
- 如何分配适合容纳 T 类型对象的缓冲区(可能过度对齐、可能有运算符 new 等)
- 缓冲区填充了不同类型的数据和严格的混叠
- 如何在运行时从平面缓冲区获取数据值和数据类型
- 与 CLOB 兼容的 Pro-C 缓冲区类型
- 在C 中,是否有可能在不兼容类型的std ::向量对象之间传输不同类型的缓冲区
- 小标量类型和谷歌协议缓冲区
- 操作方法:将 boost::endian 缓冲区类型转换回本机格式
- 抽象数据类型命名约定:(动态)数组,向量,序列,列表,容器,缓冲区
- 谷歌协议缓冲区,如何设置自定义类型的字段
- 具有不同顶点输入类型的多个着色器是否可以使用相同的顶点缓冲区
- 为什么VxWorks中的缓冲区sendto()和send()函数的类型不同,以及我如何以相同的方式处理它们
- 我想复制 (wchar_t *) 缓冲区中的数据,但我无法这样做 bcz 还有其他不兼容的类型,类型转换但没有得到结果
- 将大内存大小分配给int类型的缓冲区
- winsock,面向消息的网络,以及从recv中类型转换缓冲区
- 协议缓冲区,让C#与C++对话:类型问题和模式问题
- 实现任意类型擦除的小缓冲区优化的简单方法(如std::function.)
- Reinterpret_cast从缓冲区转换为类型
- 将字符缓冲区类型转换为来自套接字的结构
- c++中的动态(类型)二进制缓冲区
- C套接字发送/接收缓冲区类型