网络编程中常见地址结构与转换(IPv4/IPv6)

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);     
}

 

 

你可能感兴趣的:(网络编程)