在做服务器开发的时候,需要使用到ip地址。现在基本上服务器都是在ipv4版本里面。本文主要介绍的就是ipv4的方式。
struct sockaddr是通用的套接字地址,而struct sockaddr_in则是internet环境下套接字的地址形式,二者长度一样,都是16个字节。二者是并列结构,指向sockaddr_in结构的指针也可以指向sockaddr。一般情况下,需要把sockaddr_in结构强制转换成sockaddr结构再传入系统调用函数中。
数据结构定义
sockaddr
struct sockaddr {
sa_family_t sa_family; /* address family, AF_xxx */
char sa_data[14]; /* 14 bytes of protocol address */
}
sa_family :是2字节的地址家族,一般都是“AF_xxx”的形式,它的值包括三种:AF_INET,AF_INET6和AF_UNSPEC。
如果指定AF_INET,那么函数就不能返回任何IPV6相关的地址信息;如果仅指定了AF_INET6,则就不能返回任何IPV4地址信息。
AF_UNSPEC则意味着函数返回的是适用于指定主机名和服务名且适合任何协议族的地址。
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 */
};
sin_family:指代协议族,在socket编程中只能是AF_INET
sin_port:存储端口号(使用网络字节顺序)
sin_addr:存储IP地址,使用in_addr这个数据结构
in_addr
/* Internet address. */
struct in_addr {
uint32_t s_addr; /* address in network byte order */
};
s_addr是个int32的数字;ipv4。
sockaddr_in6
struct sockaddr_in6 {
sa_family_t sin6_family; /* AF_INET6 */
in_port_t sin6_port; /* port number */
uint32_t sin6_flowinfo; /* IPv6 flow information */
struct in6_addr sin6_addr; /* IPv6 address */
uint32_t sin6_scope_id; /* Scope ID (new in 2.4) */
};
in6_addr
struct in6_addr {
unsigned char s6_addr[16]; /* IPv6 address */
};
函数
endian相关
uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);
这些函数很容易背,h=host,n=network,s=short,l=long。
在做网络操作的时候一定要注意自己本地字节序和网络字节序差别。
ip地址转换工具
int inet_aton(const char *cp, struct in_addr *inp);
struct sockaddr_in adr_inet;
if( !inet_aton("127.0.0.1", &adr_inet.sin_addr))
char *inet_ntoa(struct in_addr in);
str_addr = inet_ntoa(session->sin.sin_addr);