IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 系统运维 -> Android网络框架学习——DNS解析与Socket通信原则 -> 正文阅读

[系统运维]Android网络框架学习——DNS解析与Socket通信原则

一、什么是DNS?

它所提供的服务是用来将主机名和域名转换为IP地址的工作。
我们知道域名和IP地址是一一对应的关系,但是多个域名可以对应同一个IP地址。

二、DNS查询过程

递归:DNS服务器可使用其自身的资源记录信息缓存来应答查询,
也可代表请求客户机来查询或联系其他DNS服务器,以完全解析该名称,并随后将应答返回至客户机。

迭代:客户机自己也可尝试l联系其他的DNS服务器来解析名称。
如果客户机这么做,它会使用基于服务器应答的独立和附加的查询。

1、在浏览器中输入域名,操作系统会先检查自己本地的hosts文件是否有这个网址映射关系。

2、如果hosts里没有映射关系,查找本地DNS解析器缓存。

3、如果还是没有,首先会找TCP/IP参数中设置的首选DNS服务器。

三、Socket介绍

Socket 的中文翻译过来就是“套接字”。套接字是什么,我们先来看看它的英文含义:插座。

Socket 就像一个电话插座,负责连通两端的电话,进行点对点通信,让电话可以进行通信,端口就像插座上的孔,端口不能同时被其他进程占用。而我们建立连接就像把插头插在这个插座上,创建一个 Socket 实例开始监听后,这个电话插座就时刻监听着消息的传入,谁拨通我这个“IP 地址和端口”,我就接通谁。

实际上,Socket 是在应用层和传输层之间的一个抽象层,它把 TCP/IP 层复杂的操作抽象为几个简单的接口,供应用层调用实现进程在网络中的通信。Socket 起源于 UNIX,在 UNIX 一切皆文件的思想下,进程间通信就被冠名为文件描述符(file descriptor),Socket 是一种“打开—读/写—关闭”模式的实现,服务器和客户端各自维护一个“文件”,在建立连接打开后,可以向文件写入内容供对方读取或者读取对方内容,通讯结束时关闭文件。

另外我们经常说到的Socket 所在位置如下图:

四、Socket 通信过程

Socket 保证了不同计算机之间的通信,也就是网络通信。对于网站,通信模型是服务器与客户端之间的通信。两端都建立了一个 Socket 对象,然后通过 Socket 对象对数据进行传输。通常服务器处于一个无限循环,等待客户端的连接。

一图胜千言,下面是面向连接的 TCP 时序图

五、使用socket进行DNS协议解析

在进行域名解析的时候,解析程序向域名服务器发起请求,域名服务器也就是在操作系统网络配置的时候写进去的那个DNS服务器地址,或者也有可能是由 ISP提供的自动获取的,原理都一样,域名服务器收到请求后进行处理,首先在本地缓存中查找对应的域名,找到后将IP地址直接返回,找不到就向其它的授权 服务器请求数据,又可以分为著名的递归查询和非递归查询。

  • 递归查询就是说自始至终都由一台域名服务器进行查询,它在自己这里找不到的时候会向其它的域名服务器请求并且获取数据,然后返回给请求方。
  • 非递归查询是指域名服务器收到请求后,如果自己有这个域名的信息就返回,如果没有就返回其它域名服务器的指针,请求方再根据这些域名服务器再发起查询。

DNS域名有时候会是一个主域名的别名,比如www.baidu.com,它就是 www.a.shifen.com这个域名的别名,在DNS请求发送过去之后,response里面会有一个类型为CNAME的Answers项,里面包 含了主域名的相关信息(其实也就是主域名的名称和TTL),在这个应答消息里面可能会出现多个域名消息,比如每个Answers的第一个字段就是一个域 名,当然为了减少数据包的容量,DNS系统对域名进行了压缩,同一个域名只会出现一次,其它的时候再出现的话就会用一个DNS指针表示。 比如域名:www.baidu.com在数据包中的表示是 03 77 77 77 05 62 61 69 64 75 03 63 6f 6d 00

粗体的是长度,将域名中的点去掉,用长度来分隔域名,以0结束。DNS允许的长度为0-63个字节,所以一个8位的长度最高两位都为0。

而如果此处域名重复出现,信令中便会用DNS指针代替长度,指针为两个字节,16位的最位都为1,剩下的14位表示在在整个数据包中的偏移量,当程 序读取到c00c的时候很容易判断它是一个指针而不是一个长度字段,于是根据c00c指向的领移量,即从数据包开始后的第12个字节,跳转过去读取出域名 信息。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>

#define DNS_SVR "211.68.71.4"

#define DNS_HOST  0x01
#define DNS_CNAME 0x05

int socketfd;
struct sockaddr_in dest;

static void 
send_dns_request(const char *dns_name);

static void
parse_dns_response();

/**
 * Generate DNS question chunk
 */
static void 
generate_question(const char *dns_name
        , unsigned char *buf , int *len);

/**
 * Check whether the current byte is 
 * a dns pointer or a length
 */
static int
is_pointer(int in);

/**
 * Parse data chunk into dns name
 * @param chunk The complete response chunk
 * @param ptr The pointer points to data
 * @param out This will be filled with dns name
 * @param len This will be filled with the length of dns name
 */
static void
parse_dns_name(unsigned char *chunk , unsigned char *ptr
        , char *out , int *len);

int main(int argc , char *argv[]){

    if(argc != 2){
        printf("Usage : %s <domain name>\n" , argv[0]);
        exit(-1);
    }
    socketfd = socket(AF_INET , SOCK_DGRAM , 0);
    if(socketfd < 0){
        perror("create socket failed");
        exit(-1);
    }
    bzero(&dest , sizeof(dest));
    dest.sin_family = AF_INET;
    dest.sin_port = htons(53);
    dest.sin_addr.s_addr = inet_addr(DNS_SVR);

    send_dns_request(argv[1]);

    parse_dns_response();

    return 0;
}

static void parse_dns_response(){

    unsigned char buf[1024];
    unsigned char *ptr = buf;
    struct sockaddr_in addr;
    char *src_ip;
    int n , i , flag , querys , answers;
    int type , ttl , datalen , len;
    char cname[128] , aname[128] , ip[20] , *cname_ptr;
    unsigned char netip[4];
    size_t addr_len = sizeof(struct sockaddr_in);

    n = recvfrom(socketfd , buf , sizeof(buf) , 0
        , (struct sockaddr*)&addr , &addr_len);
    ptr += 4; /* move ptr to Questions */
    querys = ntohs(*((unsigned short*)ptr));
    ptr += 2; /* move ptr to Answer RRs */
    answers = ntohs(*((unsigned short*)ptr));
    ptr += 6; /* move ptr to Querys */
    /* move over Querys */
    for(i= 0 ; i < querys ; i ++){
        for(;;){
            flag = (int)ptr[0];
            ptr += (flag + 1);
            if(flag == 0)
                break;
        }
        ptr += 4;
    }
    printf("-------------------------------\n");
    /* now ptr points to Answers */
    for(i = 0 ; i < answers ; i ++){
        bzero(aname , sizeof(aname));
        len = 0;
        parse_dns_name(buf , ptr , aname , &len);
        ptr += 2; /* move ptr to Type*/
        type = htons(*((unsigned short*)ptr));
        ptr += 4; /* move ptr to Time to live */
        ttl = htonl(*((unsigned int*)ptr));
        ptr += 4; /* move ptr to Data lenth */
        datalen = ntohs(*((unsigned short*)ptr));
        ptr += 2; /* move ptr to Data*/
        if(type == DNS_CNAME){
            bzero(cname , sizeof(cname));
            len = 0;
            parse_dns_name(buf , ptr , cname , &len);
            printf("%s is an alias for %s\n" , aname , cname);
            ptr += datalen;
        }
        if(type == DNS_HOST){
            bzero(ip , sizeof(ip));
            if(datalen == 4){
                memcpy(netip , ptr , datalen);
                inet_ntop(AF_INET , netip , ip , sizeof(struct sockaddr));
                printf("%s has address %s\n" , aname , ip);
                printf("\tTime to live: %d minutes , %d seconds\n"
                        , ttl / 60 , ttl % 60);
            }
            ptr += datalen;
        }

    }
    ptr += 2;
}

static void
parse_dns_name(unsigned char *chunk
        , unsigned char *ptr , char *out , int *len){
    int n , alen , flag;
    char *pos = out + (*len);

    for(;;){
        flag = (int)ptr[0];
        if(flag == 0)
            break;
        if(is_pointer(flag)){
            n = (int)ptr[1];
            ptr = chunk + n;
            parse_dns_name(chunk , ptr , out , len);
            break;
        }else{
            ptr ++;
            memcpy(pos , ptr , flag);   
            pos += flag;
            ptr += flag;
            *len += flag;
            if((int)ptr[0] != 0){
                memcpy(pos , "." , 1);
                pos += 1;
                (*len) += 1;
            }
        }
    }

}

static int is_pointer(int in){
    return ((in & 0xc0) == 0xc0);
}

static void send_dns_request(const char *dns_name){

    unsigned char request[256];
    unsigned char *ptr = request;
    unsigned char question[128];
    int question_len;

    generate_question(dns_name , question , &question_len);

    *((unsigned short*)ptr) = htons(0xff00);
    ptr += 2;
    *((unsigned short*)ptr) = htons(0x0100);
    ptr += 2;
    *((unsigned short*)ptr) = htons(1);
    ptr += 2;
    *((unsigned short*)ptr) = 0;
    ptr += 2;
    *((unsigned short*)ptr) = 0;
    ptr += 2;
    *((unsigned short*)ptr) = 0;
    ptr += 2;
    memcpy(ptr , question , question_len);
    ptr += question_len;

    sendto(socketfd , request , question_len + 12 , 0
       , (struct sockaddr*)&dest , sizeof(struct sockaddr));
}

static void
generate_question(const char *dns_name , unsigned char *buf , int *len){
    char *pos;
    unsigned char *ptr;
    int n;

    *len = 0;
    ptr = buf;  
    pos = (char*)dns_name; 
    for(;;){
        n = strlen(pos) - (strstr(pos , ".") ? strlen(strstr(pos , ".")) : 0);
        *ptr ++ = (unsigned char)n;
        memcpy(ptr , pos , n);
        *len += n + 1;
        ptr += n;
        irstr(pos , ".")){
            *ptr = (unsigned char)0;
            ptr ++;
            *len += 1;
            break;
        }
        pos += n + 1;
    }
    *((unsigned short*)ptr) = htons(1);
    *len += 2;
    ptr += 2;
    *((unsigned short*)ptr) = htons(1);
    *len += 2;
}

以上是对网络框架中的DNS解析与socket通信原则的浅析,这些都属于OKhttp网络框架中的部分内容;如果想深入学习Android的 网络框架;我这里推荐资料《OKhttp手册》文档获取↓↓,让你更方便的深入学习网络框架。

简述OKhttp优点

OkHttp是一个优秀的网络请求框架,它有以下默认特性:

  • 支持HTTP/2,允许所有同一个主机地址的请求共享同一个socket连接
  • 连接池减少请求延时
  • 透明的GZIP压缩减少响应数据的大小
  • 缓存响应内容,避免一些完全重复的请求

  系统运维 最新文章
配置小型公司网络WLAN基本业务(AC通过三层
如何在交付运维过程中建立风险底线意识,提
快速传输大文件,怎么通过网络传大文件给对
从游戏服务端角度分析移动同步(状态同步)
MySQL使用MyCat实现分库分表
如何用DWDM射频光纤技术实现200公里外的站点
国内顺畅下载k8s.gcr.io的镜像
自动化测试appium
ctfshow ssrf
Linux操作系统学习之实用指令(Centos7/8均
上一篇文章      下一篇文章      查看所有文章
加:2022-09-24 21:30:38  更:2022-09-24 21:33:13 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/28 18:44:06-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码
数据统计