socket 可以传输结构体吗?

2023-06-13 09:48:24 +08:00
 sbldehanhan

例如: 结构体: struct test { int a; char b[1024]; float c; }; 数据: struct test data; 发送: send(sockfd, &data, sizeof(data), 0); 接收: recv(connfd, &data, sizeof(data), 0);

5165 次点击
所在节点    C
50 条回复
xiangyuecn
2023-06-13 09:51:37 +08:00
什么结构体不结构体,最终都是 序列化、反序列化
throcean
2023-06-13 09:52:54 +08:00
当然可以了
eMvKtXL36Ft5mIaV
2023-06-13 09:53:45 +08:00
可以的,属性没有指针就正常
luvfinn
2023-06-13 09:54:44 +08:00
这边封包传过去,那边解包后挂一个指针数据不就读出来了吗
changnet
2023-06-13 09:55:07 +08:00
当然可以。不过这时候就得考虑内存对齐了,结构体是否为 POD 类型了。
tool2d
2023-06-13 09:55:13 +08:00
需要先传结构体大小,recv 有可能只接受一般数据。
tool2d
2023-06-13 09:56:25 +08:00
recv 有可能只接收一半数据。

你可以多看看实际例子,都是要封装一次的。
hankai17
2023-06-13 09:59:26 +08:00
粘包警察在此
dynos01
2023-06-13 10:02:31 +08:00
不建议就这样直接把结构体发出去,因为要考虑内存对齐,字节序,后续拆分也麻烦。推荐的办法是序列化成字符串(比如 JSON ,或者你自己定义一个也行)发出去,对端再还原回来。
NessajCN
2023-06-13 10:02:53 +08:00
结构体是语言特性,编译完了就只是连续的数据而已
你例子里的 struct test 来说,其实就是占据了 4+1*1024+4 个字节的一串 1010101 数字而已
你在接收端也定义同样的 struct 后,recv()函数就把那串数字按结构体定义分配到变量所在的地址
fgwmlhdkkkw
2023-06-13 10:05:53 +08:00
发结构化的数据,可以不需要带长度信息。你可以直接发 json……
dynos01
2023-06-13 10:07:58 +08:00
@dynos01 更正一下说法,不一定是字符串,也可以是一段字节。比如一种简单的设计:先 8 个字节传结构体大小,再 4 个字节传 a ,再直接把 b 放进去,最后 4 字节传 c 。对端拆分也好拆分,因为知道总大小,就可以确定接受这么多字节的数据,接着就能拿出三个字段并还原出结构体。涉及大端 /小端的地方一律用网络序,保证兼容性。

当然最简单的还是去找个序列化 /反序列化库。
Nazz
2023-06-13 10:09:24 +08:00
这种原始的方式很容易崩吧
hahastudio
2023-06-13 10:14:14 +08:00
可以的,不过推荐你看一看 protobuf
Metre
2023-06-13 10:16:02 +08:00
可以,注意不同操作系统大小端对齐
BBCCBB
2023-06-13 10:17:47 +08:00
去看一下序列化和反序列化的概念. 你就懂了
Guaidaodl
2023-06-13 10:21:28 +08:00
socket 就是传二进制数据. 结构体是更上层的抽象啊.

你要先把结构体转化成二进制数据. 然后再解析出来. 也就是楼上说的序列化和反序列化的概念.
haikea
2023-06-13 10:21:47 +08:00
可以传,你自己定好协议就行,比如数据包从哪一位到哪一位是结构体,结构体怎么解析
Guaidaodl
2023-06-13 10:23:05 +08:00
至于如何把结构体转化成二进制数据, 这个方法就实在太多了. 比如直接平铺数据, 或者用 ProtoBuf 协议. 甚至可以将结构体转换成 JSON 字符串再转成 utf-8 的流
kagetu
2023-06-13 10:23:47 +08:00
我觉得你能问这个问题,可能与我当初无法理解“报文”是个什么概念差不多,不知道自己到底有没有收到这个叫“报文”的东西,后来理解了(也不知道是不是真理解)才知道其实就是指发送的数据,只不过是一个名字的问题。
那么再回来看你的这个问题,send 的操作不管你是要发送结构体还是其它什么,都只是把对应内存地址里的数据弄成 01100101 这样发给对方,对方用 recv 接收到这些 01100101 后放到自己的内存里。
那对方怎么知道这些 01 是什么呢,前提就是你和对方已经商量好这次发送的是什么。对于你的结构 test ,对方也需要有一个同样的结构 test ,然后 struct a = {0}; recv(connfd, &a, sizeof(a), 0); ,或者 memcpy(&a, &data, sizeof(struct test_b);大概这样就可以了。
那如果你还有一个 struct test_b ,想要判断到底发 a 还是发 b ,有很多种方法,比如在发送的数据前加一位标志。这个标志 0 就代表后面的数据是 test ,如果是 1 就代表后面的数据是 test_b 。接收方先判断第一位数据是 0 还是 1 ,然后根据结果读取到对应结构。这个 1 你可以用 int ,或者 short ,那对方判断时也记得要对应的用 int 或者 short 。

如有错误之处,还望谅解。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/948216

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX