`
BruceXX
  • 浏览: 141532 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

关于银行端发出的socket通信回执包头长度的 高低位顺序。

 
阅读更多
首先描述一下场景,在用java做服务端的情况下,正确的获取包头(即报文长度), 我当时听了一位比较有经验的同事的疑问,说银行用C的情况下有可能获取的这个长度(int或short或long)有可能高低位不同(比如包头应该是0402,实际上我们收到的是2040),需要对这个做一个特殊处理,鉴于该同事在银行工作时间很长,所以带着一些问题看了下这方面的资料,发现并肯定,不会产生这种问题。

主要是C在不同CPU下存储机制的方式不同==》

大端模式与小端模式

一、概念及详解
  在各种体系的计算机中通常采用的字节存储机制主要有两种: big-endian和little-endian,即大端模式和小端模式。

  两个关键词,MSB和LSB:

  MSB:Most Significant Bit ------- 最高有效位
  LSB:Least Significant Bit ------- 最低有效位

  大端模式(big-edian)
  big-endian:MSB存放在最低端的地址上。

  举例,双字节数0x1234以big-endian的方式存在起始地址0x00002000中:

        | data |<-- address
        | 0x12 |<-- 0x00002000
        | 0x34 |<-- 0x00002001

  在Big-Endian中,对于bit序列中的序号编排方式如下(以双字节数0x8B8A为例):

        bit | 0 1 2 3 4 5 6 7 | 8 9 10 11 12 13 14 15
        ------MSB----------------------------------LSB
        val | 1 0 0 0 1 0 1 1 | 1 0 0 0 1 0 1 0 |
        +--------------------------------------------+
        = 0x8 B 8 A

  小端模式(little-endian)
  little-endian:LSB存放在最低端的地址上。

  举例,双字节数0x1234以little-endian的方式存在起始地址0x00002000中:

        | data |<-- address
        | 0x34 |<-- 0x00002000
        | 0x12 |<-- 0x00002001

  在Little-Endian中,对于bit序列中的序号编排和Big-Endian刚好相反,其方式如下(以双字节数0x8B8A为例):

        bit | 15 14 13 12 11 10 9 8 | 7 6 5 4 3 2 1 0
        ------MSB-----------------------------------LSB
        val | 1 0 0 0 1 0 1 1 | 1 0 0 0 1 0 1 0 |
        +---------------------------------------------+
        = 0x8 B 8 A

二、数组在大端小端情况下的存储:
  以unsigned int value = 0x12345678为例,分别看看在两种字节序下其存储情况,我们可以用unsigned char buf[4]来表示value:

  Big-Endian: 低地址存放高位,如下:

       高地址
        ---------------
        buf[3] (0x78) -- 低位
        buf[2] (0x56)
        buf[1] (0x34)
        buf[0] (0x12) -- 高位
        ---------------
        低地址

  Little-Endian: 低地址存放低位,如下:
        高地址
        ---------------
        buf[3] (0x12) -- 高位
        buf[2] (0x34)
        buf[1] (0x56)
        buf[0] (0x78) -- 低位
        --------------
        低地址

三、大端小端转换方法:
  Big-Endian转换成Little-Endian如下:

    #define BigtoLittle16(A)  ((((uint16)(A) & 0xff00) >> | \
                                 (((uint16)(A) & 0x00ff) <<)

    #define BigtoLittle32(A)  ((((uint32)(A) & 0xff000000) >> 24) | \
                                  (((uint32)(A) & 0x00ff0000) >> | \
                                  (((uint32)(A) & 0x0000ff00) << | \
                                  (((uint32)(A) & 0x000000ff) << 24))
四、大端小端检测方法:
  如何检查处理器是big-endian还是little-endian?

  联合体union的存放顺序是所有成员都从低地址开始存放,利用该特性就可以轻松地获得了CPU对内存采用Little-endian还是Big-endian模式读写。
     int checkCPUendian()
     {
         union
         {
              unsigned int a;
              unsigned char b;
         }c;
         c.a = 1;
         return (c.b == 1);
     }
     /*return 1 : little-endian, return 0:big-endian*/

网络字节顺序

1、字节内的比特位不受这种顺序的影响
    比如一个字节 1000 0000 (或表示为十六进制 80H)不管是什么顺序其内存中的表示法都是这样。

2、大于1个字节的数据类型才有字节顺序问题

    比如 Byte A,这个变量只有一个字节的长度,所以根据上一条没有字节顺序问题。所以字节顺序是“字节之间的相对顺序”的意思。

3、大于1个字节的数据类型的字节顺序有两种

    比如 short B,这是一个两字节的数据类型,这时就有字节之间的相对顺序问题了。
    网络字节顺序是“所见即所得”的顺序。而Intel类型的CPU的字节顺序与此相反。
    比如上面的 short B=0102H(十六进制,每两位表示一个字节的宽度)。所见到的是“0102”,按一般数学常识,数轴从左到右的方向增加,即内存地址从左到右增加的话,在内存中这个 short B的字节顺序是:
        01 02
    这就是网络字节顺序。所见到的顺序和在内存中的顺序是一致的!

    而相反的字节顺序就不同了,其在内存中的顺序为:02 01
    假设通过抓包得到网络数据的两个字节流为:01 02
    如果这表示两个 Byte类型的变量,那么自然不需要考虑字节顺序的问题。
    如果这表示一个 short 变量,那么就需要考虑字节顺序问题。根据网络字节顺序“所见即所得”的规则,这个变量的值就是:0102

    假设本地主机是Intel类型的,那么要表示这个变量,有点麻烦:
    定义变量 short X,
    字节流地址为:pt,按顺序读取内存是为
    x=*((short*)pt);
    那么X的内存顺序当然是 01 02
    按非“所见即所得”的规则,这个内存顺序和看到的一样显然是不对的,所以要把这两个字节的位置调换。
    调换的方法可以自己定义,但用已经有的API还是更为方便。

网络字节顺序与主机字节顺序NBO与HBO

    网络字节顺序NBO(Network Byte Order):按从高到低的顺序存储,在网络上使用统一的网络字节顺序,可以避免兼容性问题。
    主机字节顺序(HBO,Host Byte Order):不同的机器HBO不相同,与CPU设计有关计算机数据存储有两种字节优先顺序:高位字节优先和低位字节优先。

    Internet上数据以高位字节优先顺序在网络上传输,所以对于在内部是以低位字节优先方式存储数据的机器,在Internet上传输数据时就需要进行转换。

相关网络函数

htonl()

简述:
    将主机的无符号长整形数转换成网络字节顺序。
    #include <winsock.h>
    u_long PASCAL FAR htonl( u_long hostlong);
    hostlong:主机字节顺序表达的32位数。
注释:
    本函数将一个32位数从主机字节顺序转换成网络字节顺序。
返回值:
    htonl()返回一个网络字节顺序的值。

inet_ntoa()

简述:
将网络地址转换成“.”点隔的字符串格式。
#include <winsock.h>
char FAR* PASCAL FAR inet_ntoa( struct in_addr in);
in:一个表示Internet主机地址的结构。

注释:
本函数将一个用in参数所表示的Internet地址结构转换成以“.” 间隔的诸如“a.b.c.d”的字符串形式。请注意inet_ntoa()返回的字符串存放在WINDOWS套接口实现所分配的内存中。应用程序不应假设该内存是如何分配的。在同一个线程的下一个WINDOWS套接口调用前,数据将保证是有效。
返回值:
若无错误发生,inet_ntoa()返回一个字符指针。否则的话,返回NULL。其中的数据应在下一个WINDOWS套接口调用前复制出来。

网络中传输的数据有的和本地字节存储顺序一致,而有的则截然不同,为了数据的一致性,就要把本地的数据转换成网络上使用的格式,然后发送出去,接收的时候也是一样的,经过转换然后才去使用这些数据,基本的库函数中提供了这样的可以进行字节转换的函数,如和htons() htonl() ntohs() ntohl(),这里n表示network,h表示host,htons() htonl()用于本地字节向网络字节转换的场合,s表示short,即对2字节操作,l表示long即对4字节操作。同样ntohs()ntohl()用于网络字节向本地格式转换的场合。


inet_ntoa() 将网络字节序地址转换成“.”点隔的字符串格式
inet_addr() 将“.”点隔字符串地址转换成网络字节序地址
htonl() 将主机字节序转换为网络字节序 long
ntohl() 将网络字节序转换为主机字节序 long
htons() 将主机字节序转换为网络字节序 short
ntohs() 将网络字节序转换为主机字节序 short

intel cpu的主机数据是小端存储模式
网络传输是大端存储模式
小端存储模式 0x1234H 34H存在低地址,12H存在高地址
大端存储模式 0x1234H 34H存在高地址,12H存在低地址


因为给java的数据都是byte流直接过来的, 一般我们采取将字节流的byte转化为string,然后通过这个string直接获取其数字类型,而不是通过byte直接转换为数字类型,所以不会出现这种高低位相反的问题
分享到:
评论

相关推荐

    C#与Android Socket通信

    在本场景中,我们关注的是C#作为服务器端,Android作为客户端的Socket通信实现。这种通信方式常用于移动应用与后台服务之间的实时数据交互,如即时消息、位置更新、文件传输等。 一、C# Socket服务器端实现 1. 引用...

    C# Socket 通信,客户端服务器端

    本教程将深入讲解C#中的Socket通信,包括客户端和服务器端的实现,以及如何通过源码学习相关知识。 首先,我们要理解Socket的基本概念。Socket,也称为套接字,是网络通信中的一个接口,它允许应用程序通过网络发送...

    PC端和安卓实现Socket通信

    pc端通过socket通信,实现和安卓智能终端的数据交互

    unity c#实现简单前后端socket通信框架

    博客:https://blog.csdn.net/u014261855/article/details/109583060 unity c#实现简单前后端socket通信框架 .net dll工程,封装三个工具: 1.服务器 2.客户端 3.通用byte流客户端

    C#Socket通信稳定完整版类库实例

    Socket通信通常基于TCP或UDP协议,TCP保证数据传输的可靠性,而UDP则更注重速度但不保证数据顺序。 2. **TCP Socket通信** 在C#中,我们使用`TcpClient`和`TcpListener`类来实现TCP Socket通信。`TcpClient`用于...

    c++ socket通信库

    - **套接字(Socket)**: 是通信的两端,可以是服务器端也可以是客户端。每个套接字都有一个唯一的标识符,称为套接字描述符。 - **TCP(Transmission Control Protocol)与UDP(User Datagram Protocol)**: 是两...

    android+pc socket通信

    "Android+PC Socket通信"指的是通过TCP Socket协议实现Android设备(手机客户端)与个人计算机之间的数据传输。Socket通信允许应用程序之间建立端到端的连接,进行双向数据交换,非常适合用于实时通讯、文件传输等...

    Android手机客户端与服务器之间通信socket

    在Android应用开发中,手机客户端与服务器之间的通信是至关重要的,而Socket通信提供了一种可靠的、基于连接的数据传输方式。本文将深入探讨Android客户端如何利用Socket进行与服务器的交互。 一、Socket基础知识 ...

    socket通信文件传输

    在Socket通信中,TCP协议确保了数据的顺序传输和错误检查,保证了文件传输的完整性和可靠性。 3. **Socket通信步骤**: - **创建Socket**:服务器端首先创建一个ServerSocket,监听特定的端口号,等待客户端的连接...

    matlab环境下socket通信

    在MATLAB环境中实现Socket通信是将强大的MATLAB计算能力与网络通信功能相结合的重要技术。Socket是一种网络编程接口,它允许程序之间通过网络进行双向通信。MATLAB提供了丰富的工具和函数来支持Socket通信,使得用户...

    socket通信异常解决总结

    Socket 通信异常是指在网络通信过程中出现的各种错误和异常,包括网络连接断开、服务器端或客户端程序异常、网络链路异常等。这些异常会导致 Socket 连接断开,影响系统的稳定性和可靠性。下面是解决 Socket 通信...

    客户端与服务器端的Socket通信.pdf

    ### 客户端与服务器端的Socket通信:深入解析与实践 #### 引言 在当今高度互联的世界中,客户端与服务器端的通信是互联网应用的核心。本文将深入探讨Socket通信的基本原理及其在客户端与服务器端的应用,尤其关注...

    Android开发,Socket Client端和Socket Server端数据发送和接收

    在Android开发中,Socket通信是实现设备间网络通信的一种常见方式...以上就是关于Android开发中Socket Client端和Socket Server端数据发送和接收的核心知识点。理解并掌握这些内容,将有助于构建稳定的跨设备通信系统。

    SOCKET通信调试工具

    SOCKET通信调试工具是一款专为开发者设计的实用辅助软件,旨在简化SOCKET通信的调试过程。在编程领域,SOCKET是网络通信的基础,它允许不同设备间的程序通过互联网进行数据交换。这款工具允许用户在本地环境中模拟...

    pc与开发板通过socket通信

    在这个场景中,我们将讨论如何实现PC(个人计算机)与开发板之间的通信,特别关注使用Socket进行TCP/IP连接的情况,同时,PC端还具备图形用户界面(GUI)。让我们深入探讨这个主题。 首先,Socket是应用层与传输层...

    Socket通信

    Socket通信是计算机网络编程中的重要组成部分,主要用于实现不同设备间进程间的通信。在这个主题中,我们将深入探讨Socket的工作原理、服务器与客户端的交互过程以及如何使用Socket进行编程。 首先,Socket可以理解...

    c# Socket 通信 源码

    在这个"**c# Socket通信源码**"中,我们主要会看到客户端和服务器端的实现,这有助于理解如何在C#环境下使用Socket进行网络通信。 首先,让我们深入了解一下Socket的基本概念。Socket是网络上的进程间通信(IPC)的...

    C#TCP\Socket粘包处理(加长度头)

    - 发送端:构建数据包时,先写入长度头,再写入实际数据,然后使用`Socket.Send`发送。 - 接收端:首先接收长度头,转换为整数,然后循环接收数据直到达到指定长度,完成一个数据包的接收。 5. **其他解决方案** ...

    java实现简单socket通信

    Java实现的简单Socket通信是网络编程中的基础技术,主要用于设备间的双向数据传输。在这个场景中,我们有两个窗口,一个作为服务器端,另一个作为客户端,它们通过TCP协议进行通信。TCP是一种面向连接的、可靠的传输...

Global site tag (gtag.js) - Google Analytics