本库中使用的数据结构还是非常清晰的,结构体以及枚举数据也不是太多,如图整个数据结构族谱非常的清晰
ghttp代码中维护一个全局的结构体struct _ghttp_request,这里面包含了所有的操作数据,包括url、代理信息、请求、应答以及网络等信息
struct _ghttp_request { http_uri *uri;//请求URL http_uri *proxy;//请求代理的URL http_req *req;//request内容 http_resp *resp;//应答结构体 http_trans_conn *conn; //底层网络数据 const char *errstr;//错误字符串 int connected;//socket句柄 ghttp_proc proc;//处理项 char *username;//用户名 char *password;//密码 char *authtoken;//authtoken认证字段 char *proxy_username;//代理用户名 char *proxy_password;//代理密码 char *proxy_authtoken;//代理authtoken认证字段 };将传入的url字符串解析之后赋值到该结构体进行处理
/* URL结构体 */ typedef struct http_uri_tag { char *full; /* 传入的URL,比如:http://1.1.1.1:80/api/login */ char *proto;/*从URL中解析出来即:http */ char *host;/* 从URL中解析出来的IP或者域名,如full中的1.1.1.1 */ unsigned short port;/* 从URL中解析出来的端口,如full中的80 */ char *resource;/* 从URL中解析出来的请求资源,如full中的/api/login */ } http_uri;这里面封装了请求的所有信息,包括请求方法、协议版本、服务器的IP地址、端口、接口等数据,此外还有协议头和请求报文体
typedef struct http_req_tag { http_req_type type;//请求方法 float http_ver;//协议版本 char *host;//服务器IP char *full_uri;//请求的URL char *resource;//请求接口 char *body;//请求报文体 int body_len;//请求body长度 http_hdr_list *headers;//请求协议头部 http_req_state state;//请求状态 } http_req;2.2.1 http_req_type 这是个数据枚举类型,枚举了所支持的方法,根据HTTP标准,HTTP请求可以使用多种请求方法。 HTTP1.0定义了三种请求方法: GET, POST 和 HEAD方法。 HTTP1.1新增了五种请求方法:OPTIONS, PUT, DELETE, TRACE 和 CONNECT 方法。 此外: - Mkcol:创建集合 - PropFind和PropPatch:针对资源和集合检索和设置属性; - Copy和Move:管理命名空间上下文中的集合和资源; - Lock和Unlock:改写保护
typedef enum http_req_type { http_req_type_get = 0,//请求指定的页面信息,并返回实体主体 http_req_type_options,//允许客户端查看服务器的性能 http_req_type_head,//类似于get请求,只不过返回的响应中没有具体的内容,用于获取报头 http_req_type_post,//向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。POST请求可能会导致新的资源的建立和/或已有资源的修改 http_req_type_put,//从客户端向服务器传送的数据取代指定的文档的内容 http_req_type_delete,//请求服务器删除指定的页面 http_req_type_trace,//回显服务器收到的请求,主要用于测试或诊断 http_req_type_connect,//HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器 http_req_type_propfind, http_req_type_proppatch, http_req_type_mkcol, http_req_type_copy, http_req_type_move, http_req_type_lock, http_req_type_unlock } http_req_type;文中注释了常用的方法,后面的不常用的,笔者也没有使用过所有没有增加详细说明。
http_hdr_list这里记录的是协议头,根据用户的输入先保存在这个list里面,这个更类似于一个map类型,里面是key-val类似的键值对。
#define HTTP_HDRS_MAX 256 //协议头部结构体,最大256 typedef struct http_hdr_list_tag { char *header[HTTP_HDRS_MAX]; char *value[HTTP_HDRS_MAX]; } http_hdr_list;http_req_state是请求操作的一个状态,记录了当前正在操作的项
typedef enum http_req_state_tag { http_req_state_start = 0, http_req_state_sending_request,//发送请求 http_req_state_sending_headers,//发送请求头部 http_req_state_sending_body//发送请求body } http_req_state;
应答报文,里面包含了应答的协议版本、状态码和状态描述,此外还有返回的报文头以及报文体和头部状态body状态等信息,其中headers字段不再叙述,在http_req结构体中已经有过说明
typedef struct http_resp_tag { float http_ver;//协议版本 int status_code;//请求返回的状态码 char *reason_phrase;//请求返回的状态 比如OK http_hdr_list *headers;//返回的协议头 char *body;//返回的报文body部分 int body_len;//返回的报文body部分长度 int content_length;//content数据长度 int flushed_length;//刷新出来的数据长度 http_resp_header_state header_state;//头部状态 http_resp_body_state body_state;//body状态 } http_resp;
这是个枚举类型,里面是应答报文操作的状态,目前只有read状态
typedef enum http_resp_header_state_tag { http_resp_header_start = 0, http_resp_reading_header } http_resp_header_state;
应答报文体状态
typedef enum http_resp_body_state_tag { http_resp_body_start = 0, http_resp_body_read_content_length, http_resp_body_read_chunked, http_resp_body_read_standard } http_resp_body_state;
这里记录的网络操作信息,从最底层的主机信息、网络信息、socket以及到操作中的缓冲区信息都有描述
typedef struct http_trans_conn_tag { struct hostent *hostinfo;//主机信息 struct sockaddr_in saddr;//网络通信结构体 char *host;//ip地址 char *proxy_host;//代理ip地址 int sock;//socked句柄 short port;//端口 short proxy_port;//代理端口 http_trans_err_type error_type;//错误类型 int error;//错误码 int sync; /* 是否同步*/ char *io_buf; /* 缓冲区*/ int io_buf_len; /* 缓冲区大小 */ int io_buf_alloc; /* 已使用缓冲区大小 */ int io_buf_io_done; /* 缓冲区滑动窗口已使用大小 */ int io_buf_io_left; /* 预留数据缓冲区大小 */ int io_buf_chunksize; /* 读入或者数据块大小 */ int last_read; /* 最后一次读取的大小 */ int chunk_len; /* 块长度 */ char *errstr; /* 错误描述 */ } http_trans_conn;
主机信息结构体,记录的是主机相关的内容
struct hostent { char *h_name; //正式主机名 char **h_aliases; //主机别名 int h_addrtype; //主机IP地址类型:IPV4-AF_INET int h_length; //主机IP地址字节长度,对于IPv4是四字节,即32位 char **h_addr_list; //主机的IP地址列表 }; #define h_addr h_addr_list[0] //保存的是IP地址
网络通信结构体,是为了socket服务的
struct sockaddr_in { sa_family_t sin_family;//Address family一般来说AF_INET(地址族)PF_INET(协议族) uint16_t sin_port;//16位TCP/UDP端口号 struct in_addr sin_addr;//32位IP地址 unsigned char sin_zero[8];//预留 }; struct in_addr { In_addr_t s_addr;//32位IPv4地址 };这是一个枚举数据类型,描述的是网络中的错误类型
typedef enum http_trans_err_type_tag { http_trans_err_type_host = 0, http_trans_err_type_errno } http_trans_err_type;至此ghttp中的数据结构基本就介绍完了,这个库里面的数据结构设计的还是比较清晰的,但是个人使用起来的感觉就是有些字段冗余比较大,有些繁琐,不确定代码开发人员的真实意图是什么,还是这样做的目的是为了模块化更清晰一些呢,尚且还没有悟透这层含义。