程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> Linux網絡編程1——小端模式與大端模式,linux網絡編程大端

Linux網絡編程1——小端模式與大端模式,linux網絡編程大端

編輯:關於C語言

Linux網絡編程1——小端模式與大端模式,linux網絡編程大端


數據存儲優先順序的轉換

計算機數據存儲有兩種字節優先順序:高位字節優先(稱為大端模式)和低位字節優先(稱為小端模式)。內存的低地址存儲數據的低字節,高地址存儲數據的高字節的方式叫小端模式。內存的高地址存儲數據的低字節,低地址存儲數據高字節的方式稱為大端模式。

eg:對於內存中存放的數0x12345678來說(注意,對於數據而言,此處12是高字節,78是低字節;對於地址而言,左邊是低地址,右邊是高地址)

如果是采用大端模式存放的,則其真實的數是:0x12345678

如果是采用小端模式存放的,則其真實的數是:0x78563412

綜上:小端模式,先存低字節;大端模式先存高字節。

如果稱某個系統所采用的字節序為主機字節序,則它可能是小端模式的,也可能是大端模式的。通常我們的電腦存放數據,都是以小端模式存放。而端口號和IP地址都是以網絡字節序存儲的,不是主機字節序,網絡字節序都是大端模式。要把主機字節序和網絡字節序相互對應起來,需要對這兩個字節存儲優先順序進行相互轉化。

Pra1

原題

實現將字符串形式存放的ip地址(點分十進制數)轉換為主機字節序的32位二進制數值。IP為:“180.97.33.107”。十六進制為b4.61.21.6b

思路

一般我們的主機字節序均為小端字節序,也就是選存放數據的低字節。

1. 將字符串中的每個數取出來

2. 分別左移(注意,左移時一定會補0)

         180 : 00 00 00 b4    左移0  位   00 00 00 b4
         97   : 00 00 00 61    左移8  位   00 00 61 00
         33   : 00 00 00 21    左移16位   00 21 00 00
         107 : 00 00 00 6b    左移24位   6b 00 00 00

3. 或操作

代碼

/*************************************************************************
    > File Name: my_atoh.c
    > Author: KrisChou
    > Mail:[email protected] 
    > Created Time: Wed 27 Aug 2014 08:52:38 PM CST
 ************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define IP "180.97.33.107"

/* 將ip地址轉換為主機字節序的二進制數值,輸出用16進制表示 */
static int my_atoh(char *ip)
{
    int arr[4]; /* 用於存放從ip地址中扣出的4個整數 */
    int my_ip;
    sscanf(IP,"%d.%d.%d.%d",arr,arr+1,arr+2,arr+3);
    my_ip = (arr[3] << 24) | (arr[2] << 16) | (arr[1] << 8) | arr[0];
    return my_ip;
}

int main(int argc, char *argv[])
{
    int my_host = my_atoh(IP);
    printf("ip  : %s \n",IP);
    printf("host: %x \n",my_host);
    return 0;
}

運行結果如下:

[purple@localhost 0827]$ gcc -o main my_atoh.c -Wall
[purple@localhost 0827]$ ./main
ip  : 180.97.33.107
host: 6b2161b4
[purple@localhost 0827]$

注意

提一個與本題無關的注意點,當所有scanf函數,格式化讀入時,如果遇到%s,會自己加‘\0’。

Pra2

原題

實現將主機字節序(小端模式存放)轉換為網絡字節序(大端模式存放)。即主機字節序為6b2161b4 –> b461216b

思路1

將6b與b4交換,21與61交換。

代碼

/*************************************************************************
    > File Name: my_hton.c
    > Author: KrisChou
    > Mail:[email protected] 
    > Created Time: Wed 27 Aug 2014 09:26:13 PM CST
 ************************************************************************/

#include <stdio.h>

int my_hton(int ip)
{
    /* &ip指向用32個bit表示的整型數ip,將int*類型的指針轉換為char*類型的指針,
     * 則ptr指向用8個bit表示(第0-7位)的整型數,
     * ptr+1指向用8個bit表示(第8-15位)的整型數,
     * ptr+2指向用8個bit表示(第16-23位)的整型數,
     * ptr+3指向用8個bit表示(第24-31位)的整型數。*/
    
    char *ptr = (char*)&ip;
    
    char tmp;
    tmp = ptr[0];
    ptr[0] = ptr[3];
    ptr[3] = tmp;

    tmp = ptr[1];
    ptr[1] = ptr[2];
    ptr[2] = tmp;

    return ip;
}

int main(int argc, char *argv[])
{
    int my_host = 0x6b2161b4;
    int my_net = my_hton(my_host);
    printf("my_host: %x \n",my_host);
    printf("my_net : %x \n",my_net);
    return 0;
}

運行結果如下:

[purple@localhost 0827]$ gcc -o main my_hton.c -Wall
[purple@localhost 0827]$ ./main
my_host: 6b2161b4
my_net : b461216b

注意

實際上,ip地址為點分十進制,每個字節的表示范圍都是0-255。而我們的char類型通常默認為有符號數,也就是說其表示范圍是-128-127。那麼我在代碼中標記為黃色的部分是不是出錯了呢?實際上並沒有錯,因為在此處我們只是關心ip每一位的存儲情況,並不要求用到具體每個字節的實際十進制表示數值。在用printf格式化輸出時,是根據數據在內存中的二進制形式來格式化的,而16進制形式是沒有負數的。

思路2

1. 對於0x6b2161b4,先右移並進行與操作,取出各字節

例如:要取出6b,則0x6b2161b4右移24位,之後與0xff進行與操作即可

注意:千萬不能先進行與操作,再右移。如,要取出6b,先使0x6b2161b4與0xff000000進行與操作,之後右移24位。這是錯誤的,因為右移會補符號位。(tips:左移補0,並捨棄符號位)

2. 分別再左移,調整到適當位置。 (以下兩步類似於Pra1)

3. 或操作

代碼

/*************************************************************************
    > File Name: my_hton2.c
    > Author: KrisChou
    > Mail:[email protected] 
    > Created Time: Wed 27 Aug 2014 10:08:07 PM CST
 ************************************************************************/

#include <stdio.h>

int my_hton2(int ip)
{
    int my_net;
    my_net = ((ip&0xff)<<24) | (((ip>>8)&0xff) << 16) | (((ip>>16)&0xff) << 8) | ((ip>>24)&0xff);
    return my_net;
}

int main(int argc, char *argv[])
{
    int my_host = 0x6b2161b4;
    int my_net = my_hton2(my_host);
    printf("my_host: %x \n", my_host);
    printf("my_net : %x \n", my_net);
    return 0;
}

Pra3

原題

實現將網絡字節序轉換為點分十進制

代碼

/*************************************************************************
    > File Name: my_ntoa.c
    > Author: KrisChou
    > Mail:[email protected] 
    > Created Time: Wed 27 Aug 2014 10:27:03 PM CST
 ************************************************************************/

#include <stdio.h>

static char* my_ntoa(int ip)
{
    static char buf[1024] = "";
    sprintf(buf,"%d.%d.%d.%d",(ip >> 24) & 0xff,(ip >> 16) & 0xff, (ip >> 8) & 0xff, ip & 0xff);
    return buf;
}

int main(int argc,char *argv[])
{
    int my_net = 0xb461216b;
    printf("my_net: %x \n", my_net);
    printf("IP    : %s \n", my_ntoa(my_net));
    return 0;
}

檢查小端與大端模式方法

定義一聯合體.
union A{
int a;
char b[4];
}a;
a.a=1;
if (a.b[0] == 0)
{
//大端
} else {
//小端
}
 

什是大端模式與小端模式?

如果將一個32位的整數0x12345678存放到一個整型變量(int)中,這個整型變量采用大端或者小端模式在內存中的存儲由下表所示。為簡單起見,本書使用OP0表示一個32位數據的最高字節MSB(Most Significant Byte),使用OP3表示一個32位數據最低字節LSB(Least Significant Byte)。

---------------------------
地址偏移大端模式小端模式
0x00 12(OP0) 78(OP3)
0x01 34(OP1) 56(OP2)
0x02 56(OP2) 34(OP1)
0x03 78(OP3) 12(OP0)
---------------------------

如果將一個16位的整數0x1234存放到一個短整型變量(short)中。這個短整型變量在內存中的存儲在大小端模式由下表所示。

---------------------------------
地址偏移大端模式小端模式
0x00 12(OP0) 34(OP1)
0x01 34(OP1) 12(OP0)
-------------------------------------
 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved