sockaddr & sockaddr_in & IPV4地址 & IPV6地址 & inet_addr & inet_ntop & inet_pton & inet_aton & inet_ntoa

sockaddr & sockaddr_in & IPV4地址 & IPV6地址 & inet_addr & inet_ntop & inet_pton & inet_aton & inet_ntoa_第1张图片

1.IPV4地址用socket_in结构体表示;
2.IPV4和IPV6地址类型分别定义为常数AF_INET、AF_INET6;
3.IPV4和IPV6在定义时定义为struct sockaddr_in*结构,但是socket API的接口接
受struct sockaddr*结构,故在使用地址的时候需要强转为struct sockaddr*结
构,这样的好处就是可以提高代码的通用性,可以接收IPV4、IPV6;
4.sockaddr_in结构包含三部分信息:
  (1)地址类型(例如AF_INET是IPV4,AF_INET6是IPV6)
  (2)端口号
  (3)IP地址
  5.IP地址位于sockaddr_in中的sin_addr中的s_addr;
  6.端口号位于sockaddr_in中的sin_port
  7.地址类型位于sockaddr_in中的sin_family

把点分十进制字符串表示的IP地址转换为网络网络字节序的整数表示的IP地址

1.inet_aton(const char*strprt,struct in_addr*addrptr)

2.int addr_t inet addr(const char*strptr)
参数说明:
strptr:是点分十进制表示的IP地址

3.int inet_pton(int family,const char*strptr,void*addrptr)
参数说明:
  (1)family:指定是那种地址族,例如AF_INET是IPV4,AF_INET6是IPV6
  (2)strptr:是点分十进制的IP地址
  (3)addrptr:是一个指针,指向一块内存,用于存储转换之后的结果
返回值:
   成功:返回1
   失败:返回0

把网络字节序的整数表示的IP地址转换为点分十进制字符串表示的IP地址

1.char* inet_ntoa(struct in_addr inaddr);

2.const char* inet_ntop(int family,const void*addrptr,char*strptr,
                        size_t len);

返回值:
     成功:返回目标存储单元的地址
     失败:返回NULL

用于转换IPV4地址的函数:inet_aton()、inet_addr()、inet_ntoa()
用于转换IPV4和IPV6地址的函数:inet_ntop()、inet_pton()
ps:注意inet_aton()不是线程安全函数

inet_ntoa()

inet_ntoa函数返回一个char*,此函数是自己在内部申请了一块内存来保存ip的结果,而且此内存还是一块静态存储区,所以会导致inet_ntoa不安全,第二次调用的结果会覆盖掉第一次的调用结果,故在多线程下推荐使用inet_ntop函数,此函数是由调用者提供一个缓冲区来保存结果的,可以规避线程安全问题

示例
1.调用i两次net_ntoa(),测试inet_ntoa()的静态存储区

#include
#include
#include
int main()
{
 struct sockaddr_in addr1;
 struct sockaddr_in addr2;
 addr1.sin_addr.s_addr=0;
 addr2.sin_addr.s_addr=0xffffffff;
 char*ptr1=inet_ntoa(addr1.sin_addr);
 char*ptr2=inet_ntoa(addr2.sin_addr);
 printf("ptr1:%s,ptr2:%s\n",ptr1,ptr2);
 return 0;
 }

运行结果:
这里写图片描述
结果解析:第二次调用inet_ntoa时 ,把第一次的结果覆盖了,所以没有输出两次255.255.255.255,没有输出IP地址为0.0.0.0

2.在多线程中使用inet_ntoa(),测试inet_nton()的不安全性

#include
#include
#include
#include
#include
#include
#include
void* ThreadEnter1(void* addr)
{
    struct sockaddr_in* addr1=(struct sockaddr_in*)addr;
    char* ptr1=inet_ntoa(addr1->sin_addr);
    printf("addr1:%s\n",ptr1);
    return NULL;
}
void*ThreadEnter2(void*addr)
{
    struct sockaddr_in* addr2=(struct sockaddr_in*)addr;
    char* ptr2=inet_ntoa(addr2->sin_addr);
    printf("addr2:%s\n",ptr2);
    return NULL;
}
int main()
{
    pthread_t tid1,tid2;
    struct sockaddr_in addr1;
    struct sockaddr_in addr2;
    addr1.sin_addr.s_addr=0;
    addr2.sin_addr.s_addr=0xffffffff;
    pthread_create(&tid1,NULL,ThreadEnter1,&addr1);
    pthread_create(&tid2,NULL,ThreadEnter2,&addr2);
    pthread_detach(tid1);
    pthread_detach(tid2);
    while(1){
        printf("I am main\n");
        sleep(1);
    }
    return 0;
}

运行结果:
sockaddr & sockaddr_in & IPV4地址 & IPV6地址 & inet_addr & inet_ntop & inet_pton & inet_aton & inet_ntoa_第2张图片
结果解析:程序输出了我们想要的结果,第二次调用inet_ntoa函数并没有覆盖第一次的结果,我的系统是Centos6.5,此系统内部可能实现了互斥锁,所以没有出现线程安全问题(两次输出255.255.255.255),但是inet_ntoa函数不是线程安全函数,会引起多线程不安全问题,在多线程中推荐使用inet_ntop函数

一般用于把点分十进制的IPV4地址转换为网络字节序的函数是inet_addr()
一般用于把网络字节序的IPV4地址转换为点分十进制的函数是inet_ntoa()

你可能感兴趣的:(linux,socket,inet_addr,inet_ntoa)