[原]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,"@_@,sync time from %s,H_NTP.Stratum=%d\n", 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...\n",__FUNCTION__,__LINE__); return -1; } sockfd = socket(AF_INET, SOCK_DGRAM, 0); if(sockfd<0) { NF_LOG(ERROR_L,"[%s,%d]socket error...\n",__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\n",__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("@_@:Parse ip:%s\n",m_ipaddr); } sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (sockfd < 0) { NF_LOG(ERROR_L,"[%s,%d]socket error...\n",__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...\n",__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...\n",__FUNCTION__,__LINE__); return -1; } if(recv(sockfd, (void*)data, 48, 0)<0) //48 后续要定义成宏 { NF_LOG(ERROR_L,"[%s,%d]recv error...\n",__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("@_@:Parse ip:%s\n",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...\n",__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...\n",__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...\n",__FUNCTION__,__LINE__); return -1; }
getaddrinfo能够获取多个ip地址,这里可以去bind尝试看看哪个可以通来优化:
https://blog.csdn.net/an_zhenwei/article/details/8591729
待确认:
gethostIPbyname 不能解析地址域吗???当时之所以不能解析的原因是由于没有添加DNS服务器在resolv.conf