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;
}
运行结果:
结果解析:程序输出了我们想要的结果,第二次调用inet_ntoa函数并没有覆盖第一次的结果,我的系统是Centos6.5,此系统内部可能实现了互斥锁,所以没有出现线程安全问题(两次输出255.255.255.255),但是inet_ntoa函数不是线程安全函数,会引起多线程不安全问题,在多线程中推荐使用inet_ntop函数
一般用于把点分十进制的IPV4地址转换为网络字节序的函数是inet_addr()
一般用于把网络字节序的IPV4地址转换为点分十进制的函数是inet_ntoa()