Linux网络编程基础API-socket地址API-1.1
一、主机字节序和网络字节序
1、字节序分为大端字节序(big endian)和小端字节序(littl endian):
- 大端字节序:一个整数的高位字节(23~31bit)存储在内存的低地址处,低位字节(0~7bit)存储在内存的高地址处;
- 小端字节序:一个整数的低位字节存储在内存的低地址处,高位字节存储在内存的高地址处。
2、现代PC大多采用小端字节序,小端字节序也称为主机字节序;
因为发送端和接收端使用的标准可能不同,所以需要发送端先转换为大端字节序然后发送,大端字节序也成为网络字节序。
即使是同一机器上的两个进程(如c和java编写的程序),也要考虑字节序的问题。
3、Linux提供的主机字节序和网络字节序之间的转换:
#include <netinet/in.h> unsigned long int htonl( unsigned long int hostlong); unsigned short int htons( unsigned short int hostshort ); unsigned long int ntohl( unsigned long int netlong); unsigned short int ntohs( unsigned short int netshort );
htonl表示“host to network long”,其他同理;长整型(long)通常是IP,短整型(short)通常是端口号。
二、通用socket地址
socket网络编程接口中表示scket地址的是结构体sockaddr:
#include <bits/socket.h> struct sockadd { sa_family_t sa_family; /*sa_family_t是地址族类型,协议族类型通常和地址族类型对应*/ char sa_data[14];/*sa_data用于存放socket地址值,注意 不同协议族的长度不同*/ };
协议族和协议族的关系:
协议族及其地址值:
由上表可见14字节的sa_data根本无法容纳多数协议族的地址值,故linux定义了下面的这个通用结构体:
#include <bits/ socket .h> struct sockaddr_ storage { sa_ family_ t sa_ family; unsigned long int __ss_ align; char __ss_ padding[128-sizeof (__ ss_ align )] ; }
三、专用socket地址
UNIX本地域协议族专用结构体:
include <sys/un.h> struct sockaddr_ un { sa_family_t sin_family; /* 地址族:AF_UNIX */ char sun_path[108]; /* 文件路径名 */ }
TCP/IP协议族的专用socket结构体:
struct sockaddr_ in { sa_ family_ t sin_family; /*地址族; AF_ INET */ u_int16_ t sin_port; /*端口号,要用网络字节序表示*/ struct in_addr sin_addr; /* 1PV4地址结构体,见下面*/ }; struct in_ addr u_int32_ t s_addr; /* IPv4 地址,要用网络宇节序表示*/ }; struct sockaddr_in6 { sa_family_t sin6_family;/*地址族: AF_ INET6 */ u_int16_t sn6_t sin6_port;/*端口号,要用网络字节序表示*/ u_int32_t sn6_t flowinfo;/*流信息,应设置为0 */ struct in6_addr sin6_addr;/* IPv6地址结构体,见下面*/ u_int32_t sin6_scope_id;/* scope ID, 尚处于实验阶段*/ }; struct in6_ addr { unsigned char sa_ addr[16] ;/* IPv6地址, 要用网络字节序表示*/ };
所有专用socket地址类型变量在实际使用时都需要转换为sockadd_storage,因为所有socket编程接口使用的地址参数都是sockaddr。
四、IP地址转换函数
1、 IPv4地址和用网络字节序整数表示的IPv4地址之间转换:
#include <arpa/inet.h> in_addr_t inet_addr ( const char* strptr ); int inet_aton( const char* cp, struct in_addr* inp ) ; char* inet_ntoa( struct in_addr in );
inet_addr:IPv4的点分十进制 转换为 网络字节序整数,失败返回INADDR_NONE;
inet_aton:和inet_addr结果一致,但转化结果存储在参数inp指向的地址结构中;
inet_ntoa:网络字节序整数 转换为 IPv4的点分十进制地址。
ps:inet_ntoa函数不可重入
2、适用于IPv4和IPv6的函数
#include <arpa/inet.h> int inet_pton( int af, const char* src, void* dst ); const char* inet_ntop( int af, const void* src, char* dst, socklen_t cnt );
inet_pton:字符串表示的IP地址 src 转换成 网络字节序整数表示的IP地址;
inet_ntop:相反的转换,最后一个cnt参数是指定目标存储单元大小的,下方两个宏帮助程序员指定这个大小:
#include <netinet/in.h> #define INET_ADDRSTRLEN 16 #define INET6_ADDRSTRLEN 46
inet_ntop成功时返回目标存储单元的地址,失败返回NULL 并设置error。