您的位置:首页 > 运维架构 > Linux

Linux下c实现域名转IP的方法封装

2017-09-18 17:45 357 查看
arm开发板下运行时请确认你的开发板已联网

cat /etc/resolv.conf是否为空

urlIpTest_main.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>    //
#include <netdb.h>      // gethostbyname, gethostbyname2, gethostbyname_r, gethostbyname_r2
#include <setjmp.h>
#include <errno.h>

#include <fcntl.h>      // 非阻塞关键字
#include <stdbool.h>    // 使用bool变量
#include <pthread.h>    // 使用多线程

void delayus(unsigned int us)
{
struct timeval tim;
tim.tv_sec = us/1000000;
tim.tv_usec = us%1000000;
select(0, NULL, NULL, NULL, &tim);
}

////////////////////////////////// 域名转IP //////////////////////////////////

// 封装个和线程交互用的结构体
typedef struct{
pthread_t thread_id;
char ip[256];
bool result;
bool actionEnd;
}GetHostName_Struct;

// 调用 gethostbyname_r 函数需在单独的线程中调用, 阻塞时还可以外部超时退出
void *getHost_fun(void *arge)
{
int ret;
int i;
char buf[1024];
struct hostent host_body, *host;
struct in_addr **addr_list;
GetHostName_Struct *gs = (GetHostName_Struct *)arge;

/*  此类方法不可重入!  即使关闭线程
if((host = gethostbyname(gs->ip)) == NULL)
//if((host = gethostbyname2(gs->ip, AF_INET)) == NULL)
{
gs->actionEnd = true;
return NULL;
}*/
if(gethostbyname_r(gs->ip, &host_body, buf, sizeof(buf), &host, &ret))
{
gs->actionEnd = true;
return NULL;
}

if(host == NULL)
{
gs->actionEnd = true;
return NULL;
}
addr_list = (struct in_addr **)host->h_addr_list;

// 查看获得的ip列表
/*printf("ip name : %s\r\nip list : ", host->h_name);
for(i = 0; addr_list[i] != NULL; i++)
printf("%s, ", inet_ntoa(*addr_list[i]));
printf("\r\n");*/

// 默认返回列表第一条ip
if(addr_list[0] == NULL)
{
gs->actionEnd = true;
return NULL;
}
memset(gs->ip, 0, sizeof(gs->ip));
strcpy(gs->ip, (char *)inet_ntoa(*addr_list[0]));
gs->result = true;
gs->actionEnd = true;
return NULL;
}

// 封装方法, 成功返回调用耗时, 错误返回负数的耗时  (ms)
int getIpFromHostName(char *hostName, char *backIp)
{
int i, timeOut = 1;
GetHostName_Struct gs;
if(hostName == NULL)
return -1;
else if(strlen(hostName) < 1)
return -1;
//----- 开线程从域名获取IP -----
memset(&gs, 0, sizeof(GetHostName_Struct));
strcpy(gs.ip, hostName);
gs.result = false;
gs.actionEnd = false;
if (pthread_create(&gs.thread_id, NULL, getHost_fun, &gs) < 0)
return -1;
i = 0;
while(!gs.actionEnd)
{
if(++i > 10)
{
i = 0;
if(++timeOut > 1000)    // 1s 超时
break;
}
delayus(100);// 0.1ms延时
}
pthread_cancel(gs.thread_id);
if(!gs.result)
return -timeOut;
//----- 开线程从域名获取IP -----
memset(backIp, 0, strlen(backIp));
strcpy(backIp, gs.ip);
return timeOut;
}

////////////////////////////////// 域名转IP //////////////////////////////////

int main(int argc, char *argv[])
{
char ip[128] = {0};
int ret;
//
if(argc < 2)
{
printf("input such as : ./urlIpTest www.baidu.com\r\n");
return 0;
}
//
if((ret = getIpFromHostName(argv[1], ip)) > 0)
printf("host(%s) to ip(%s) , ret/%d\r\n", argv[1], ip, ret);
else
printf("test failed , ret/%d\r\n", ret);
//
return 0;
}

// 在tcp连接时的使用
/*
...
{
...
struct sockaddr_in sock_addr;

memset(&sock_addr,0,sizeof(sock_addr));

sock_addr.sin_family=AF_INET;
//获取IP不成功时可尝试调用域名转换

if((sock_addr.sin_addr.s_addr = inet_addr(ip)) == INADDR_NONE)

{

//printf("url is : %s\r\n", ip);

//

memset(buf, 0, sizeof(buf));

ret = getIpFromHostName(ip, buf);

if(ret < 0)

return ret;

else if(strlen(buf) < 7)

return -ret;

//

if((sock_addr.sin_addr.s_addr = inet_addr(buf)) == INADDR_NONE)

return -ret;

printf("Host(%s) to Ip(%s)\r\n", ip, buf);

}
...
}
*/


Makefile:

#CC=arm-linux-gnueabihf-
CC=
target:
$(CC)gcc -O3 -o urlIpTest urlIpTest_main.c -lpthread
clean:
@rm -rf urlIpTest
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: