IPv4的socket網絡編程中,sockaddr_in中的成員struct in_addr sin-addr 表示32位的IP地址,但是通常我們使用的是點分十進制的字符串表示IP地址,那麼這兩個如何轉換呢?
#include<arpa/inet.h>
字符串轉in_addr的函數:
int_addr_t addr_t inet_addr(const char *strptr);
int inet_aton(const char* strptr,struct in_addr *addrptr);
int inet_pton(int family,const char* strptr,void *addrptr);
in_addr轉字符串的函數:
char *inet_ntoa(struct in_addr inaddr);
const char *inet_ntop(int famliy,const void*addrptr,char *strptr,size_t len);
我們在UDP中,初始化sockaddr_in時,調用了 int_addr_t inet_addr(const char* strptr),把我們的命令行參數中的IP地址轉換成了 int_addr_t
inet_ntop() 和 inet_pton() 函數不僅可以把IPv4的地址轉成字符串,而且還可以把IPv6的地址也轉成。
char *inet_ntoa(struct in_addr inaddr);
inet_ntoa() 返回的是一個指針,那麼我們可以想到,該函數肯定是在某個位置保存了我們的IP地址了。
那麼我們在調用結束的時候,是否需要去釋放該地址空間。
操作系統中說明,該函數存放的IP地址空間開闢在了靜態區,那麼該函數調用結束就不需要我們手動去釋放了。
提到靜態區,那是一個全局變量,共享的,我們必當想到的是 ——數據安全的問題。
我們看如下代碼:
#include<stdio.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<sys/socket.h>
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);
}
運行結果:
因爲inet_ntoa把結果放到自己內部的一個靜態儲存區中,這樣第二次調用的結果UI覆蓋掉上一次的結果。
在多線程環境下,推薦使用inet_ntop(),這個函數由調用者提供一個緩衝區保存結果,可以規避線程安全問題。
但是目前centos7中可能加了互斥鎖,所以並沒有出現覆蓋的情況。如一下測試:
#include<stdio.h>
#include<stdlib.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<pthread.h>
void *rout1(void *p)
{
struct sockaddr_in *addr = (struct sockaddr_in *)p;
while(1)
{
char *ptr = inet_ntoa(addr->sin_addr);
printf("addr1:%s\n",ptr);
}
return NULL;
}
void *rout2(void *p)
{
struct sockaddr_in *addr = (struct sockaddr_in *)p;
while(1)
{
char *ptr = inet_ntoa(addr->sin_addr);
printf("addr2:%s\n",ptr);
}
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,rout1,&addr1);
pthread_create(&tid2,NULL,rout2,&addr2);
pthread_join(tid1,NULL);
pthread_join(tid2,NULL);
return 0;
}
運行結果如下:
並沒有出現覆蓋的那種情況。
但是在APUE中,明確提出了inet_addr()函數不是線程安全的函數。
我們在多線程情況下,建議使用inet_ntop().