[关闭]
@rg070836rg 2017-01-09T22:51:11.000000Z 字数 6689 阅读 1253

TCP_IP第二次作业

TCP_IP


由于自己的偷懒,现在才开始补作业。
2017年1月9日19点

第二次 作业域名查询

域名解析协议(DNS)用来把便于人们记忆的主机域名和电子邮件地址映射为计算机易于识别的IP地址。DNS是一种c/s的结构,客户机就是用户用于查找一个名字对应的地址,而服务器通常用于为别人提供查询服务。

本次服务器采用的地址是谷歌的8.8.4.4

主要是利用winsock实现客户端查询。首先介绍几个必要的函数

1 初始化操作函数

按照之前的框架,进行winsock的初始化

  1. // 初始化操作
  2. bool initWSA()
  3. {
  4. WSADATA wsaData;
  5. int Result = WSAStartup( MAKEWORD( 2, 2 ), &wsaData );
  6. if(Result!=0 )
  7. {
  8. return false;
  9. }
  10. if( LOBYTE( wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion)!= 2 )
  11. {
  12. if(WSACleanup()==SOCKET_ERROR)//注释4
  13. cout<<"WSACleanup出错<<endl;
  14. return false;
  15. }
  16. return true;
  17. }

2 创建套接字

  1. //创建套接字,根据传来的类型创建,本程序需要创建UDP套接字
  2. SOCKET CreateSocket(int type)
  3. {
  4. SOCKET sock=socket(AF_INET,type,0);
  5. if (sock == INVALID_SOCKET )
  6. {
  7. return 0;
  8. }
  9. return sock;
  10. }

3 Dns头部结构

  1. typedef struct _DNSHEAD{ //dns 头部
  2. USHORT ID;
  3. USHORT tag; // dns 标志(参数)
  4. USHORT numQ; // 问题数
  5. USHORT numA; // 答案数
  6. USHORT numA1; // 权威答案数
  7. USHORT numA2; // 附加答案数
  8. }DnsHead;

4 dns 查询结构

  1. typedef struct _DNSQUERY //dns 查询结构
  2. {
  3. USHORT type;
  4. //查询类型,大约有20个不同的类型
  5. USHORT classes;
  6. //查询类,通常是A类既查询IP地
  7. }DnsQuery;

5 设置DNS 头部

  1. bool SetDNSHead(char *name,char *buf)
  2. {
  3. memset(buf,0,sizeof(DnsHead));
  4. //设置头部
  5. DnsHead *DnsH = (DnsHead *)buf;
  6. DnsH->ID = (USHORT)1;
  7. DnsH->tag = htons(0x0100);
  8. DnsH->numQ = htons(1);
  9. DnsH->numA = 0;
  10. DnsQuery *DnsQ =(DnsQuery *) ( buf+ sizeof(DnsHead) );
  11. int NameLen = ChName(name,(char *)DnsQ);
  12. //设置查询信息
  13. DnsQ = (DnsQuery *)( (char *)DnsQ + NameLen );
  14. DnsQ->classes = htons(1);
  15. DnsQ->type = htons(1);
  16. return true;
  17. }

6 发送DNS 请求

  1. int MySendto(SOCKET sockTo, const char FAR * buf,int len,char *addr,USHORT port)
  2. {
  3. if (addr[0]<'0'||addr[0]>'9') //addr 中不是IP 地址,域名解析
  4. {
  5. struct sockaddr_in addr_in;
  6. HOSTENT *host = NULL;
  7. host = gethostbyname(addr);//域名解析函数
  8. if ( host->h_addr_list[0]!=NULL )
  9. {
  10. memcpy (&addr_in.sin_addr.s_addr,host->h_addr_list[0], host->h_length);
  11. addr = inet_ntoa(addr_in.sin_addr);
  12. }
  13. }
  14. //设置发送数据到的 套接字及地址结构
  15. SOCKADDR_IN addrTo;
  16. addrTo.sin_addr.S_un.S_addr=inet_addr(addr);
  17. addrTo.sin_family=AF_INET;
  18. addrTo.sin_port=htons(port);
  19. return sendto(sockTo, buf, len, 0,(sockaddr*)&addrTo, sizeof(sockaddr));
  20. }

7 接受DNS请求

  1. int MyRecvFrom(SOCKET s, char FAR * buf,int len,char *addr,USHORT port)
  2. {
  3. if (addr[0]<'0'||addr[0]>'9') //addr 中不是IP 地址,域名解析
  4. {
  5. struct sockaddr_in addr_in;
  6. HOSTENT *host = NULL;
  7. host = gethostbyname(addr);//域名解析函数
  8. if ( host->h_addr_list[0]!=NULL )
  9. {
  10. memcpy ( &addr_in.sin_addr.s_addr,
  11. host->h_addr_list[0], host->h_length);
  12. addr = inet_ntoa(addr_in.sin_addr);
  13. }
  14. }
  15. //设置发送数据到的 套接字及地址结构
  16. SOCKADDR_IN addrFrom;
  17. addrFrom.sin_addr.S_un.S_addr=inet_addr(addr);
  18. addrFrom.sin_family=AF_INET;
  19. addrFrom.sin_port=htons(port);
  20. int addrlen = sizeof(SOCKADDR_IN);
  21. return recvfrom( s, buf, len, 0, (SOCKADDR *)&addrFrom, &addrlen);
  22. }

8 主函数设计

  1. int main()
  2. {
  3. int Result=0;
  4. char buf[1024]={0};
  5. char addr[16] = "8.8.4.4";// dns 服务器地址
  6. char *name = NULL; //要查询的域名
  7. if ( !initWSA() )//初始化
  8. {
  9. displayErrWSA("initWSA err!");
  10. return 1;
  11. }
  12. //创建套接字
  13. SOCKET sockTo ;
  14. if ( (sockTo = CreateSocket(SOCK_DGRAM)) == 0)
  15. {
  16. displayErrWSA("CreatSocket err!");
  17. return 1;
  18. }
  19. while (1)
  20. {
  21. char temp[1024]={0};
  22. cout<<"\n请输入要查询的域名:";
  23. cin>>temp;
  24. if (temp[0] == 'q' ||temp[0] == 'Q')
  25. {
  26. break;
  27. }
  28. name = temp;
  29. //设置dns 头部
  30. SetDNSHead(name,buf);
  31. //发送出去的请求数据长度
  32. int len = sizeof(DnsHead)+sizeof(DnsQuery)+strlen(name)+2;
  33. //发送DNS 请求
  34. if ( ( Result =MySendto(sockTo,buf,len,addr,53) ) <= 0)
  35. {
  36. displayErrWSA("sendto err!");
  37. continue;
  38. }
  39. //接收应答
  40. if ( (Result =MyRecvFrom(sockTo,buf,1024,addr,53) ) <= 0)
  41. {
  42. displayErrWSA("recvfrom err!");
  43. continue;
  44. }
  45. //简单的取得返回的 IP 地址( 收到的最后4字节 )
  46. DnsHead *DnsH = (DnsHead *)buf;
  47. if (DnsH->numA == 0)
  48. {
  49. printf("无法解析 %s 的IP 地址。\n",name);
  50. continue;
  51. }
  52. char *getIP =(char *)buf +Result - 4;
  53. printf("%s 的IP地址为: ",name);
  54. for (int Result= 0 ;Result<4 ;Result++)
  55. {
  56. printf("%u.",(UCHAR )getIP[Result]);
  57. }
  58. printf("\n");
  59. }
  60. return 0;
  61. }

9 运行实例

image_1b61qnj0e1jf1jg476a1c225ll9.png-26.7kB

10 所有程序

  1. #include <iostream>
  2. #include <Winsock2.h>
  3. #include <windows.h>
  4. #pragma comment(lib,"ws2_32.lib")
  5. using namespace std;
  6. typedef struct _DNSHEAD{ //dns 头部
  7. USHORT ID;
  8. USHORT tag; // dns 标志(参数)
  9. USHORT numQ; // 问题数
  10. USHORT numA; // 答案数
  11. USHORT numA1; // 权威答案数
  12. USHORT numA2; // 附加答案数
  13. }DnsHead;
  14. typedef struct _DNSQUERY //dns 查询结构
  15. {
  16. USHORT type;
  17. //查询类型,大约有20个不同的类型
  18. USHORT classes;
  19. //查询类,通常是A类既查询IP地
  20. }DnsQuery;
  21. // 初始化操作
  22. bool initWSA()
  23. {
  24. WSADATA wsaData;
  25. int Result = WSAStartup( MAKEWORD( 2, 2 ), &wsaData );
  26. if(Result!=0 )
  27. {
  28. return false;
  29. }
  30. if( LOBYTE( wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion)!= 2 )
  31. {
  32. if(WSACleanup()==SOCKET_ERROR)//注释4
  33. cout<<"WSACleanup出错\n"<<endl;
  34. return false;
  35. }
  36. return true;
  37. }
  38. bool SetDNSHead(char *name,char *buf)
  39. {
  40. memset(buf,0,sizeof(DnsHead));
  41. //设置头部
  42. DnsHead *DnsH = (DnsHead *)buf;
  43. DnsH->ID = (USHORT)1;
  44. DnsH->tag = htons(0x0100);
  45. DnsH->numQ = htons(1);
  46. DnsH->numA = 0;
  47. DnsQuery *DnsQ =(DnsQuery *) ( buf+ sizeof(DnsHead) );
  48. int NameLen = ChName(name,(char *)DnsQ);
  49. //设置查询信息
  50. DnsQ = (DnsQuery *)( (char *)DnsQ + NameLen );
  51. DnsQ->classes = htons(1);
  52. DnsQ->type = htons(1);
  53. return true;
  54. }
  55. //显示错误信息
  56. void displayErrWSA(char *str)
  57. {
  58. printf("\n%s,err = %d\n",str,WSAGetLastError());
  59. getchar();
  60. }
  61. //域名转化
  62. int ChName(char *fname,char *tname)
  63. {
  64. int j =0;
  65. int i =strlen(fname)-1;
  66. tname[i+2] = 0;
  67. int k = i+1;
  68. for (; i>=0;i--,k--)
  69. {
  70. if (fname[i] == '.')
  71. {
  72. tname[k] = j;
  73. j=0;
  74. }
  75. else
  76. {
  77. tname[k] = fname[i];
  78. j++;
  79. }
  80. }
  81. tname[k] = j;
  82. return strlen(tname)+1;
  83. }
  84. //创建套接字
  85. SOCKET CreateSocket(int type)
  86. {
  87. SOCKET sock=socket(AF_INET,type,0);
  88. if (sock == INVALID_SOCKET )
  89. {
  90. return 0;
  91. }
  92. return sock;
  93. }
  94. //UDP sendto
  95. int MySendto(SOCKET sockTo, const char FAR * buf,int len,char *addr,USHORT port)
  96. {
  97. if (addr[0]<'0'||addr[0]>'9') //addr 中不是IP 地址,域名解析
  98. {
  99. struct sockaddr_in addr_in;
  100. HOSTENT *host = NULL;
  101. host = gethostbyname(addr);//域名解析函数
  102. if ( host->h_addr_list[0]!=NULL )
  103. {
  104. memcpy ( &addr_in.sin_addr.s_addr,
  105. host->h_addr_list[0], host->h_length);
  106. addr = inet_ntoa(addr_in.sin_addr);
  107. }
  108. }
  109. //设置发送数据到的 套接字及地址结构
  110. SOCKADDR_IN addrTo;
  111. addrTo.sin_addr.S_un.S_addr=inet_addr(addr);
  112. addrTo.sin_family=AF_INET;
  113. addrTo.sin_port=htons(port);
  114. return sendto( sockTo, buf, len, 0,
  115. (sockaddr*)&addrTo, sizeof(sockaddr) );
  116. }
  117. // UDP recvfrom
  118. int MyRecvFrom(SOCKET s, char FAR * buf,int len,char *addr,USHORT port)
  119. {
  120. if (addr[0]<'0'||addr[0]>'9') //addr 中不是IP 地址,域名解析
  121. {
  122. struct sockaddr_in addr_in;
  123. HOSTENT *host = NULL;
  124. host = gethostbyname(addr);//域名解析函数
  125. if ( host->h_addr_list[0]!=NULL )
  126. {
  127. memcpy ( &addr_in.sin_addr.s_addr,
  128. host->h_addr_list[0], host->h_length);
  129. addr = inet_ntoa(addr_in.sin_addr);
  130. }
  131. }
  132. //设置发送数据到的 套接字及地址结构
  133. SOCKADDR_IN addrFrom;
  134. addrFrom.sin_addr.S_un.S_addr=inet_addr(addr);
  135. addrFrom.sin_family=AF_INET;
  136. addrFrom.sin_port=htons(port);
  137. int addrlen = sizeof(SOCKADDR_IN);
  138. return recvfrom( s, buf, len, 0, (SOCKADDR *)&addrFrom, &addrlen);
  139. }
  140. int main()
  141. {
  142. int Result=0;
  143. char buf[1024]={0};
  144. char addr[16] = "8.8.4.4";// dns 服务器地址
  145. char *name = NULL; //要查询的域名
  146. if ( !initWSA() )//初始化
  147. {
  148. displayErrWSA("initWSA err!");
  149. return 1;
  150. }
  151. //创建套接字
  152. SOCKET sockTo ;
  153. if ( (sockTo = CreateSocket(SOCK_DGRAM)) == 0)
  154. {
  155. displayErrWSA("CreatSocket err!");
  156. return 1;
  157. }
  158. while (1)
  159. {
  160. char temp[1024]={0};
  161. cout<<"\n请输入要查询的域名:";
  162. cin>>temp;
  163. if (temp[0] == 'q' ||temp[0] == 'Q')
  164. {
  165. break;
  166. }
  167. name = temp;
  168. //设置dns 头部
  169. SetDNSHead(name,buf);
  170. //发送出去的请求数据长度
  171. int len = sizeof(DnsHead)+sizeof(DnsQuery)+strlen(name)+2;
  172. //发送DNS 请求
  173. if ( ( Result =MySendto(sockTo,buf,len,addr,53) ) <= 0)
  174. {
  175. displayErrWSA("sendto err!");
  176. continue;
  177. }
  178. //接收应答
  179. if ( (Result =MyRecvFrom(sockTo,buf,1024,addr,53) ) <= 0)
  180. {
  181. displayErrWSA("recvfrom err!");
  182. continue;
  183. }
  184. //简单的取得返回的 IP 地址( 收到的最后4字节 )
  185. DnsHead *DnsH = (DnsHead *)buf;
  186. if (DnsH->numA == 0)
  187. {
  188. printf("无法解析 %s 的IP 地址。\n",name);
  189. continue;
  190. }
  191. char *getIP =(char *)buf +Result - 4;
  192. printf("%s 的IP地址为: ",name);
  193. for (int Result= 0 ;Result<4 ;Result++)
  194. {
  195. printf("%u.",(UCHAR )getIP[Result]);
  196. }
  197. printf("\n");
  198. }
  199. return 0;
  200. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注