【网络编程小结(二)】域名系统

域名系统一般指的是DNS协议,将我们填写的网址转换成点分十进制形式的ip地址(ipv4)。

在这里我们不讨论DNS服务器的细节,只需要知道它是udp协议之上的即可,下面我们来学习如何用函数完成域名转换的目的。

 

一、一组函数

struct hostent *gethostbyname (const char *__name)
name就是传入的字符串,如果网址是不合法的将返回null并且error设置为h_error,如果是合法的,将返回一个结构体:
struct hostent
{
  char *h_name;			/* Official name of host.  */
  char **h_aliases;		/* Alias list.  */
  int h_addrtype;		/* Host address type.  */
  int h_length;			/* Length of address.  */
  char **h_addr_list;		/* List of addresses from name server.  */
#if defined __USE_MISC || defined __USE_GNU
# define	h_addr	h_addr_list[0] /* Address, for backward compatibility.*/
#endif
};
h_name是地址的规范名字
h_addrtype是主机类型,一般是AF_INET
h_length是4,32bit的ip地址是4字节
h_aliases是它所有的别名,一组char*字符串,以NULL结尾
h_addr_list是所有可用地址的字符串表示形式,也是以NULL结尾

不多说,写个小程序试一下。

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;


int main(){
   hostent* hostent_ptr=gethostbyname("www.baidu.com");
    cout<h_name<h_length<h_addrtype==AF_INET)<h_aliases;
    while(*p1){
        cout<<"#"<<*p1<h_addr_list;*pp!= nullptr;++pp){
        cout<<"address:"<

运行结果为:

www.a.shifen.com
4
is AF_INET? true
aliases:
#www.baidu.com
address:61.135.169.125address:61.135.169.121

这样就得到了百度的ip和正式的名。

 

二、获取服务名

 

主要是以下两个函数:

struct servent *getservbyname (const char *__name, const char *__proto);
第一个参数是服务名,比如ftp,ntp,http之类的。
第二个参数是运输层协议名,可以填tcp/udp或nullptr。

下面看一个例子:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;


int main(){
   servent* sp=getservbyname("http", nullptr);
    cout<<"name:"<s_name<s_aliases;*p;++p){
        cout<<"#"<<*p<s_proto<s_port)<

输出为:

name:http
aliases:
#www
#www-http
protocol:tcp
port:80


可以看出http有俩别名,传入nullptr时候会选择tcp作为协议

值得注意的是返回的段口号是网络字节序,所以要用ntoh转换。

如果我们用的是下面的函数:

struct servent *getservbyport (int __port, const char *__proto)
注意,传入端口号的时候应该用hton转换

就是根据端口号查看对应的服务:

int main(){
    /*getserbyport*/
   servent* sp=getservbyport(htons(80), nullptr);

    cout<<"name:"<s_name<s_aliases;*p;++p){
        cout<<"#"<<*p<s_proto<s_port)<

上面的函数会返回一样的结果。

三、现代标准——getaddrinfo

此函数同时支持ipv4和ipv6,能够处理名字到地址,服务到端口两种转换,

int getaddrinfo (const char *__restrict __name,
			const char *__restrict __service,
			const struct addrinfo *__restrict __req,
			struct addrinfo **__restrict __pai)
第一个参数是主机名或地址字符串;
第二个参数是服务名或者十进制端口号;
第三个参数是hint保存期望得到的返回类型
第四个是用于保存的指针,结果将保存为一个链表;
如果成功则返回0,否则为其他值

下面依然以百度为例写一个例子:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;


int main(){
   addrinfo hints,*res;
    bzero(&hints,sizeof(hints));
    hints.ai_family=AF_INET;
    hints.ai_flags=AI_CANONNAME;
    getaddrinfo("www.baidu.com","80",&hints,&res);
    addrinfo* temp=res;
    while(temp){
        sockaddr_in* addr=(sockaddr_in*)temp->ai_addr;
        temp=temp->ai_next;
        char buf[30];
        cout<sin_port)<<";"<sin_addr,buf,sizeof(buf))<

运行结果为:

80;61.135.169.121
80;61.135.169.121
80;61.135.169.121
80;61.135.169.125
80;61.135.169.125
80;61.135.169.125

实际上只有两个ip剩下都是重复的,我们应当对这个链表进一步处理。

最后应当使用freeaddrinfo 来把整个链表释放掉。

 

你可能感兴趣的:(读书笔记)