例如: 结构体: struct test { int a; char b[1024]; float c; }; 数据: struct test data; 发送: send(sockfd, &data, sizeof(data), 0); 接收: recv(connfd, &data, sizeof(data), 0);
1
xiangyuecn 2023-06-13 09:51:37 +08:00 5
什么结构体不结构体,最终都是 序列化、反序列化
|
2
throcean 2023-06-13 09:52:54 +08:00
当然可以了
|
3
eMvKtXL36Ft5mIaV 2023-06-13 09:53:45 +08:00
可以的,属性没有指针就正常
|
4
luvfinn 2023-06-13 09:54:44 +08:00
这边封包传过去,那边解包后挂一个指针数据不就读出来了吗
|
5
changnet 2023-06-13 09:55:07 +08:00
当然可以。不过这时候就得考虑内存对齐了,结构体是否为 POD 类型了。
|
6
tool2d 2023-06-13 09:55:13 +08:00
需要先传结构体大小,recv 有可能只接受一般数据。
|
7
tool2d 2023-06-13 09:56:25 +08:00
recv 有可能只接收一半数据。
你可以多看看实际例子,都是要封装一次的。 |
8
hankai17 2023-06-13 09:59:26 +08:00 4
粘包警察在此
|
9
dynos01 2023-06-13 10:02:31 +08:00 via iPad 1
不建议就这样直接把结构体发出去,因为要考虑内存对齐,字节序,后续拆分也麻烦。推荐的办法是序列化成字符串(比如 JSON ,或者你自己定义一个也行)发出去,对端再还原回来。
|
10
NessajCN 2023-06-13 10:02:53 +08:00
结构体是语言特性,编译完了就只是连续的数据而已
你例子里的 struct test 来说,其实就是占据了 4+1*1024+4 个字节的一串 1010101 数字而已 你在接收端也定义同样的 struct 后,recv()函数就把那串数字按结构体定义分配到变量所在的地址 |
11
fgwmlhdkkkw 2023-06-13 10:05:53 +08:00
发结构化的数据,可以不需要带长度信息。你可以直接发 json……
|
12
dynos01 2023-06-13 10:07:58 +08:00 via iPad
@dynos01 更正一下说法,不一定是字符串,也可以是一段字节。比如一种简单的设计:先 8 个字节传结构体大小,再 4 个字节传 a ,再直接把 b 放进去,最后 4 字节传 c 。对端拆分也好拆分,因为知道总大小,就可以确定接受这么多字节的数据,接着就能拿出三个字段并还原出结构体。涉及大端 /小端的地方一律用网络序,保证兼容性。
当然最简单的还是去找个序列化 /反序列化库。 |
13
Nazz 2023-06-13 10:09:24 +08:00 1
这种原始的方式很容易崩吧
|
14
hahastudio 2023-06-13 10:14:14 +08:00
可以的,不过推荐你看一看 protobuf
|
15
Metre 2023-06-13 10:16:02 +08:00
可以,注意不同操作系统大小端对齐
|
16
BBCCBB 2023-06-13 10:17:47 +08:00 1
去看一下序列化和反序列化的概念. 你就懂了
|
17
Guaidaodl 2023-06-13 10:21:28 +08:00
socket 就是传二进制数据. 结构体是更上层的抽象啊.
你要先把结构体转化成二进制数据. 然后再解析出来. 也就是楼上说的序列化和反序列化的概念. |
18
haikea 2023-06-13 10:21:47 +08:00
可以传,你自己定好协议就行,比如数据包从哪一位到哪一位是结构体,结构体怎么解析
|
19
Guaidaodl 2023-06-13 10:23:05 +08:00
至于如何把结构体转化成二进制数据, 这个方法就实在太多了. 比如直接平铺数据, 或者用 ProtoBuf 协议. 甚至可以将结构体转换成 JSON 字符串再转成 utf-8 的流
|
20
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 。 如有错误之处,还望谅解。 |
21
bthulu 2023-06-13 10:26:38 +08:00 4
传结构体不知道, 我一直在研究怎么通过 socket 传送小动物, 研究好了我就能做传送阵了.
|
22
coderxy 2023-06-13 10:26:41 +08:00
结构体是你这个语言的概念, 对于网络设备来说,都是二进制数据流。
|
23
kagetu 2023-06-13 10:29:55 +08:00
所以复杂的地方还不只在于你能不能发送结构,你还要和对方商量后怎么识别到底发的什么,要发送的数据有多大,比如你发了 8 个 00001111 ,由于网卡了一下,对方只接收到了前 4 个 0000 就以后全接完了。那他读取时肯定就不对了。
所以除了在首位加个区别发送数据类型的标志,你可能还需要再加个发送的数据大小的。具体根据你的实际情况去自定义就可以了,一般是把数据的大小放在首位。 |
24
Maboroshii 2023-06-13 10:30:30 +08:00
大小端和对齐要处理好
|
25
gps949 2023-06-13 10:30:39 +08:00
传啥不是传二进制啊,只要你说的“结构体”和二进制间 encode 、decode 规则确定了,啥都行。这里面 encode 、decode 就涉及序列化、字符编码这些了。
|
26
xqdoo00o 2023-06-13 10:32:56 +08:00
建议看下 Protobuf 或者 FlatBuffers
|
27
nuk 2023-06-13 10:35:01 +08:00
如果是同一个程序可以,不然不同的编译器,不同的编译 flag 都会造成差异
|
28
lincanbin 2023-06-13 10:40:11 +08:00
序列化就可以,json 或者 pb 或者其他
|
29
duke807 2023-06-13 10:43:42 +08:00 via Android
|
30
sbldehanhan OP @coderxy 我可能没表达清除。我知道可以传,其实我是想知道这样传输会不会有什么问题?例如粘包、字节序和内存对齐什么的,我不太清楚在这里会不会造成影响。
|
31
sbldehanhan OP @duke807 好的。
|
32
wildman9527 2023-06-13 11:15:47 +08:00
最简单的方法: 把 4 字节指针传过去就好了, 通过指针远程调用, 当然这样也有不好的地方就是: 判断野指针不方便, 因为这个指针太野了.
|
34
JiRouWaZi 2023-06-13 11:28:20 +08:00
本质就是发二进制 ; 你可以直接发结构体的二进制 或者 发字符串这个二进制编码的一个高级格式
楼上说的大小端判断是因为 cpu 的一些特性,接受方的设备和发送方的特性不一致 |
35
huluye 2023-06-13 11:35:45 +08:00 via iPhone
最好还是要做一下序列化和反序列化。直接把结构体地址交给 socket 发送的话,结构体内部是否有引用到其他对象是需要考虑的,然后字节序也是个问题。
|
36
huluye 2023-06-13 11:38:21 +08:00 via iPhone
还有不同编译环境对结构体的字段对齐的处理也会有差异
|
37
fregie 2023-06-13 11:45:28 +08:00
tcp socket 传输的是字节流,就是一堆字节
你要自己把结构体编码成一堆字节用 socket 传给另一端,另一端再把这一堆字节解码成结构体 |
38
kenvix 2023-06-13 12:16:14 +08:00
最好是序列化,把内存数据直接传递除了要考虑楼上说的字节序、对齐,更大的问题是,如果链路不可信,数据被篡改后是要命的
|
39
mooyo 2023-06-13 12:20:42 +08:00
警惕粘包问题 socket 化
|
40
byaiu 2023-06-13 12:24:33 +08:00
粘包是有什么说法吗?
本来写网络程序就要处理流->用户可识别消息,不可避免会收到一半要等什么的。 这种处理为啥要含沙射影? |
41
duke807 2023-06-13 12:52:29 +08:00 via Android
|
42
ysc3839 2023-06-13 13:35:02 +08:00 via Android
@byaiu 因为有些教程误人子弟,硬是认为 TCP 发送的是数据包,接收时会“粘在一起”,然而 TCP 传的是字节流,本来就是连续的。
这就好比有个教程说,文件会“粘块”,写入文件时分两次写入了两块,下次读的时候会粘成一块读出来。 |
43
tomychen 2023-06-13 13:42:10 +08:00
粘包警出列
|
44
DreamSpace 2023-06-13 14:14:20 +08:00
@bthulu 如果有生物体可用的序列化 /反序列化方式的话,感觉也不是不行啊。
|
45
Jirajine 2023-06-13 14:26:00 +08:00
你的结构体不要太大,并且全部都是 inline 的字段,不要包含指针 /引用。
两边的程序和系统架构也要是一样的。 之前看到一个用 zig 写的分布式数据库就是这样做的,极致的 kiss ,cast bytes without parse. |
46
MeteorCat 2023-06-13 14:26:05 +08:00 via Android
每种语言都有序列化对象方法吧
|
47
MrKrabs 2023-06-13 16:02:06 +08:00
同一平台确实无所谓
|
48
siweipancc 2023-06-14 10:04:47 +08:00 via iPhone
网络 io 不也是 socket 吗。
|
49
sbldehanhan OP @kagetu 讲的很好。感谢。
|
50
alqaz 2023-10-25 13:44:41 +08:00
可以,考虑字节序和对其就行了。
|