https网络编程——HTTP协议的简介HTTP报文结构和代理HTTP解析方法(哈希加速协议状态机)

Posted 行稳方能走远

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了https网络编程——HTTP协议的简介HTTP报文结构和代理HTTP解析方法(哈希加速协议状态机)相关的知识,希望对你有一定的参考价值。

参考:HTTP协议的简介及其工作原理等
地址:https://qingmu.blog.csdn.net/article/details/108046553?spm=1001.2014.3001.5502

目录

HTTP协议的简介及其工作原理

1、HTTP简介

1.1、什么是超文本(HyperText)?

包含有超链接(Link)和各种多媒体元素标记(Markup)的文本。这些超文本文件彼此链接,形成网状(Web),因此又被称为网页(Web Page)。这些链接使用URL表示。最常用的超文本格式是超文本标记语言html

1.2、什么是URL?

URL即统-资源定位符(Uniform Resource Locator),用来唯一地标识万维网中的某一 个文档。 URL由协议、主机和端口(默认为80)以及文件名三部分构成。 如:

1.3、什么是超文本传输协议HTTP?

是一种按照URL指示,将超文本文档从-台主机(Web服务器)传输到另一台主机(浏览器)的应用层协议, 以实现超链接的功能。

2、HTTP工作原理

2.1、请求/相应交互模式

在用户点击URL为http://www.sxtyu.com/index.html的链接后,浏览器和Web服务器执行以下动作:

①、浏览器分析超链接中的UR了

②、浏览器向DNS请求解析www.sxtyu.com的IP地址

③、DNS将解析出的IP地址202.2.16.21返回浏览器

④、浏览器与服务器建立TCP连接(80端)

⑤、浏览器请求文档: GET /index.htm

⑥、服务器给出响应,将文档index.html发送给浏览器

⑦、释放TCP连接

⑧、浏览器显示index.html中的内容

2.2、HTTP的连接方式(非持久性/持久性)和无状态性

2.2.1、非持久性连接

即浏览器每请求一个Web文档, 就创建一个新的连接, 当文档传输完毕后,连接就立刻被释放。

HTTP1.0、HTTP0.9采用此连接方式。

对于请求的Web页中包含多个其他文档对象(如图像、音、视频等)的链接的情况,于请求每个链接对应的文档都要创建新连接,效率低下。

2.2.2、持久性连接

即在一个连接中, 可以进行多次文档的请求和响应。服务器在发送完响应后,钚立即释放连接,浏览器可以使用该连接继续请求其他文档。连接保持的时间可以由双方进行协商。

2.2.3、无状态性

是指同一个客户端(浏览器第二 _次访问同一 个Web服务器上的页面时,服务器无法知道这个客户曾经访问过。HTTP的无状态性简化了服务器的设计,使其更容易支持大量并发的HTTP请求。

HTTP的报文结构和HTTP代理

1、HTTP报文结构

1.1、请求报文

即从客户端(浏览器)向Web服务器发送请求报文。报文的所有字段都是ASCII码。


实例:

GET /js/an.js HTTP/1.1				#请求行
Accept: */*							#可接受的媒体类型
Accept-Encoding: gzip, deflate		#可接受的编码
Accept-L anguage: zh-cn				#接受的语言
Connection: Keep-Alive				#持久连接
Host: cache.soso.com				#Host
Referer: http://help.soso.com/	    #引用 页面
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727; InfoPath.2) #用户代理

1.2、响应报文

即从Web服务器到客户机(浏览器)的应答。报文的所有字段都是ASCII码。


实例:

HTTP/1.1200 OK                                               #状态行.
Accept-Ranges: bytes										 #表示服务器端可以接受range请求
Cache-Control: max -age=86400					 			 #缓存控制时间
Content-Encoding: gzip										 #内容编码格式
Content-L ength: 1088									   	 #内容长度
Content-Type: text/javascript							  	 #内容类型
Date: Thu, 18 Jun 2009 15:47:14 GMT            				 #时间
ETag:“1902284250“										 	 #实体标签
Expires: Fri, 19 Jun 2009 15:47:14 GMT         				 #过期时间
L ast-Modified: Fri, 10 Oct 2008 04:13:19 GMT    			 #最后修改日期
Server: WS CDN Server										 #Server名称
Vary: Accept-Encoding										 #告知该响应缓存时取决的方式

1.3、请求报文中的一些方法

方法(Method)是所请求对象所进行的操作,也就是一些命令。请求报文中的操作有:

方法(操作)含义
GET请求读取一个页面
POST附加一个命名资源(如Web页面)
HEAD请求读取一个Web页面的首部
PUT请求存储一个Web页面
DELETE删除Web页面
TRACE用于测试,要求服务器送回收到的请求
CONNECT用于代理服务器
OPTION查询特定选项

1.4、响应报文中的状态码

状态码:Status-code是响应报文状态行中包含的以三位数字,指明特定的要求是否被满足,如果没有满足,原因是什么。状态码分为一下的五类:

状态码含义例子
1xx通知信息100=服务器正在处理客户请求
2xx成功200=请求成功
3xx重定向301=页面改变了位置
4xx客户端错误403=禁止的页面;401=页面未找到
5xx服务器错误500=服务器内部错误;503=以后再试

常见的状态码:
➢200 OK
➢206 Partial Content
➢301 Moved Permanently
➢302 Found
➢304 Not Modified
➢400 Bad Request
➢403 Forbidden
➢404 Not Found
➢502 Bad Gateway
➢503 Service Unavailable
➢504 Gateway Timeout

1.5、首部字段或消息头

头(header)类型说明
User- Agent请求关于浏览器和它平台的信息,如Moilla5.0
Accept请求客户能处理的页面的类型,如text/html
Accept-Charset请求客户可以接受的字符集,如Unicode-1-1
Accept-Encoding请求客户能处理的页面编码方法,如gzip
Accept-Language请求客户能处理的自然语言,如en(英语),zh- cn(简体中文)
Host请求服务器的DNS名称。从URL中提取出来,必需。
Authorization请求客户的信息凭据列表
Cookie请求将以前设置的Cookie送回服务器器,可用来作为会话信息
Date双向消息被发送时的日期和时间
Server响应关于服务器的信息,如Microsoft IS/6.0
Content-Encoding响应内容是如何被编码的(如gzip)
Content-Language响应页面所使用的自然语言
Content-Length响应以字节计算的页面长度
Content-Type响应页面的MIIME类型
Last-Modified响应页面最后被修改的时间和日期,在页面缓存机制中意义重大
Location响应指示客户将请求发送给别处,即重定向到另个URL
Set-Cookie响应服务器希望客户保存一个Cookie

2、HTTP代理

2.1、什么是HTTP用户代理?

HTTP代理又称Web缓存或代理服务器(Proxy Server),是一种网络实体, 能代表浏览器发出HTTP请求,并将最近的一些请求和响应暂存在本地磁盘中,当请求的Web页面先前暂存过,则直接将暂存的页面发给客户端(浏览器),无须再次访问Internet。

2.2、使用HTTP代理的Web访问过程

HTTP高效解析的方法之哈希加速

哈希加速

在我们获取到HTTP的外部请求的时候,第一步去识别它所对应的请求类型,然后再去获取它后面所对的URL,最后在对URL做进一步的解析。

在我们获取到了URL之后,我们需要在数据库中或者文件系统中获取对应的文件(也就是字符串匹配),但是解析过程中字符串的比较很慢,达不到我们的需求,那么我们就需要加快URL的解析,那么如何操作呢?我们可以使用哈希加速

哈希加速:把服务器自己所对应的url全部通过哈希算法,把每一个路径都算成一个数,然后把输入的URL也进行哈希算法,算成一个数,和服务器的进行比较,如果在服务器的哈希范围内并且有匹配的值,就打开对应的路径所对应的文件,如果哈希值匹配不上,就认为此URL是错误的URL。

这样通过哈希来比较,比字符串的比较快的多。

HASH解析URL链接实现

/*管理URL的对象*/
typedef struct 
    char    url[MAX_URL_LEN];	//URL
    size_t  len;				//长度
    int     all;				//个数
    UT_hash_handle hh;  		//HASH表
 url_t;


/*HASH表的一个节点*/
typedef struct UT_hash_handle 
   struct UT_hash_table *tbl;
   void *prev;                       /* prev element in app order      */
   void *next;                       /* next element in app order      */
   struct UT_hash_handle *hh_prev;   /* previous hh in bucket order    */
   struct UT_hash_handle *hh_next;   /* next hh in bucket order        */
   void *key;                        /* ptr to enclosing struct's key  */
   unsigned keylen;                  /* enclosing struct's key len     */
   unsigned hashv;                   /* result of hash-fcn(key)        */
 UT_hash_handle;


/*HASH表*/
typedef struct UT_hash_table

   UT_hash_bucket *buckets;
   unsigned num_buckets, log2_num_buckets;
   unsigned num_items;
   struct UT_hash_handle *tail; /* tail hh in app order, for fast append    */
   ptrdiff_t hho; /* hash handle offset (byte pos of hash handle in element */

   /* in an ideal situation (all buckets used equally), no bucket would have
    * more than ceil(#items/#buckets) items. that's the ideal chain length. */
   unsigned ideal_chain_maxlen;

   /* nonideal_items is the number of items in the hash whose chain position
    * exceeds the ideal chain maxlen. these items pay the penalty for an uneven
    * hash distribution; reaching them in a chain traversal takes >ideal steps */
   unsigned nonideal_items;

   /* ineffective expands occur when a bucket doubling was performed, but
    * afterward, more than half the items in the hash had nonideal chain
    * positions. If this happens on two consecutive expansions we inhibit any
    * further expansion, as it's not helping; this happens when the hash
    * function isn't a good fit for the key domain. When expansion is inhibited
    * the hash will still work, albeit no longer in constant time. */
   unsigned ineff_expands, noexpand;

   uint32_t signature; /* used only to find hash tables in external analysis */
#ifdef HASH_BLOOM
   uint32_t bloom_sig; /* used only to test bloom exists in external analysis */
   uint8_t *bloom_bv;
   uint8_t bloom_nbits;
#endif



/*HASH算法*/
HASH_FIND_STR(urls, url, u);

#define HASH_FIND_STR(head,findstr,out)                                          \\
    HASH_FIND(hh,head,findstr,(unsigned)uthash_strlen(findstr),out)


#define HASH_FIND(hh,head,keyptr,keylen,out)                                     \\
do                                                                              \\
  unsigned _hf_hashv;                                                            \\
  HASH_VALUE(keyptr, keylen, _hf_hashv);                                         \\
  HASH_FIND_BYHASHVALUE(hh, head, keyptr, keylen, _hf_hashv, out);               \\
 while (0


#define HASH_VALUE(keyptr,keylen,hashv)                                          \\
do                                                                              \\
  HASH_FCN(keyptr, keylen, hashv);                                               \\
 while (0)


#ifdef HASH_FUNCTION
#define HASH_FCN HASH_FUNCTION
#else
#define HASH_FCN HASH_JEN
#endif

#define HASH_JEN(key,keylen,hashv)                                               \\
do                                                                              \\
  unsigned _hj_i,_hj_j,_hj_k;                                                    \\
  unsigned const char *_hj_key=(unsigned const char*)(key);                      \\
  hashv = 0xfeedbeefu;                                                           \\
  _hj_i = _hj_j = 0x9e3779b9u;                                                   \\
  _hj_k = (unsigned)(keylen);                                                    \\
  while (_hj_k >= 12U)                                                          \\
    _hj_i +=    (_hj_key[0] + ( (unsigned)_hj_key[1] << 8 )                      \\
        + ( (unsigned)_hj_key[2] << 16 )                                         \\
        + ( (unsigned)_hj_key[3] << 24 ) );                                      \\
    _hj_j +=    (_hj_key[4] + ( (unsigned)_hj_key[5] << 8 )                      \\
        + ( (unsigned)_hj_key[6] << 16 )                                         \\
        + ( (unsigned)_hj_key[7] << 24 ) );                                      \\
    hashv += (_hj_key[8] + ( (unsigned)_hj_key[9] << 8 )                         \\
        + ( (unsigned)_hj_key[10] << 16 )                                        \\
        + ( (unsigned)_hj_key[11] << 24 ) );                                     \\
                                                                                 \\
     HASH_JEN_MIX(_hj_i, _hj_j, hashv);                                          \\
                                                                                 \\
     _hj_key += 12;                                                              \\
     _hj_k -= 12U;                                                               \\
                                                                                \\
  hashv += (unsigned)(keylen);                                                   \\
  switch ( _hj_k )                                                              \\
    case 11: hashv += ( (unsigned)_hj_key[10] << 24 ); /* FALLTHROUGH */         \\
    case 10: hashv += ( (unsigned)_hj_key[9] << 16 );  /* FALLTHROUGH */         \\
    case 9:  hashv += ( (unsigned)_hj_key[8] << 8 );   /* FALLTHROUGH */         \\
    case 8:  _hj_j += ( (unsigned)_hj_key[7] << 24 );  /* FALLTHROUGH */         \\
    case 7:  _hj_j += ( (unsigned)_hj_key[6] << 16 );  /* FALLTHROUGH */         \\
    case 6:  _hj_j += ( (unsigned)_hj_key[5] << 8 );   /* FALLTHROUGH */         \\
    case 5:  _hj_j += _hj_key[4];                      /* FALLTHROUGH */         \\
    case 4:  _hj_i += ( (unsigned)_hj_key[3] << 24 );  /* FALLTHROUGH */         \\
    case 3:  _hj_i += ( (unsigned)_hj_key[2] << 16 );  /* FALLTHROUGH */         \\
    case 2:  _hj_i += ( (unsigned)_hj_key[1] << 8 );   /* FALLTHROUGH */         \\
    case 1:  _hj_i += _hj_key[0];                                                \\
                                                                                \\
  HASH_JEN_MIX(_hj_i, _hj_j, hashv);                                             \\
 while (0)

#define HASH_FIND_BYHASHVALUE(hh,head,keyptr,keylen,hashval,out)                 \\
do                                                                              \\
  (out) = NULL;                                                                  \\
  if (head)                                                                     \\
    unsigned _hf_bkt;                                                            \\
    HASH_TO_BKT(hashval, (head)->hh.tbl->num_buckets, _hf_bkt);                  \\
    if (HASH_BLOOM_TEST((head)->hh.tbl, hashval) != 0)                          \\
      HASH_FIND_IN_BKT((head)->hh.tbl, hh, (head)->hh.tbl->buckets[ _hf_bkt ], keyptr, keylen, hashval, out); \\
                                                                                \\
                                                                                \\
 while (0)


 HASH_ADD_STR(urls, url, u); 

那么我们如何维护一个HASH表呢?

添加一个HASH


int add_url(const char *url)

    url_t  *u;

    if (!url || strlen(url) >= MAX_URL_LEN) return 0;

    pthread_rwlock_wrlock(&rwlock);

    HASH_FIND_STR(urls, url, u);
    if (u) 
        pthread_rwlock_unlock(&rwlock);
        return 0;
    

    u = (url_t *)calloc(1, sizeof(url_t));

    strncpy(u->url, url, MAX_URL_LEN - 1);
    u->len = strlen(u->url);

    if (u->url[u->len - 1] == URL_SPLIT) 
        //u->url[u->len - 1] = 0;
        u->all = 1;
    

    HASH_ADD_STR(urls, url, u);

    pthread_rwlock_unlock(&rwlock);

    return 1;

判断URL在不在HASH表中

int has_url(const char *url)

    char    tmp[MAX_URL_LEN];
    char   *start, *end, *pos;
    size_t  ul;
    url_t  *u;

    if (!url) 
        return 0;
    
    
    ul = strlen(url); 
    if (ul >= MAX_URL_LEN) 
        return 0;
    

    memset(tmp, 0x00, sizeof(tmp));

    pos   = tmp;
    start = (char *)url;

    pthread_rwlock_rdlock(&rwlock);

    HASH_FIND_STR(urls, url, u);
    if (u) 
        pthread_rwlock_unlock(&rwlock);
        return 1;
    

    end = strchr(start, URL_SPLIT);
    for (; end; end = strchr(start, URL_SPLIT)) 
        memcpy(pos, start, end - start + 1);

        HASH_FIND_STR(urls, tmp, u);
        if (u && u->all) 
            pthread_rwlock_unlock(&rwlock);
            return 1;
        

        pos += (end - start + 1);
        start = end + 1;
    

    pthread_rwlock_unlock(&rwlock);

    return 0;

删除一个URL

int del_url(const char *url)

    url_t  *u;

    if (!url || strlen(url) >= MAX_URL_LEN) 
        return 0;
    

    pthread_rwlock_wrlock(&rwlock);
    
    HASH_FIND_STR(urls, url, u);
    if (u) 
        HASH_DEL(urls, u);
        pthread_rwlock_unlock网络知识_详解HTTP和HTTPS

网络知识_详解HTTP和HTTPS

网络安全HTTPS为什么比较安全

Libcurl库——HTTP协议实现

网络协议--HTTP

Java基础学习 网络编程简介