IP地址轉換函數

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().

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章