网络报文发送方、接收方以及网络传输中的大端小端问题

首先明确大端、小端概念:

大端:高字节存放低地址,低字节存放高地址;

小端:低字节存放低地址,高字节存放高地址。

再明确一个概念,网络字节序

        网络上传输的数据都是字节流,对于一个多字节数值,如占4个字节的int,在进行网络传输的时候,先传递哪个字节?也就是说,当接收端收到第一个字节的时候,它将这个字节作为高位字节还是低位字节处理,是一个比较有意义的问题:

        UDP/TCP/IP协议规定:把收到的第一个字节当作高位字节看待。这就要求发送方发送的第一个字节是高位字节。但是发送方在发送的时候,只能是从存储该变量的起始地址开始一个字节一个字节的发送,那这样只有是大端字节序满足要求。因为这两句话结合在一起就是:网络要求先发出去的必须是变量的高地址,而实际机器中又是要从低地址开始一字节一字节的发,所以只有机器是大端字节序就刚好满足要求。所以网络字节序是大端字节序,网络协议使用大端字节序来传输数据。

        这样我们就可以发现一个问题,如果机器是大端,那刚好就是按照大端的要求发出的,那如果机器是小端呢,那不做任何处理发出去的不也就是小端吗?是的。这就有了以下这个现象:

因为我们的机器通常情况下是小端字节序,在写网络数据传输时最开始建立连接去初始化sockaddr_in时,经常要先把IP和端口转换成大端模式(使用inet_addr,htons)。

        既然网络传输协议规定了传输使用的是大端字节序,那为什么又只把IP地址,端口等转成大端格式,数据部分却不进行大小端转换呢?

        我纠结这个问题还纠结了很久,答案是没有必要。

        首先明确为什么IP地址和端口要大端化。网络传输协议规定了要大端化,那么对于各级交换机、路由器提取报文中的MAC、IP也应该是大端化的,这样统一便于做比对去查找路由表。

        那么为什么数据部分又不大端化呢?数据大小端的差异与机器的存储方式有关,而与传输方式无关。也就是说,网络包都是以大端的方式传输,而传输到本地对包做解析时,不管你是按大端传来的还是按小端传来的,接收方将变量赋值给本地变量,还是只能将先拿到的字节存在低地址。这样如果发送、接收两端都是大端,那解析存的变量去没有问题,如果发送、接收两端都是小端,那存的变量去解析时没有问题。但是如果一个大端机器一个小端呢?大端按照先发出的是高字节来发出的,小端机器也在分配好的内存位置按照顺序一个一个的存下来了,但是去从地址处取值读的时候就出问题了。所以网络传输只管规定要大端字节序传输,但是他自己不管转换的事,内核也不管,而具体要不要转不转,转哪些,怎么转,都得各位根据具体的情况亲自来,不是你丢给socket了它在传输的时候给你转换好。

        所以与建立连接相对应的现象就是,接收到数据后,想获取发送方的IP地址和端口,又得将大端字节序本地化。而数据部分,你那边怎么存的,发过来我还是怎么存,只要不是一个大端一个小端,我接收完了还是照样就能解析了,所以没有必要去发的时候转换一道,接的时候又转换回来,交换机、路由器不需要关心你传的数据是啥,你把他们要的IP和端口按照大端转换好就行,他们这样才能正确的找到路由。至于数据,不管你怎么发、按照什么格式发,网络都认为是大端,但是不是大端你自己知道就行。

附加一点笔记有个知识点有点忘记了:

socket和sockaddr_in是什么关系?

先放点代码在这

 int   sockfd;  
  struct   sockaddr_in   m_addr;  
  sockfd   =   socket(AF_INET,   SOCK_STREAM,   0);     
   
  m_addr.sin_family   =   AF_INET;     
  m_addr.sin_port   =   htons(MYPORT);     
  m_addr.sin_addr.s_addr   =   inet_addr("192.168.0.106");  
   
  bzero(&(my_addr.sin_zero),   8);     
    
  bind(sockfd,   (struct   sockaddr   *)&m_addr,   sizeof(struct   sockaddr));

socket只是一个用于通信的符号,sockaddr_in存储的是具体的通信需要的信息,将socket bind在sockaddr_in上,这样这个socket管的就是和sockaddr_in里面地址的通信。

  • 27
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值