socket 套接字程式設計筆記——IP地址轉換
阿新 • • 發佈:2019-02-20
0.前言
網上有很多使用arduion和樹莓派連線yeelink的例子,硬體和軟體的實現方式都非常簡單。通過學習這些例子一下激發我學習嵌入式網路的動力。雖然使用arduion連線yeelink簡單方便穩定可靠,但是依然像使用嵌入式乙太網協議棧連線yeelink,例如MCU使用STM32,網絡卡晶片使用ENC28J60,乙太網協議棧使用LwIP。雖然這樣做硬體軟體都要複雜的多,但是也多了不少“樂趣”。事情總是要循序漸進,我決定先認真研究socket程式設計,使用PC平臺和yeelink交換資料。1.測試環境說明
windows環境,編譯器為minGW,IDE為eclipse。windows環境下的套接字程式設計和linux環境略有區別,但是基本的思路和方法相同。若使用minGW加eclipse的開發方式,需要加入wsock32庫。新增的方法如下:1.project -> properties 2.c/c++ build -> settting 3.tool setting -> mingw c linker -> libraries 4.add wsock32
圖1 新增wsock32庫
2.IP地址格式轉換
通常情況下,IP地址都被寫成以下格式:192.168.1.101或者10.13.11.105。這種形式的IP地址易於理解,但是對於協議處理來說就顯得不是那麼的方便,為了讓IP地址更容易被處理併兼顧網路傳輸中的格式(網路傳輸為大端格式),所以定義了in_addr結構體:struct in_addr { union { struct { u_char s_b1,s_b2,s_b3,s_b4; } S_un_b; struct { u_short s_w1,s_w2; } S_un_w; u_long S_addr; } S_un; #define s_addr S_un.S_addr #define s_host S_un.S_un_b.s_b2 #define s_net S_un.S_un_b.s_b1 #define s_imp S_un.S_un_w.s_w2 #define s_impno S_un.S_un_b.s_b4 #define s_lh S_un.S_un_b.s_b3 };
在一些網上流傳的套接字程式碼中,經常會看到這樣的程式碼
struct in_addr server_addr server_addr.s_addr = ..... 此處的server_addr為一個in_addr型別結構體,server_addr代表一個IP地址。如果理解in_addr型別結構體,也就是把一個IP地址理解為4個字元,或2個16位長度整數,或1個32位長度的整數。由於in_addr型別結構體中包含一個共用體。為使程式設計更簡便些可使用s_addr替代S_un.S_addr,所以便有了server_addr.s_addr這樣的程式碼。in_addr型別結構體一般不單獨出現(除了DNS地址解析外),而是存在於sockaddr_in結構體中,sockaddr_in可理解為套接字地址結構體。
3.格式之間的相互轉換
3.1 inet_addr
函式原型和輸入輸出引數unsigned long inet_addr(
_In_ const char *cp
);
函式作用把ASCII格式的IP地址(AAA.BBB.CCC.DDD形式)轉換為一個32位無符號整數。
3.2 inet_ntoa
函式原型和輸入輸出引數char* FAR inet_ntoa(
_In_ struct in_addr in
);
函式作用把in_addr型別的IP地址轉換為ASCII格式的IP地址(AAA.BBB.CCC.DDD形式)。inet_ntoa中的n可理解為network,a可理解為ascii。該函式一般用於列印IP地址。
4.示例程式碼
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#include <string.h>
#include <windows.h>
int main(int argc, char **argv)
{
unsigned long addr = INADDR_NONE;
// 測試inet_addr
char server_ipaddr[] = {"192.168.1.101"};
addr = inet_addr( server_ipaddr);
if ( addr == INADDR_NONE && addr == INADDR_ANY )
{
printf("轉換失敗\n");
return 1;
}
// 轉換結果(unsigned long)1694607552
printf("轉換結果(unsigned long)%lu\n",addr);
// 測試inet_itoa
// 轉化為ASCII字串形式的IP地址
struct in_addr client_ipaddr;
client_ipaddr.s_addr = addr;
// 轉換結果("XXX.XXX.XXX.XXX") 192.168.1.101
printf( "轉換結果(\"XXX.XXX.XXX.XXX\") %s" , inet_ntoa( client_ipaddr ) );
return 0;
}
執行結果 轉換結果(unsigned long)1694607552 轉換結果("XXX.XXX.XXX.XXX") 192.168.1.101 程式分析 首先準備一個ASCII形式的IP地址,例如192.168.1.101。使用inet_addr轉換為一個32位無符號整數,轉換結果為1694607552。保留該結果並在通過inet_ntoa還原192.168.1.101。還原之前需要先定義in_addr型別結構體,並命名為client_ipaddr,client_ipaddr.s_addr 為32位無符號整數可直接賦值。最後使用inet_ntoa對client_ipaddr變數進行格式轉換並通過串列埠列印。