C/C++实现HTTP协议解析的示例代码
作者:程序猿编码
超文本传输协议 (HTTP) 是分布式、协作、超媒体信息系统的应用层协议。 这是自 1990 年以来万维网数据通信的基础。HTTP 是一种通用且无状态的协议,它可以用于其他目的,也可以使用其请求方法、错误代码和标头的扩展。
基本上,HTTP 是一种基于 TCP/IP 的通信协议,用于通过 Web 传递 HTML 文件、图像文件、查询结果等数据。 它为计算机之间的通信提供了一种标准化的方式。 HTTP 规范指定了客户端请求的数据如何发送到服务器,以及服务器如何响应这些请求。
HTTP客户端和服务器通信
客户端和服务器通过交换单独的消息(而不是数据流)进行通信。 客户端(通常是 Web 浏览器)发送的消息称为请求,服务器发送的作为应答的消息称为响应。
HTTP通过 TCP 或 TLS 加密的 TCP 连接发送的应用层协议,尽管理论上可以使用任何可靠的传输协议。 由于其可扩展性,它不仅用于获取超文本文档,还用于获取图像和视频或将内容发布到服务器,例如 HTML 表单结果。 HTTP 还可用于获取部分文档以按需更新网页。
HTTP和连接
连接是在传输层控制的,因此基本上超出了 HTTP 的范围。 HTTP 不要求底层传输协议是基于连接的;
它只要求它是可靠的,或者不丢失消息。在 Internet 上最常见的两种传输协议中,TCP 是可靠的,而 UDP 则不是。因此,HTTP 依赖于基于连接的 TCP 标准。
在客户端和服务器可以交换 HTTP 请求/响应对之前,它们必须建立 TCP 连接,这个过程需要多次往返。
HTTP/1.0 的默认行为是为每个 HTTP 请求/响应对打开一个单独的 TCP 连接。当多个请求连续发送时,这比共享单个 TCP 连接效率低。
HTTP 消息
HTTP/1.1 及更早版本中定义的 HTTP 消息是人类可读的。 在 HTTP/2 中,这些消息被嵌入到二进制结构中,即一个帧,允许像压缩头和多路复用这样的优化。 即使在这个版本的 HTTP 中只发送原始 HTTP 消息的一部分,每个消息的语义都不会改变,客户端会(实际上)重构原始 HTTP/1.1 请求。 因此,理解 HTTP/1.1 格式的对 HTTP/2 消息很有用。
HTTP 消息有两种类型,请求和响应,每种都有自己的格式。
HTTP请求消息
请求由以下元素组成:
HTTP 方法,通常是 GET、POST 之类的动词或 OPTIONS 或 HEAD 之类的名词,用于定义客户端想要执行的操作。 通常,客户端想要获取资源(使用 GET)或发布 HTML 表单的值(使用 POST),但在其他情况下可能需要更多操作。
要获取的资源的路径; 从上下文中明显的元素中剥离的资源的 URL。
HTTP响应消息
响应由以下元素组成:
他们遵循的 HTTP 协议的版本。
状态码,指示请求是否成功以及原因。
状态消息,状态代码的非权威简短描述。
HTTP 标头,例如用于请求的标头。
可选地,包含获取的资源的主体。
HTTP 状态
一些常见的 HTTP 状态代码包括:
200 - 请求成功(网页存在)
301 - 永久移动(通常转发到新 URL)
401 - 未经授权的请求(需要授权)
403 - 禁止(不允许访问页面或目录)
500 - 内部服务器错误(通常由不正确的服务器配置引起)
HTTP协议解析及C/C++代码实现
... void got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet) { ... /* print source and destination IP addresses */ printf(" From: %s\n", inet_ntoa(ip->ip_src)); printf(" To: %s\n", inet_ntoa(ip->ip_dst)); /* determine protocol */ switch(ip->ip_p) { case IPPROTO_TCP: printf(" Protocol: TCP\n"); break; case IPPROTO_UDP: printf(" Protocol: UDP\n"); break; case IPPROTO_ICMP: printf(" Protocol: ICMP\n"); return; case IPPROTO_IP: printf(" Protocol: IP\n"); return; default: printf(" Protocol: unknown\n"); return; } /* * OK, this packet is TCP. */ /* define/compute tcp header offset */ if(ip->ip_p == IPPROTO_TCP) { ... printf(" Src port: %d\n", ntohs(tcp->th_sport)); printf(" Dst port: %d\n", ntohs(tcp->th_dport)); int sport = ntohs(tcp->th_sport); int dport = ntohs(tcp->th_dport); ... if (size_payload > 0) { printf(" Payload (%d bytes):\n", size_payload); //print_payload(payload, size_payload); if ((sport == 80) || (dport == 80)) { printf(" HTTP prase:\n"); prase_http(payload, size_payload); } else if(sport == 443 || dport == 443) { printf(" SSL/TLS prase:\n"); prase_ssl_tls(payload, size_payload); } } } ... } int main(int argc, char *argv[]) { char errbuf[100]; pcap_t *desc = 0; char *filename = argv[1]; if (argc != 2) { printf("usage: ./dissect_http [pcap file]\n"); return -1; } printf("ProcessFile: process file: %s\n", filename); if ((desc = pcap_open_offline(filename, errbuf)) == NULL) { printf("pcap_open_offline: %s error!\n", filename); return -1; } pcap_loop(desc, -1, got_packet, NULL); pcap_close(desc); return 0; }
运行结果:
总结
HTTP 是一种易于使用的可扩展协议。 客户端-服务器结构与添加标头的能力相结合,允许 HTTP 与 Web 的扩展功能一起发展。
尽管 HTTP/2 通过在帧中嵌入 HTTP 消息来提高性能增加了一些复杂性,但消息的基本结构自 HTTP/1.0 以来一直保持不变。 会话流保持简单,允许使用简单的 HTTP 消息监视器对其进行调查和调试。
以“http://”开头的 URL 通过标准超文本传输协议访问,默认使用端口 80。以“https://”开头的 URL 通过安全的 HTTPS 连接访问,通常使用端口 443。
以上就是C/C++代码实现HTTP协议解析的示例代码的详细内容,更多关于C++解析HTTP协议的资料请关注脚本之家其它相关文章!