Chinaunix

标题: tcp报文收发时, data offset 的ushort是否需要做字节序转换? [打印本页]

作者: mordorwww    时间: 2016-06-22 17:48
标题: tcp报文收发时, data offset 的ushort是否需要做字节序转换?
  如下的黑体部分  

0                   1                   2                   3   
    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |          Source Port          |       Destination Port        |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                        Sequence Number                        |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                    Acknowledgment Number                      |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |  Data |           |U|A|P|R|S|F |                               |
   | Offset | Res   |R|C|S|S|Y |I |            Window             |
   |           |          |G|K|H|T|N |N |                               |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

   |           Checksum            |         Urgent Pointer        |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                    Options                    |    Padding    |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |                             data                              |
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+



struct tcphdr {
        __be16        source;
        __be16        dest;
        __be32        seq;
        __be32        ack_seq;
#if defined(__LITTLE_ENDIAN_BITFIELD)
        __u16        res1:4,
                doff:4,
                fin:1,
                syn:1,
                rst:1,
                psh:1,
                ack:1,
                urg:1,
                ece:1,
                cwr:1;
#elif defined(__BIG_ENDIAN_BITFIELD)
        __u16        doff:4,
                res1:4,
                cwr:1,
                ece:1,
                urg:1,
                ack:1,
                psh:1,
                rst:1,
                syn:1,
                fin:1;
#else

作者: Godbach    时间: 2016-06-22 18:19
回复 1# mordorwww

就 4 个 bit,不需要转换的。直接用。字节序,是超过一个 byte 时需要考虑的。


   
作者: mordorwww    时间: 2016-06-23 08:48
Godbach 发表于 2016-06-22 18:19
回复 1# mordorwww

就 4 个 bit,不需要转换的。直接用。字节序,是超过一个 byte 时需要考虑的。


我是问她所在的这个 ___u16不用转换吧
作者: Godbach    时间: 2016-06-23 10:47
回复 3# mordorwww

所在的 _u16 已经按照 bitfield 分出去了,你直接通过结构体对应的各自成员去访问就成了。你没有必要一下子读取整个 _u16 的值啊,或者是这个 _u16 的数值对你来说没有用处。

只有你需要一次读取超过 1 个 bytes 的数值时,才需要考虑字节序的转换。
作者: mordorwww    时间: 2016-06-23 11:33
本帖最后由 mordorwww 于 2016-06-23 11:45 编辑
Godbach 发表于 2016-06-23 10:47
回复 3# mordorwww

所在的 _u16 已经按照 bitfield 分出去了,你直接通过结构体对应的各自成员去访问就 ...


下面这种奇葩的定义见过没

我觉得应该是要对整个64bits做字节序转换,虽然位域没有超过或者达到8bits,但是好几个都跨bytes甚至跨short了。手头上没有big的CPU,没法验证

#if __BYTE_ORDER != __LITTLE_ENDIAN

        uint32_t Odo:32;
        uint16_t BmprHghtFnt:7;
        uint16_t BmprHghtRear:7;
        uint16_t VehHght:7;
        uint16_t VehMass:7;
        uint16_t VehType:4;

#else  // __BYTE_ORDER != __BIG_ENDIAN
        uint16_t VehType:4;
        uint16_t VehMass:7;
        uint16_t VehHght:7;
        uint16_t BmprHghtRear:7;
        uint16_t BmprHghtFnt:7;
        uint32_t Odo:32;

#endif
作者: _nosay    时间: 2016-06-23 12:38
回复 5# mordorwww

那你把数字反着写不能验证么?
作者: _nosay    时间: 2016-06-23 12:39
那你把数字反着写不能验证么?
作者: Godbach    时间: 2016-06-23 16:45
回复 5# mordorwww
这个人家结构体定义的时候已经考虑好了。你就按照单个成员访问就行了。超过一个字节的,要考虑这个问题。


   
作者: karma303    时间: 2016-06-26 09:22
本帖最后由 karma303 于 2016-06-26 09:27 编辑

  结构体内bitfield的顺序是对byte endian敏感的。
  并不是说x86或MIPS除了byte order之外,还有bit order的区别。
  这个问题的根源在于编译器。纯粹是编译器作怪。展开讲话就多了。暂且不表。
  不过我可以告诉你一个技巧,如果位域不跨字节的,大小端的变换是有规律的。
  像小端模式的一个结构体:
struct abcdef {
        int a: 4;
        int b: 4;
        int c: 4;
        int d: 2;
        int e: 2;
};
你想让它在MIPS上的gcc编译后有同样的内存布局,方法是:从上到下,位域每8个bit一组,反转组内的成员顺序。结果是这样:
struct abcdef {
        int b: 4;
        int a: 4;
        int e: 2;
        int d: 2;
        int c: 4;
};
如果位域跨字节,那我就没有办法了。你贴出来的那个struct video什么的代码,我是看不懂的。

一般这种针对big/little endian的条件编译,是出于两种场合的需要。
(1)网络底层协议的传输,从host A传到 host B上,相当于一份远程的内存拷贝,网络协议必须规定这段内存(记作xxx)该以big or little endian的方式存放数据。 我们上面代码里#if #else条件编译,其实都是折腾编译器。我们希望我们的代码在MIPS和x86机器编译后,希望类似下面的代码的输出是一致的:
----------------------------------------------
  struct tcphdr *hdr = (void *)xxx  ;
  printf( "%d\n", hdr->res1);
---------------------------------------------

(2) 驱动代码里,我们要把bitfield与寄存器对应死。

自己写的一篇帖子,希望对题主有帮助。http://bbs.chinaunix.net/forum.p ... =4248004&extra=
  




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2