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 */
};
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);
//這個函數轉換字符串到網絡地址,第一個參數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);
}
