我有一个来自线路的数据包,我有一个表示数据包的结构:
void decodePacket(char *packet) {
Connect *connect = NULL;
connect = (Connect *) packet;
// Here I access the different fields of the packet using the connect struct
printf("Protocol Name is %s\n", connect->protocolName);
}
我有以下用于解析数据包的C代码:
var module=ons.bootstrap('myApp',['onsen']);
module.controller('MainController',function($scope){
console.log("Main controller");
});
<body ng-app="FirstProject" ng-controller="MainController">
<ons-tabbar>
<ons-tab label="tab1" page="tab1.html" active>
</ons-tab>
<ons-tab label="tab2" page="tab2.html">
</ons-tab>
</ons-tabbar>
<ons-template id="tab1.html">
<ons-page>
<p style="text-align: center;">
This is the first page.
</p>
</ons-page>
</ons-template>
<ons-template id="tab2.html">
<ons-page>
<p style="text-align: center;">
This is the second page.
</p>
</ons-page>
</ons-template>
</body>
在上面的协议中,当字符串从线路进入时,字符串不是空的,因此当我打印协议名称时,我会得到一些奇怪的字符。有没有办法在不改变协议的情况下解决这个问题?
如果协议名称是> 20,char缓冲区将溢出。有没有办法解决这个问题?我是否需要放弃这种解析数据包的方法,只需使用索引并手动解析数据包的每个字节?
由于
答案 0 :(得分:2)
将数据包转换为结构体非常危险,因为您很少或根本无法控制结构在内存中的实际对齐方式。
你需要阅读C结构包装的失落艺术:http://www.catb.org/esr/structure-packing/
答案 1 :(得分:0)
有几种方法;哪个最好取决于很多因素。
第一种方式。如果您一次读取一个字节,使用指针或索引在接收缓冲区中写入,那么在读取protocolNameLength之后,您就知道protocolName会有多少个字符。那么你可以1)在你的结构中丢弃名字中的尾随字符; 2)在protocolName的末尾添加一个NULL,这样就可以轻松管理名称; 3)在读取protocolName后将写指针移动到正确的位置。您还可以通过将其声明为“char protocolName [many]”来为protocolName保留尽可能多的字符:它不会有太大的成本。 第二种方式。您可以在一个缓冲区中,在缓冲区中接收数据包,然后在两个不同的操作中将接收到的缓冲区memcpy()到您的结构中。第一个memcpy复制前4个成员;第二个将数据包的其余部分复制到正确的目的地。必须对第二个memcpy()执行一些指针运算。第一个memcpy()可以防止名称过长。同样,您可以在使用第一个memcpy复制的数据末尾添加NULL,因此您拥有protocolName的真实C字符串。 第三种方式。您可以使用struct本身作为接收缓冲区,然后将protocolmvel的“real(received)”位置的memmove()用作“正确(设计)”地址。假设您为protocolName []保留了足够的空间,此memmove将始终向后移动数据。同样,如果protocolName(或者在示例中的最后一个元素19(20-1)中),您可以将NULL放在正确的位置。鉴于protocolNameLength是用16位声明的,我可以假设名字可能很长,而且很奇怪。但如果真的这个名字可能如此冗长,那么移动内存就会浪费CPU。
如果你需要管理很多字段,那么使用memcpy()/ memmove()会有意义,你必须多次这样做。如果您没有大块移动,它是可行的,并且您知道编译器如何打包/填充结构(如果您想在有线协议上叠加C结构,则无论如何都需要此最后一个要求)。
我个人更喜欢第一种方式,如果可能的话;否则,如果字段不是太多,请“手动”解析数据包。
答案 2 :(得分:0)
在上面的协议中,字符串在进入时不会以空值终止...当我打印协议名称时,我会得到一些奇怪的字符。有没有办法在不改变协议的情况下解决这个问题?
以%s
如果指定了精度,则不超过那么多字节 写了C11dr§7.21.6.18
// printf("Protocol Name is %s\n", connect->protocolName);
printf("Protocol Name is %.*s\n",
(int)(sizeof connect->protocolName),
connect->protocolName);
“字符串不是空终止”是一个矛盾。在C中,标准库中使用的字符串始终为空字符终止,否则它不是字符串,而只是字符数组。幸运的是%.*s
处理字符数组和字符串,以给定的精度或空字符停止。
以下代码是问题@M.M char *
,包括Connect *
的对齐方式。这可以通过更高的未发布代码或如下解决。使用char*
解码数据包不是最好的解决方案。
void decodePacket(char *packet) {
Connect *connect = NULL;
connect = (Connect *) packet; // bad
// alternative
void decodePacket(char *packet) {
Connect connect;
memcpy(&connect, packet, sizeof connect);
printf("Protocol Name is %.*s\n",
(int)(sizeof connect.protocolName),
connect.protocolName);
如果协议名称是> 20,char缓冲区将溢出。
目前尚不清楚。如果发件人中发生溢出,则接收代码无法解决此问题。可以如上所述修复OP的printf()
代码。 OP没有其他代码溢出任何缓冲区。