Linux API 网址转换(DWORD, IP,域名)

本文详细介绍了IP地址在不同形式间的转换方法,包括点分十进制到DWORD的转换、域名到IP地址的解析等,并提供了实用的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

做网络模块的时候经常会遇到有关网址的处理.一般大致的情形是3种:

1.得到的是域名,如:www.3322.org

2.得到的是实际的IP地址,如:61.160.235.203

3.得到的是经过inet_addr处理过的IP,为unsigned long(DWORD)

一.那么如果是给出点分制的IP要转为DWORD型是如何转化呢?这个其实最简单,有专门的函数专门处理此事

unsigned long dwIP = inet_addr("222.212.12.77");
printf("IP(%s)->DWORD(%lu)/n");

//output
IP(222.212.12.77)->DWORD(1292686558)

 

二.第一种情况的逆转化

#include <stdio.h>
#include <stdlib.h>
#include <sys/select.h>
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#include <string.h>

int main(int argc, char *argv[])
{
	struct in_addr net;
	char tmp[16] = {0};

	if(argc != 3)
	{
		printf("You MUST enter 3 varibal.No.1:func name No.2:case.No.3:ip(string or DWORD)/n");
		return 0;
	}

	if(strcmp("1", argv[1]) == 0) 
	{
		char* ip_string;
		ip_string = argv[2];
		unsigned long dword = inet_addr(ip_string);

		printf("IP(%s)-->DWORD(%lu)/n", ip_string, dword);
	}
	else if(strcmp("2", argv[1]) == 0)
	{
		net.s_addr = (unsigned long)atol(argv[2]);
		strcpy(tmp, inet_ntoa(net));
		printf("DWORD(%s)-->IP(%s)/n",argv[2], tmp);
	}
	return 0;
}
这里给出一个点分制IP和DWORD相互转化的程序
三.如果给出的是域名而想得到点分制的IP呢?
这里给出一个接口,支持输入的类型是点分制和域名2中类型,返回的是DWORD型的IP
有一点要声明的是gethostbyname这个函数必须在网络连通的情况下才能正确完成域名的解析,你想,连个网都不通,它怎么解析?
#include <stdio.h>
#include <stdlib.h>
#include <sys/select.h>
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#include <string.h>


#define DWORD unsigned long

DWORD platform_domain2ip(const char *szDomain, char *szDotNumIP)
{
	char szAddr[32] = {0};
	struct hostent *pHost;

	printf("input domain name(%s)/n", szDomain);
	

	if((pHost = gethostbyname(szDomain)) == NULL)
	{
		printf("can not parse domain/n");
		return -1;
	}
	printf("HostName :%s/n",pHost->h_name);
	strcpy(szAddr, inet_ntoa(*((struct in_addr *)pHost->h_addr)));
	printf("IP Address :%s/n", szAddr);
	strcpy(szDotNumIP, szAddr);

	return inet_addr(szAddr);
}

int main(int argc, char *argv[])
{
	DWORD dwip;
	char *ip = malloc(32);
	//dwip = platform_domain2ip("www.3322.org", ip);
	dwip = platform_domain2ip("61.160.235.203", ip);
	printf("ip 1 (%s) 2 dw(%lu)/n", ip, dwip);
	return 0;
}
//可以将main的注册分别打开来判断下结果是否正确,这里给出运行的结果,有图有真相
编译的命令再说下吧,怕有人不知道
gcc gethost.c –Wall –o gethost//在linux下
arm-hismall-linux-gcc gethost.c –Wall –o gethost//嵌入式环境下
 
此接口已经在我的工程中使用,在平台IP的解析和3322的解析中得到了应用,所以是稳定可行的.
这3中IP的转化都了解了的话,那么网络编程不就扫除了一个大石头吗?呵呵,大家功能进步
 
网上比较流行的gethostbyname的例子如下,受到了启发
#include <stdio.h>
#include <stdlib.h>
#include <sys/select.h>
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#include <string.h>

int main(int argc, char **argv)
{
    char *ptr,**pptr;
    struct hostent *hptr;
    char str[32];

    /* 取得命令后第一个参数,即要解析的域名或主机名 */ 
    ptr = argv[1];

    /* 调用gethostbyname()。调用结果都存在hptr中 */ 
    if((hptr = gethostbyname(ptr)) == NULL)
    {
        printf("gethostbyname error for host:%s/n", ptr);
        return 1; /* 如果调用gethostbyname发生错误,返回1 */
    }

     
    printf("official hostname:%s/n",hptr->h_name);

    /* 主机可能有多个别名,将所有别名分别打出来 */ 
    for(pptr = hptr->h_aliases; *pptr != NULL; pptr++)
        printf("  alias:%s/n",*pptr);

    /* 根据地址类型,将地址打出来 */
    switch(hptr->h_addrtype)
    {
        case AF_INET:
        case AF_INET6:
            pptr=hptr->h_addr_list;

            /* 将刚才得到的所有地址都打出来。其中调用了inet_ntop()函数*/
            for(;*pptr!=NULL;pptr++)
            printf("  address:%s/n", inet_ntop(hptr->h_addrtype,*pptr, str, sizeof(str)));
        break;
        default:
            printf("unknown address type/n");
        break;
    }

    return 0;
}
/* 程序名称:路由追踪(Tracert)程序 实现原理:Tracert 程序关键是对 IP 头部生存时间(time to live)TTL 字段的使用,程序实现时是向目 地主机发送一个 ICMP 回显请求消息,初始时 TTL 等于 1,这样当该数据报抵达途中的第一个路由器 时,TTL 的值就被减为 0,导致发生超时错误,因此该路由生成一份 ICMP 超时差错报文返回给源主 机。随后,主机将数据报的 TTL 值递增 1,以便 IP 报能传送到下一个路由器,并由下一个路由器生成 ICMP 超时差错报文返回给源主机。不断重复这个过程,直到数据报达到最终的目地主机,此时目地 主机将返回 ICMP 回显应答消息。这样,源主机只需对返回的每一份 ICMP 报文进行解析处理,就可 以掌握数据报从源主机到达目地主机途中所经过的路由信息。 */ #include <iostream> #include <winsock2.h> #include <ws2tcpip.h> #include<map> #include<vector> using namespace std; #pragma comment(lib, "Ws2_32.lib") //IP 报头 typedef struct { unsigned char hdr_len:4; //4 位头部长度 unsigned char version:4; //4 位版本号 unsigned char tos; //8 位服务类型 unsigned short total_len; //16 位总长度 unsigned short identifier; //16 位标识符 unsigned short frag_and_flags; //3 位标志加 13 位片偏移 unsigned char ttl; //8 位生存时间 unsigned char protocol; //8 位上层协议号 unsigned short checksum; //16 位校验和 unsigned long sourceIP; //32 位源 IP 地址 unsigned long destIP; //32 位目的 IP 地址 } IP_HEADER; //ICMP 报头 typedef struct { BYTE type; //8 位类型字段 BYTE code; //8 位代码字段 USHORT cksum; //16 位校验和 USHORT id; //16 位标识符 USHORT seq; //16 位序列号 } ICMP_HEADER; //报文解码结构 typedef struct { USHORT usSeqNo; //序列号 DWORD dwRoundTripTime; //往返时间 in_addr dwIPaddr; //返回报文的 IP 地址 } DECODE_RESULT; vector< pair<string,string> > IpAddressStatus1; //计算网际校验和函数 USHORT checksum(USHORT *pBuf,int iSize) { unsigned long cksum=0; while(iSize>1) { cksum+=*pBuf++; iSize-=sizeof(USHORT); } if(iSize) { cksum+=*(UCHAR *)pBuf; } cksum=(cksum>>16)+(cksum&0xffff); cksum+=(cksum>>16); return (USHORT)(~cksum); } //对数据包进行解码 BOOL DecodeIcmpResponse(char * pBuf,int iPacketSize,DECODE_RESULT &DecodeResult,BYTE ICMP_ECHO_REPLY,BYTE ICMP_TIMEOUT) { //检查数据报大小的合法性 IP_HEADER* pIpHdr = (IP_HEADER*)pBuf; int iIpHdrLen = pIpHdr->hdr_len * 4; if (iPacketSize < (int)(iIpHdrLen+sizeof(ICMP_HEADER))) return FALSE; //根据 ICMP 报文类型提取 ID 字段和序列号字段 ICMP_HEADER *pIcmpHdr=(ICMP_HEADER *)(pBuf+iIpHdrLen); USHORT usID,usSquNo; if(pIcmpHdr->type==ICMP_ECHO_REPLY) { //ICMP 回显应答报文 usID=pIcmpHdr->id; //报文 ID usSquNo=pIcmpHdr->seq; //报文序列号 } else if(pIcmpHdr->type==ICMP_TIMEOUT) { //ICMP 超时差错报文 char * pInnerIpHdr=pBuf+iIpHdrLen+sizeof(ICMP_HEADER); //载荷中的 IP 头 int iInnerIPHdrLen=((IP_HEADER *)pInnerIpHdr)->hdr_len*4; //载荷中的 IP 头长 ICMP_HEADER * pInnerIcmpHdr=(ICMP_HEADER *)(pInnerIpHdr+iInnerIPHdrLen);//载荷中的 ICMP 头 usID=pInnerIcmpHdr->id; //报文 ID usSquNo=pInnerIcmpHdr->seq; //序列号 } else { return false; } //检查 ID 和序列号以确定收到期待数据报 if(usID!=(USHORT)GetCurrentProcessId()||usSquNo!=DecodeResult.usSeqNo) { return false; } // cout<<" pIpHdrLen="<<htons(pIpHdr->total_len); //填充序列号<<" "; cout<<" bytes="<<(int)iPacketSize-iIpHdrLen-8<<" "; cout<<"ttl="<<(int)pIpHdr->ttl<<" "; // cout<<"Protocol:"<<(int)pIpHdr->protocol<<"\n"; //记录 IP 地址并计算往返时间 DecodeResult.dwIPaddr.s_addr=pIpHdr->sourceIP; DecodeResult.dwRoundTripTime=GetTickCount()-DecodeResult.dwRoundTripTime; //处理正确收到的 ICMP 数据报 if (pIcmpHdr->type == ICMP_ECHO_REPLY ||pIcmpHdr->type == ICMP_TIMEOUT) { //输出往返时间信息 if(DecodeResult.dwRoundTripTime) cout<<" 时间="<<DecodeResult.dwRoundTripTime<<"ms"<<flush; else cout<<" "<<"时间<1ms"<<flush; } return true; } int main(void) { //初始化 Windows sockets 网络环境 WSADATA wsa; WSAStartup(MAKEWORD(2,2),&wsa); char IpAddress[255]; map<string,string> IpAddressStatus; int ip1,ip2,ip3,ip4,ip5; int cnt = 255; int maxHops = 20; int maxTimeout=1000; cout<<"请输入一个 IP 地址范围(如192.168.142.119-255,只需要输入192 168 142 119 255):"; cin>>ip1>>ip2>>ip3>>ip4>>ip5; cnt=ip5-ip4; while(ip1>255||ip2>255||ip3>255||ip4>255||cnt<0) { cout<<"输入的 IP 地址范围无效!请重新输入:"<<"\n"; cin>>ip1>>ip2>>ip3>>ip4>>ip5; cnt=ip5-ip4; } cout<<"请输入超时时间(ms):"; cin>>maxTimeout; cout<<"最大路由跳数:"; cin>>maxHops; while(cnt>=0) { // if(ip1>255||ip2>255||ip3>255||ip4>255||) { // cout<<"输入的 IP 地址范围无效!请重新输入:"<<"\n"; // cin>>ip1>>ip2>>ip3>>ip4>>ip5; // cnt=ip5-ip4; // } sprintf(IpAddress,"%d.%d.%d.%d",ip1,ip2,ip3,ip5-cnt); cnt--; //得到 IP 地址 u_long ulDestIP=inet_addr(IpAddress); cout<<"\n正在 ping 的 ip 地址:"<<IpAddress<<"\n"; //转换不成功时按域名解析 if(ulDestIP==INADDR_NONE) { hostent * pHostent=gethostbyname(IpAddress); if(pHostent) { ulDestIP=(*(in_addr*)pHostent->h_addr).s_addr; } else { cout<<"输入的 IP 地址或域名无效!"<<endl; WSACleanup(); return 0; } } // cout<<"Tracing route to "<<IpAddress<<" with a maximum of "<<maxHops<<" hops.\n"<<endl; //填充目地端 socket 地址 sockaddr_in destSockAddr; ZeroMemory(&destSockAddr,sizeof(sockaddr_in)); destSockAddr.sin_family=AF_INET; destSockAddr.sin_addr.s_addr=ulDestIP; //创建原始套接字 SOCKET sockRaw=WSASocket(AF_INET,SOCK_RAW,IPPROTO_ICMP,NULL,0, WSA_FLAG_OVERLAPPED); //超时时间 int iTimeout=maxTimeout; //接收超时 setsockopt(sockRaw,SOL_SOCKET,SO_RCVTIMEO,(char *)&iTimeout,sizeof(iTimeout)); //发送超时 // setsockopt(sockRaw,SOL_SOCKET,SO_SNDTIMEO,(char *)&iTimeout,sizeof(iTimeout)); //构造 ICMP 回显请求消息,并以 TTL 递增的顺序发送报文 //ICMP 类型字段 const BYTE ICMP_ECHO_REQUEST=8; //请求回显 const BYTE ICMP_ECHO_REPLY=0; //回显应答 const BYTE ICMP_TIMEOUT=11; //传输超时 //其他常量定义 const int DEF_ICMP_DATA_SIZE=32; //ICMP 报文默认数据字段长度 const int MAX_ICMP_PACKET_SIZE=1024;//ICMP 报文最大长度(包括报头) const DWORD DEF_ICMP_TIMEOUT=maxTimeout; //回显应答超时时间 // const int DEF_MAX_HOP=30; //最大跳站数 const int DEF_MAX_HOP=maxHops; //最大跳站数 //填充 ICMP 报文中每次发送时不变的字段 char IcmpSendBuf[sizeof(ICMP_HEADER)+DEF_ICMP_DATA_SIZE];//发送缓冲区 memset(IcmpSendBuf, 0, sizeof(IcmpSendBuf)); //初始化发送缓冲区 char IcmpRecvBuf[MAX_ICMP_PACKET_SIZE]; //接收缓冲区 memset(IcmpRecvBuf, 0, sizeof(IcmpRecvBuf)); //初始化接收缓冲区 ICMP_HEADER * pIcmpHeader=(ICMP_HEADER*)IcmpSendBuf; pIcmpHeader->type=ICMP_ECHO_REQUEST; //类型为请求回显 pIcmpHeader->code=0; //代码字段为 0 pIcmpHeader->id=(USHORT)GetCurrentProcessId(); //ID 字段为当前进程号 memset(IcmpSendBuf+sizeof(ICMP_HEADER),'E',DEF_ICMP_DATA_SIZE);//数据字段 USHORT usSeqNo=0; //ICMP 报文序列号 int iTTL=1; //TTL 初始值为 1 BOOL bReachDestHost=FALSE; //循环退出标志 int iMaxHot=DEF_MAX_HOP; //循环的最大次数 DECODE_RESULT DecodeResult; //传递给报文解码函数的结构化参数 int flag=0; int ping_ttl=4; while(!bReachDestHost&&ping_ttl--) { //设置 IP 报头的 TTL 字段 // setsockopt(sockRaw,IPPROTO_IP,IP_TTL,(char *)&iTTL,sizeof(iTTL)); // cout<<iTTL<<flush; //输出当前序号 cout<<4-ping_ttl; //填充 ICMP 报文中每次发送变化的字段 ((ICMP_HEADER *)IcmpSendBuf)->cksum=0; //校验和先置为 0 ((ICMP_HEADER *)IcmpSendBuf)->seq=htons(usSeqNo++); //填充序列号 ((ICMP_HEADER *)IcmpSendBuf)->cksum=checksum((USHORT *)IcmpSendBuf, sizeof(ICMP_HEADER)+DEF_ICMP_DATA_SIZE); //计算校验和 //记录序列号和当前时间 DecodeResult.usSeqNo=((ICMP_HEADER*)IcmpSendBuf)->seq; //当前序号 DecodeResult.dwRoundTripTime=GetTickCount(); //当前时间 //发送 TCP 回显请求信息 sendto(sockRaw,IcmpSendBuf,sizeof(IcmpSendBuf),0,(sockaddr*)&destSockAddr,sizeof(destSockAddr)); //接收 ICMP 差错报文并进行解析处理 sockaddr_in from; //对端 socket 地址 int iFromLen=sizeof(from); //地址结构大小 int iReadDataLen; //接收数据长度 while(1) { //接收数据 iReadDataLen=recvfrom(sockRaw,IcmpRecvBuf,MAX_ICMP_PACKET_SIZE,0,(sockaddr*)&from,&iFromLen); // cout<<"iReadDataLen:"<<iReadDataLen<<"\n"; // cout<<"IcmpRecvBuf:"<<IcmpRecvBuf<<"\n"; if(iReadDataLen!=SOCKET_ERROR) { //有数据到达 //对数据包进行解码 if(DecodeIcmpResponse(IcmpRecvBuf,iReadDataLen,DecodeResult,ICMP_ECHO_REPLY,ICMP_TIMEOUT)) { //到达目的地,退出循环 if(DecodeResult.dwIPaddr.s_addr==destSockAddr.sin_addr.s_addr) // bReachDestHost=true; flag=1; //输出 IP 地址 cout<<'\t'<<inet_ntoa(DecodeResult.dwIPaddr)<<"\n"; // IpAddressStatus[IpAddress] = "在线"; // IpAddressStatus1.push_back(make_pair(IpAddress,"在线")); break; } // else{ // IpAddressStatus1.push_back(make_pair(IpAddress,"在线")); // break; // } } else if(WSAGetLastError()==WSAETIMEDOUT) { //接收超时,输出*号 cout<<" *"<<'\t'<<"Request timed out."<<endl; // IpAddressStatus1.push_back(make_pair(IpAddress,"不可达")); iTTL++; if(iTTL>6)break; break; } else { cout<<"错误\n"; break; } } // iTTL++; //递增 TTL 值 } if(flag) { IpAddressStatus1.push_back(make_pair(IpAddress,"在线")); } else { IpAddressStatus1.push_back(make_pair(IpAddress,"不可达")); } // if(iMaxHot <= 0) { // //cout<<"地址不可达\n"; IpAddressStatus[IpAddress] = "不可达"; // IpAddressStatus1.push_back(make_pair(IpAddress,"不可达")); // } } //迭代 cout<<"----------------------------------------------------------\n"; cout<<"ip 地址范围 "<<ip1<<"."<<ip2<<"."<<ip3<<"."<<ip4<<"-"<<ip5<<" 的 ping 情况:\n"; for(vector< pair<string,string> > ::iterator it = IpAddressStatus1.begin(); it != IpAddressStatus1.end(); it++) cout<<(*it).first<<":\t\t"<<(*it).second<<"\n";//输出key 和value值 } 优化该代码 且符合ICMP报文结构 实现Ping的基本操作 发送ICMP回显请求报文,用于测试主机与主机之间的连通情况
最新发布
05-29
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值