1. 網(wǎng)絡字節(jié)序與主機字節(jié)序
1.1 主機字節(jié)序()
CPU的字節(jié)順序類型,
- 小端,little endian;
- 大端,big endian;
1.2 網(wǎng)絡字節(jié)序
TCP/IP中規(guī)定好的一種數(shù)據(jù)表示格式,它與具體使用的CPU類型和操作系統(tǒng)類型無關;網(wǎng)絡字節(jié)序固定的采用大端終結的方式
1.3 字節(jié)序轉換函數(shù)
- htons:主機序 -> 網(wǎng)絡序,處理unsigned short類型;
- htonl:主機序 -> 網(wǎng)絡序,處理unsigned long類型;
- ntohs:網(wǎng)絡序 -> 主機序, 處理unsigned short類型;
- ntohl:網(wǎng)絡序 -> 主機序,處理unsigned long類型;
2. Socket地址結構
2.1 sockaddr結構體
定義如下,這個結構體會作為bind、connect、recvfrom、sendto等函數(shù)的輸入地址參數(shù)結構體,
struct sockaddr {
sa_family_t sa_family;
char sa_data[14];
}
這里的sa_data包含了地址+端口號
2.2 sockaddr_in結構體
struct sockaddr_in {
sa_family_t sin_family; /* address family: AF_INET */
in_port_t sin_port; /* port in network byte order */
struct in_addr sin_addr; /* internet address */
};
/* Internet address. */
struct in_addr {
uint32_t s_addr; /* address in network byte order */
};
這個結構體的大小和sockaddr結構體的大小一致,可以互相轉換;
在網(wǎng)絡編程中我們會對sockaddr_in的結構體進行操作賦值,使用這個結構體建立地址信息;然后強制類型轉換成sockaddr并傳遞給調用函數(shù),
struct sockaddr_in servaddr;
bzero( (void *)&servaddr, sizeof(servaddr) );
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl( INADDR_ANY );
servaddr.sin_port = htons(MY_PORT_NUM);
sctp_bindx( sock_fd, (struct sockaddr *)&servaddr, addr_count, SCTP_BINDX_ADD_ADDR)
- 使用htonl和htons進行字節(jié)序轉換;
- 強制類型轉換sockaddr_in到sockaddr作為bind的輸入?yún)?shù);
3. 轉換函數(shù)
3.1 inet_ntop函數(shù)
函數(shù)把一個網(wǎng)絡字節(jié)序的二進制的IP地址轉換成一個ASCII類型的IP,定義如下,
#include <arpa/inet.h>
const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
- af 代表地址族,比如說AF_NET或者AF_INET6;
- 這個函數(shù)把src地址轉換結果保存到dst指向的buffer中;比如說IPv4的時候把一個in_addr的結構體轉換成“ddd. ddd. ddd. ddd”的IP地址結構;
3.2 inet_pton函數(shù)
這個函數(shù)的功能和inet_ntop函數(shù)恰好相反,
#include <arpa/inet.h>
int inet_pton(int af, const char *src, void *dst);
轉換的網(wǎng)絡序的二進制IP會寫入dst指向的內存中;這個函數(shù)可以用來把一個IP字符串轉換并賦值給地址結構體;
來看一個簡單的例子,
struct sockaddr_in sa;
char ip[20];
inet_pton(AF_INET, "172.0.0.1", &(sa.sin_addr));
printf("[inet_pton]: IP addr --> binary: %x\n", sa.sin_addr);
inet_ntop(AF_INET, &(sa.sin_addr), ip, 20);
printf("[inet_ntop]: binary --> IP address: %s\n", ip);
打印出來的信息如下,
- 結果是以16進制打印的,網(wǎng)絡字節(jié)序是大端終結;對打印結果拆解一下就是,01 - 00 - 00 - ac;每個小數(shù)點隔開的數(shù)字都以一個字節(jié)存儲,比如說AC就是172的16進制表示;
inet_pton: IP addr --> binary: 10000ac
- 恢復成字符串IP地址
[inet_ntop]: binary --> IP address: 172.0.0.1
3.3 inet_addr函數(shù)
把一個小數(shù)點分隔的IP轉換成一個網(wǎng)絡字節(jié)序的長整型的數(shù)(u_long)
in_addr_t inet_addr(const char *cp);
舉個簡單的例子
printf("[inet_addr]: IP addr --> binary: %x\n", inet_addr("172.0.0.1"))
打印結果
[inet_addr]: IP addr --> binary: 10000ac