linux的套接字部分比較容易混亂,在這裏稍微總結一下。linux
地址轉換函數在地址的文本表達式和它們存放在套接字地址結構中的二進制值進行轉換。網絡
地址轉換函數有四個:其中inet_addr 和 inet_ntoa適用於IPv4,inet_pton 和 inet_ntop同時適於用IPv4和IPv6。socket
1 struct in_addr{ 2 in_addr_t s_addr; // 3 }; 4 5 struct sockaddr_in{ 6 uint8_t sin_len; 7 sa_family_t sin_family; //套接字地址結構的地址族 8 in_port_t sin_port //TCP或UDP端口,通常爲uint16_t 9 struct in_addr sin_addr; //IPv4地址,通常爲uint32_t 10 char sin_zero[8]; 11 };
說明:POSIX規範只須要這個結構中的3個字段:sin_family、sin_addr和sin_port。對於符合POSIX的實現來講,定義額外的結構字段是能夠接受的。幾乎全部的實現都增長了sin_zero字段,因此全部的套接字地址結構大小都至少是16字節。函數
1 struct sockaddr{ 2 uint8_t sa_len; 3 sa_family_t sa_family; 4 char sa_data[14]; 5 };
因而套接字函數被定義爲以指向某個通用套接字地址結構的一個指針做爲其參數之一,例如bind函數的ANSI C函數原型:ui
int bind(int, struct sockaddr *, socklen_t); //通常是uint32_t
這就要求對這些函數的任何調用都必需要將指向特定於協議的套接字地址結構的指針進行強制類型轉換,變成指向某個通用套接字地址類型的指針,如:spa
struct sockaddr_in serv; bind(sockfd, (struct sockaddr *) &serv, sizeof(serv));
struct sockaddr_in serv; connect(sockdf, (SA *) &serv, sizof(serv));
struct sockaddr_un cli; socklen_t len; len = sizeof(cli); getpeername(unixfd, (SA *) &cli, &len);
#include <arpa/inet.h> int inet_aton(const char *strptr, struct in_addr *addrptr); //返回:若字符串有效則爲1,不然爲0 in_addr_t inet_addr(const char *strptr); //返回:若字符串有效則爲32位二進制網絡字節序的IPv4地址,不然爲INADDR_NONE char *inet_ntoa(struct in_addr inaddr); //返回:指向一個點分十進制數串的指針
//還有一個名爲inet_network的函數和inet_addr相似,可是其返回的是主機字節序
in_addr_t inet_network(const char *strptr);
inet_aton 和 inet_addr 兩個函數都是將一個點分十進制字符串轉換成一個32位的網絡字節序二進制值。inet_aton函數,若是addrptr指針爲空,那麼該函數仍然對輸入的字符串執行有效性檢查,可是不存儲任何結果。inet_addr函數存在一些問題:全部2^32個可能的二進制值都是有效的ip地址(0.0.0.0-255.255.255.255),可是當出錯時函數返回INADDR_NONE常量(一般是一個32位均爲1的值),這意味着點分十進制數串255.255.255.255不能由該函數處理,由於它的二進制用來指示該函數失敗,inet_addr還存在一個潛在的問題:一些手冊聲明該函數出錯時返回-1而不是INADDR_NONE,這樣在對該函數的返回值和一個負常量進行比較時可能會發生問題。現在,inet_addr已經廢棄,新的代碼應該改用inet_ato函數,更好的解決方法是使用inet_pton函數。另外須要注意的是inet_ntoa函數的參數是in_addr的結構體而不是指針。unix
#include <arpa/inet.h> int inet_pton(int family, const char *strptr, void *addrptr); //返回:若成功則爲1,若輸入不是有效的表達格式則爲0,若出錯則爲-1 const char *inet_ntop(int family, void *addrptr, char *strptr, size_t len); //返回:若成功則爲指向結果的指針,若出錯則爲NULL
//len:INET_ADDRSTRLEN INET6_ADDRSTRLEN
//inet_ntop函數的strptr不能夠是一個空指針,調用者必須爲目標存儲單元分配內存並制定其大小,調用成功時,這個指針就是該函數的返回值
inet_pton(AF_INET),inet_aton, inet_addr 點分十進制數 -----------------------------------------------------> in_addr{} IPv4地址 <----------------------------------------------------- 32位二進制IPv4地址 inet_ntop(AF_INET),inet_ntoa
#include <stdio.h> #include <string.h> #include <arpa/inet.h> int main(int argc, char **argv) { const char *ip_str = "127.0.0.1"; char *ip_res; in_addr_t addr_t; struct in_addr addr; //1.str -> binary inet_aton(ip_str, &addr); printf("inet_aton::%x\n", addr); //1000007f addr_t = inet_addr(ip_str); printf("inet_addr::%x\n", addr_t); //1000007f inet_pton(AF_INET, ip_str, (void *)&addr); //1000007f printf("inet_pton::%x\n", addr); //2.binary -> str ip_res = inet_ntoa(addr); printf("inet_ntoa::%s\n", ip_res); //127.0.0.1 inet_ntop(AF_INET, &addr, ip_res, INET_ADDRSTRLEN); printf("inet_ntop::%s\n", ip_res); //127.0.0.1 return 0; } output: inet_aton::100007f inet_addr::100007f inet_pton::100007f inet_ntoa::127.0.0.1 inet_ntop::127.0.0.1