Linux網路程式設計(一)基礎
一、資料儲存順序:大端和小端
大端模式: 地址的增長順序與值的增長順序相反
小段模式: 地址的增長順序與值的增長順序相同
為什麼會有大小端模式之分呢?這是因為在計算機系統中,我們是以位元組為單位的,每個地址單元都對應著一個位元組,一個位元組為8bit。但是在C語言中除了8bit的char之外,還有16bit的short型,32bit的long型(要看具體的編譯器),另外,對於位數大於8位的處理器,例如16位或者32位的處理器,由於暫存器寬度大於一個位元組,那麼必然存在著一個如果將多個位元組安排的問題。
我們常用的X86結構是小端模式,而KEIL C51則為大端模式。很多的ARM,DSP都為小端模式。有些ARM處理器還可以由硬體來選擇是大端模式還是小端模式。所以,主機位元組順序是小端模式。網路位元組順序是大端模式。
在C語言中,不同於結構體,共用體(聯合體)中的幾種不同型別的變數存放在同一段記憶體單元中。利用這一特點,可以用聯合體變數判斷ARM或X86環境下,儲存系統是是大端還是小端模式。
#include "stdio.h"
int main()
{
union w
{
int a; //4 bytes
char b; //1 byte
} c;
c.a=1;
if (c.b==1)
printf("It is Little_endian!\n");
else
printf("It is Big_endian!\n");
return 1;
}
說明:1 若是小端模式,由低地址到高地址c.a存放為0x01 00 00 00,c.b被賦值為0x01;
————————————————————————————
地址 0x00000000 0x00000001 0x00000002 0x00000003
c.a 01 00 00 00
c.b 01
————————————————————————————
2 若是大端模式,由低地址到高地址c.a存放為0x00 00 00 01,c.b被賦值為0x0;
————————————————————————————
地址 0x00000000 0x00000001 0x00000002 0x00000003
c.a 00 00 00 01
c.b 00
————————————————————————————
位元組序的處理
因為存在大端小端的問題,所以就要進行統一的轉換。
注意字串是不用轉換的,因為一個字元正好佔一位元組。儲存順序不影響值。而浮點數也不用轉換,因為浮點數的讀取規則是在cpu中定義的,是一致的。
轉換所用的函式為:
htons(),htonl(); 主機轉為網路位元組序,s為short , l為long
ntohs(),ntohl(); 網路轉為主機位元組序。
二、地址格式的轉換
通常情況下,都是用點分十進位制(如:202.134.23.145)來表示IP地址。是個字串。但是程式中處理時用到的是一個二進位制的值。所以要進行轉換。
具體的有四個函式:
#include<stdio.h>
#include<stdlib.h>
#include<netinet/in.h>
int main(){
//ip地址字串
char* sa="202.30.45.11";
//記錄ip地址的結構體
struct in_addr addr,ret;
//是網路地址型別
in_addr_t at;
//將點分十進位制字串轉換為32位網路位元組序的IP
at=inet_addr(sa);
//十六進位制輸出
printf("inet_addr:0x%x \n",at);
//將點分十進位制字串轉換為32位主機位元組序,與網路位元組序應該是反過來的
printf("inet_network:0x%x \n",inet_network(sa));
//結構體中記錄IP地址的資料成員
addr.s_addr=at;
//網路位元組序轉換為點分十進位制數
printf("inet_ntoa:%s \n",inet_ntoa(addr));
//點分十進位制數轉換為網路位元組序,引數為結構體
inet_aton(sa,&ret);
printf("inet_aton:0x%x \n",ret.s_addr);
}
執行結果:
[localhost 400]$ ./addr
inet_addr:0xb2d26ca
inet_network:0xca262d0b
inet_ntoa:202.30.45.11
inet_aton:0xb2d26ca
[localhost 400]$