网络编程中常见地址结构与转换(IPv4/IPv6)
1. sockaddr/sockaddr_in/in_addr (IPv4)、sockaddr6_in/in6_addr/addrinfo (IPv6)
struct
sockaddr { http://www.cnblogs.com/sunada2005/p/3240724.html
unsigned
short
sa_family;
/* address family, AF_xxx */
char
sa_data[14];
/* 14 bytes of protocol address */
};
struct
sockaddr_in {
short
int
sin_family;
/* Address family AF_INET */
unsigned
short
int
sin_port;
/* Port number */
struct
in_addr sin_addr;
/* Internet address */
unsigned
char
sin_zero[8];
/* Same size as struct sockaddr */
}; <br>
struct
in_addr {
unsigned
long
s_addr;
/* Internet address */
};
struct
sockaddr_in6 {
sa_family_t sin6_family;
/* AF_INET6 */
in_port_t sin6_port;
/* transport layer port # */
uint32_t sin6_flowinfo;
/* IPv6 traffic class & flow info */
struct
in6_addr sin6_addr;
/* IPv6 address */
uint32_t sin6_scope_id;
/* set of interfaces for a scope */
};
struct
in6_addr {
uint8_t s6_addr[16];
/* IPv6 address */
};
struct
addrinfo{
int
ai_flags;
/* AI_PASSIVE,AI_CANONNAME,AI_NUMERICHOST */
int
ai_family;
/* AF_INET,AF_INET6 */
int
ai_socktype;
/* SOCK_STREAM,SOCK_DGRAM */
int
ai_protocol;
/* IPPROTO_IP, IPPROTO_IPV4, IPPROTO_IPV6 */
size_t ai_addrlen;
/* Length */
char
*ai_cannoname;
/* */
struct
sockaddr *ai_addr;
/* struct sockaddr */
struct
addrinfo *ai_next;
/* pNext */
}
|
2. 与IP地址相关的常用网络编程函数
2.1 地址转化函数
IPv4中,可使用inet_ntoa/inet_aton来转化字符串形式表示的IPv4地址和数字形式表示的IPv4地址。此两函数不适用于IPv6地址转换。在Linux环境下使用inet_ntoa/inet_atoa时,需加头文件:
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
|
函数原型:
int
inet_aton(
const
char
* cp,
struct
in_addr *inp);
char
* inet_ntoa(
struct
in_addr
in
);
|
举例:
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
int
main(
int
aargc,
char
* argv[])
{
struct
in_addr addr1;
ulong
l1;
l1 = inet_addr(
"192.168.0.74"
);
memcpy(&addr1, &l1,
sizeof
(l1));
printf(
"%s\n"
, inet_ntoa(addr1));
if
(inet_aton(
"127.0.0.1"
, &addr1)){
printf(
"inet_aton:ip=%lu\n"
,ntohl(inp.s_addr));
}
else
{
printf(
"inet_aton return -1 when 255.255.255.255\n"
);
}
return
0;
}
|
IPv6中,使用inet_ntop/inet_pton来转化字符串形式表示的IPv6地址和数字形式表示的IPv6地址。IPv4中也可使用这两个函数。
函数原型:
int
inet_pton(
int
af,
const
char
*src,
void
*dst); <br>
//这个函数转换字符串到网络地址,第一个参数af是地址族,转换后存在dst中 af的值可为AF_INET (代表使用IPv4协议)或AF_INET6(代表作用IPv6协议)
const
char
*inet_ntop(
int
af,
const
void
*src,
char
*dst, socklen_t cnt);
//这个函数转换网络二进制结构到ASCII类型的地址,参数的作用和上面相同,只是多了一个参数socklen_t cnt,
//他是所指向缓存区dst的大小,避免溢出,如果缓存区太小无法存储地址的值,则返回一个空指针,并将errno置为ENOSPC
|
举例:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
int
main(
int
argc,
char
**argv)
{
unsigned
char
buf[
sizeof
(
struct
in6_addr)];
int
domain, s;
char
str[INET6_ADDRSTRLEN];
if
(argc != 3){
fprintf(stderr,
"usage: %s {i4|i6|<num>} string/n"
, argv[0]);
exit(EXIT_FAILURE);
}
domain = (strcmp(argv[1],
"i4"
) == 0) ? AF_INET:(strcmp(argv[1],
"i6"
) == 0) ? AF_INET6 : atoi(argv[1]);
//IP字符串 ——》网络字节流
s = inet_pton(domain, argv[2], buf);
if
(s<=0){
if
(0 == s)
fprintf(stderr,
"Not in presentation format/n"
);
else
perror(
"inet_pton"
);
exit(EXIT_FAILURE);
}
//网络字节流 ——》IP字符串
if
(inet_ntop(domain, buf, str, INET6_ADDRSTRLEN) == NULL){
perror(
"inet ntop/n"
);
exit(EXIT_FAILURE);
}
printf(
"%s/n"
, str);
exit(EXIT_SUCCESS);
}
|