[原]socket通信实现域名解析

Posted secondtononewe

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[原]socket通信实现域名解析相关的知识,希望对你有一定的参考价值。

//extern     unsigned char gSntpServerIP[20];
int GetNTPTime(unsigned char *ntpServerIP,unsigned int ntpPort,unsigned int  *data)  
{  
    int sockfd=0;  
    char ntpServerName[20];
    
      
    STNP_Header H_NTP;        
    
    H_NTP.LiVnMode = 0x1b;//LI(2bit )  VN(3bit 版本)      Mode(3bit客户端模式)  
    H_NTP.Stratum = STRATUM;
    H_NTP.Poll = POLL;
    H_NTP.Precision =PREC;
    
    memset(ntpServerName,0,sizeof(ntpServerName));
    sprintf(ntpServerName,"%s",ntpServerIP);

    NF_LOG(DEBUG_K,"@[email protected],sync time from %s,H_NTP.Stratum=%d
", ntpServerName,H_NTP.Stratum); 

    #if 0//不能解析域名的方式
    struct sockaddr_in server;
    server.sin_family = AF_INET;  
    server.sin_addr.s_addr = gethostIPbyname((const char*)ntpServerName);  
    server.sin_port = htons(ntpPort);
    if(-1 == (int)server.sin_addr.s_addr)  
    {
        NF_LOG(ERROR_L,"[%s,%d]s_addr error...
",__FUNCTION__,__LINE__);
        return -1;  
    }
    
    sockfd = socket(AF_INET, SOCK_DGRAM, 0);  
    if(sockfd<0)  
    {  
        NF_LOG(ERROR_L,"[%s,%d]socket error...
",__FUNCTION__,__LINE__);
        return -1;  
    }
    #endif

    
    #if 1//getaddrinfo可以解析域名的方式
    int  rc;
    addrinfo hints, *res = NULL,*cur=NULL;
    memset(&hints, 0, sizeof(hints));
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_DGRAM;
    hints.ai_protocol = IPPROTO_UDP;
    char port[10];
    memset(port,0,sizeof(port));
    sprintf(port,"%d",ntpPort);
    rc = getaddrinfo((const char*)ntpServerName, port, &hints, &res);

    if (rc != 0) 
    {
        NF_LOG(ERROR_L,"[%s,%d]getaddrinfo error...rc=%s
",__FUNCTION__,__LINE__,gai_strerror(rc));
        
        return -1;  
    }

    struct sockaddr_in *addr;
    char m_ipaddr[16];
    memset(m_ipaddr,0,sizeof(m_ipaddr));
    
     for (cur = res; cur != NULL; cur = cur->ai_next) {
        addr = (struct sockaddr_in *)cur->ai_addr;
        inet_pton(AF_INET, m_ipaddr, (void *)addr);
        inet_ntop(AF_INET, (void *)&addr, m_ipaddr, 16);// 反转换
        printf("@[email protected]:Parse ip:%s
",m_ipaddr);
    }
    
    sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
    if (sockfd < 0) 
    {
        NF_LOG(ERROR_L,"[%s,%d]socket error...
",__FUNCTION__,__LINE__);
        return -1;  
    }
    #endif

    //if(sendto(sockfd, (void*)&H_NTP, sizeof(STNP_Header), 0, (struct sockaddr*)&server, sizeof(server))<0)  
    if(sendto(sockfd, (void*)&H_NTP, sizeof(STNP_Header), 0, res->ai_addr, res->ai_addrlen)<0)  
    {  
        NF_LOG(ERROR_L,"[%s,%d]sendto error...
",__FUNCTION__,__LINE__); 
        return -1;  
    }  
      
    fd_set r;  
    FD_ZERO(&r);  
    FD_SET(sockfd, &r);  
    struct timeval timeout;  
    timeout.tv_sec = 10;  
    timeout.tv_usec = 0;  
      
    if(1 != select(sockfd+1, &r, NULL, NULL, &timeout))  
    {
        NF_LOG(ERROR_L,"[%s,%d] select error...
",__FUNCTION__,__LINE__);
        return -1;  
    }
    
    if(recv(sockfd, (void*)data, 48, 0)<0) //48 后续要定义成宏
    {
        NF_LOG(ERROR_L,"[%s,%d]recv error...
",__FUNCTION__,__LINE__);
        return -1;  
    }
    
    close(sockfd);  
    return 0;  
}  
getaddrinfo函数

使用到的结构体理解
addrinfo
sockaddr_in
/* Internet address.  */

typedef __u16 in_port_t;
typedef __u32 in_addr_t;

struct in_addr
  {
    in_addr_t s_addr;
  };



/* Structure describing an Internet socket address.  */
struct sockaddr_in
  {
    __SOCKADDR_COMMON (sin_);
    in_port_t sin_port;            /* Port number.  */
    struct in_addr sin_addr;        /* Internet address.  */

    /* Pad to size of `struct sockaddr‘.  */
    unsigned char sin_zero[sizeof (struct sockaddr) -
               __SOCKADDR_COMMON_SIZE -
               sizeof (in_port_t) -
               sizeof (struct in_addr)];
  };

 

将sockaddr_in格式的地址,打印成点分十进制的方式:

  struct sockaddr_in *addr;
  char m_ipaddr[16];
  memset(m_ipaddr,0,sizeof(m_ipaddr));


for
(cur = res; cur != NULL; cur = cur->ai_next) { addr = (struct sockaddr_in *)cur->ai_addr; inet_pton(AF_INET, m_ipaddr, (void *)addr); inet_ntop(AF_INET, (void *)&addr, m_ipaddr, 16);// 反转换 printf("@[email protected]:Parse ip:%s ",m_ipaddr); }

 

 

======

需要区分下这些结构体的差异

sockaddr_in 用于IPV4的网络Internet IP/port,所以其结构成员sin_family必须填入AF_INET??

struct sockaddr_in server;
    server.sin_family = AF_INET;  
    server.sin_addr.s_addr = gethostIPbyname((const char*)ntpServerName);  
    server.sin_port = htons(ntpPort);
    if(-1 == (int)server.sin_addr.s_addr)  
    {
        NF_LOG(ERROR_L,"[%s,%d]s_addr error...
",__FUNCTION__,__LINE__);
        return -1;  
    }

 

   addrinfo  

addrinfo hints, *res = NULL,*cur=NULL;
    memset(&hints, 0, sizeof(hints));
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_DGRAM;
    hints.ai_protocol = IPPROTO_UDP;
    char port[10];
    memset(port,0,sizeof(port));
    sprintf(port,"%d",ntpPort);
    rc = getaddrinfo((const char*)ntpServerName, port, &hints, &res);

根据地址域获取到的信息存放在res

操作res获取的地址和port信息来链接及发送数据:
sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
    if (sockfd < 0) 
    {
        NF_LOG(ERROR_L,"[%s,%d]socket error...
",__FUNCTION__,__LINE__);
        return -1;  
    }

if(sendto(sockfd, (void*)&H_NTP, sizeof(NTP_Header), 0, res->ai_addr, res->ai_addrlen)<0)  
    {  
        NF_LOG(ERROR_L,"[%s,%d]sendto error...
",__FUNCTION__,__LINE__); 
        return -1;  
    } 

 

 

 getaddrinfo能够获取多个ip地址,这里可以去bind尝试看看哪个可以通来优化:

https://blog.csdn.net/an_zhenwei/article/details/8591729

 

 

 

待确认:
gethostIPbyname 不能解析地址域吗???当时之所以不能解析的原因是由于没有添加DNS服务器在resolv.conf






















以上是关于[原]socket通信实现域名解析的主要内容,如果未能解决你的问题,请参考以下文章

VC++调用gethostbyname实现域名解析(附源码)

Python实现将网站域名解析为ip地址

Python实现将网站域名解析为ip地址

网络通信与信息安全之深入解析TCP与UDP传输协议

Socket通信 客户端(Android)

Socket通信 客户端(Android)