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