1. sockaddr/sockaddr_in/in_addr (IPv4)、sockaddr6_in/in6_addr/addrinfo (IPv6)
struct sockaddr { 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); } |