C++ 实现HTTP的客户端、服务端demo和HTTP三方库介绍

        本文使用C++模拟实现http的客户端请求和http的服务端响应功能,并介绍几种封装HTTP协议的三方库。

1、实现简单HTTP的服务端功能

        本程序使用C++ tcp服务端代码模拟HTTP的服务端,服务端返回给客户端的消息内容按照HTTP协议的消息响应格式进行了组装。

demo如下:

#include <iostream>
#include <cstring>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>int main() {int server_fd, new_socket;struct sockaddr_in address;int addrlen = sizeof(address);char buffer[1024] = {0};const char* hello = "HTTP/1.1 200 OK\nContent-Type: text/plain\n\nHello, World!";// 创建套接字if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {perror("socket failed");exit(EXIT_FAILURE);}address.sin_family = AF_INET;address.sin_addr.s_addr = INADDR_ANY;address.sin_port = htons(37777);// 绑定套接字到端口if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {perror("bind failed");exit(EXIT_FAILURE);}// 监听连接if (listen(server_fd, 3) < 0) {perror("listen");exit(EXIT_FAILURE);}printf("Listening on port 37777\n");while (true) {if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) {perror("accept");exit(EXIT_FAILURE);}// 读取客户端请求int length = read(new_socket, buffer, 1024);printf("******** HTTP Server recv request length: %d,as follow: ********\n%s\n",length,buffer);// 发送响应send(new_socket, hello, strlen(hello), 0);printf("******** HTTP Server replied to the request ********\n");close(new_socket);}return 0;
}

2、实现简单HTTP的客户端功能

         本程序使用C++ tcp客户端代码模拟HTTP的客户端,客户端发给服务端的请求内容按照HTTP协议的请求格式进行了组装。

demo如下:

#include <iostream>
#include <cstring>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <arpa/inet.h>int main() {int sock = 0, length;struct sockaddr_in serv_addr;char buffer[1024] = {0};const char* get_request = "GET / HTTP/1.1\r\nHost: localhost\r\n\r\n";if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {perror("Socket creation error");exit(EXIT_FAILURE);}serv_addr.sin_family = AF_INET;serv_addr.sin_port = htons(37777);//serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); //bind ip method 1// 将IPv4地址从点分十进制转换为二进制形式 bind ip method 2if (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0) {perror("Invalid address/Address not supported");exit(EXIT_FAILURE);}if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {perror("Connection failed");exit(EXIT_FAILURE);}send(sock, get_request, strlen(get_request), 0);printf("HTTP Client GET method has been sent\n");length = read(sock, buffer, 1024);printf("******** HTTP Client receive msg length: %d,context as follow: ********\n%s\n",length,buffer);printf("****************\n");close(sock);return 0;
}

分别运行上面的服务端和客户端程序,服务端程序运行结果如下:

客户端程序运行结果如下:

 3、实现HTTP的客户端访问百度功能

        本程序使用C++ tcp客户端代码模拟HTTP的客户端,按照http协议请求格式对百度网页进行GET请求消息的组装。

实现demo如下:

#include <iostream>
#include <cstring>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netdb.h>#define URL  "/"                            //资源
#define HTTP_VESTION "HTTP/1.1"
#define HOST "www.baidu.com"                //域名
#define	CONNETION  "Connection: close\r\n"  //短链接
#define BUFFER_SIZE		1024
std::string strBuffer = "";
int getIpAddress(char** ip)
{int ret = -1;struct  hostent *ht = NULL;ht = gethostbyname(HOST);if(ht) {printf("type:%s\n", ht->h_addrtype == AF_INET ? "AF_INET" : "AF_INET6");for(int i=0; ;i++) {if(ht->h_addr_list[i]!=NULL) {*ip = inet_ntoa(*((struct in_addr *)ht->h_addr_list[i]));ret = 1;break;}}}return ret;
}char* receiveNew(int sockfd, size_t& len) {char* buffer = nullptr; // 初始化为nullptrssize_t totalBytesReceived = 0; // 累计接收的字节数ssize_t bytesReceived; // 当前接收的字节数// 循环接收数据,直到对方关闭连接或发生错误do {// 分配额外的空间以容纳更多数据char* newBuffer = new char[totalBytesReceived + 1024]; // 假设每次额外分配1024字节,用于接受下次数据if (buffer) {// 如果有旧的数据,复制到新的缓冲区,每次所有内容复制一遍std::memcpy(newBuffer, buffer, totalBytesReceived);delete[] buffer; // 释放旧缓冲区}buffer = newBuffer; // 更新指针以指向新的缓冲区,指向的内容可以任意大,即只要可分配// 接收数据bytesReceived = recv(sockfd, buffer + totalBytesReceived, 1024, 0);if (bytesReceived == -1) {// 错误处理,例如检查errnostd::cerr << "Error receiving data: " << strerror(errno) << std::endl;delete[] buffer; // 释放已分配的缓冲区return nullptr; // 返回nullptr表示错误}totalBytesReceived += bytesReceived; // 累计已接收的字节数// 如果需要,可以在此处设置接收的最大字节数限制} while (bytesReceived > 0); // 当recv返回0时,表示对方已关闭连接// 调整缓冲区的大小以匹配实际接收的数据量char* finalBuffer = new char[totalBytesReceived + 1]; // +1为了字符串终止符'\0'std::memcpy(finalBuffer, buffer, totalBytesReceived);finalBuffer[totalBytesReceived] = '\0'; // 添加字符串终止符delete[] buffer; // 释放中间缓冲区len = totalBytesReceived; // 更新len以反映实际接收的数据长度return finalBuffer; // 返回最终缓冲区
}void receiveString(int sockfd, size_t& len) {char buffer[BUFFER_SIZE] = {}; // 初始化为nullptrssize_t totalBytesReceived = 0; // 累计接收的字节数ssize_t bytesReceived; // 当前接收的字节数// 循环接收数据,直到对方关闭连接或发生错误do {// 接收数据bytesReceived = recv(sockfd, buffer, BUFFER_SIZE, 0);if (bytesReceived == -1) {// 错误处理,例如检查errnoprintf("Error receiving data:%s", strerror(errno));}strBuffer += buffer;totalBytesReceived += bytesReceived; // 累计已接收的字节数memset(buffer,0,BUFFER_SIZE);// 如果需要,可以在此处设置接收的最大字节数限制} while (bytesReceived > 0); // 当recv返回0时,表示对方已关闭连接len = totalBytesReceived;
}void MakeSocketConnect()
{char* ipAddr = nullptr;getIpAddress(&ipAddr);int sock = 0;struct sockaddr_in serv_addr;serv_addr.sin_family = AF_INET;serv_addr.sin_port = htons(80);if (inet_pton(AF_INET, ipAddr, &serv_addr.sin_addr) <= 0) {perror("Invalid address/Address not supported");exit(EXIT_FAILURE);}if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {perror("Socket creation error");exit(EXIT_FAILURE);}if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {perror("Connection failed");exit(EXIT_FAILURE);}char get_request[1024] = {};sprintf(get_request,"GET %s %s\r\n""Host: %s\r\n""%s\r\n""\r\n",URL,HTTP_VESTION,HOST,CONNETION);send(sock, get_request, strlen(get_request), 0);printf("HTTP Client GET method has been sent\n");size_t len = 0; // 用于保存接收到的数据的长度/* 由于HTTP服务端回复的消息客户端一次接收不完,需要多次接收,直到数据接收完毕*  本文采用下面两种C++方法进行接收*  方法1:采用new方法分配内存,缺点:需要多次分配,并且需要多次memcpy(可以使用c语言malloc分配内存,realloc扩容)*  方法2:采用string容器(stinrg是字符串容器),动态的存储数据,也可以采用vector<char>容器存储*/
#if 0char* receivedData = receiveNew(sock,len);if (receivedData) {// 处理接收到的数据printf("******** HTTP Client receive msg length: %d,context as follow: ********\n%s\n",len,receivedData);printf("****************\n");// 释放动态分配的内存delete[] receivedData;} else {// 错误处理printf("Failed to receive data.\n");}
#elsereceiveString(sock,len);printf("******** HTTP Client receive msg length: %d,context as follow: ********\n%s\n",len,strBuffer.c_str());printf("****************\n");
#endifclose(sock);
}int main() {MakeSocketConnect();return 0;
}

上面程序运行结果如下:

上面接收的响应正文太长,上面图片没有截完。

C++ 实现http请求用法也可参考下面的文章:Linux C/C++ 实现HTTP请求器(TCP客户端)_linux c++ http-CSDN博客

4、HTTP协议的三方库

        使用封装HTTP协议的三方库,可以高效开发HTTP的功能需求,HTTP的协议封装有很多的三方库,下面只介绍几种,更多的三方库可查看其他资料。

(1)cpp-httplib

       优点:

                轻量级:非常轻量,仅包含一个头文件,方便集成到项目中。

                简单易用:API设计直观,可以快速上手。

                跨平台:支持多种操作系统,如Windows、Linux和macOS等。

                支持断点续传:通过ETag和Range字段,可以实现断点续传功能。

        缺点:

                功能相对简单:相比于其他HTTP库,可能不支持一些高级特性。

(2)libcurl

         优点:

                功能强大:支持多种协议,包括HTTP、HTTPS、FTP等。

                灵活性强:支持代理、HTTP POST、SSL连接、HTTP PUT等多种功能。

                跨平台:可以在多种操作系统上运行。

                与其他库配合:可以与其他网络库如libevent、openssl等配合使用,实现高性能的网络

                 编程。

         缺点:

                依赖外部库:需要安装和配置libcurl库。

        libcurl的介绍和使用可参考libcurl开源库的编译与使用全攻略_libcurl编译-CSDN博客

(3)Poco C++ Libraries

         优点:

                功能丰富:除了HTTP功能外,还包含其他实用程序库,如日志记录、XML解析等。

                跨平台:支持多种操作系统和编译器。

                稳定性:经过长时间的验证和广泛的使用,具有较高的稳定性。

         缺点:

                较为庞大:包含多个库和模块,可能对于只需要HTTP功能的项目来说过于庞大。

        cpp-httplib适合需要轻量级、简单易用且跨平台的HTTP库的项目。 libcurl适合需要强大功能和灵活性的项目,特别是需要支持多种协议和与其他库配合使用的场景。Poco C++ Libraries适合需要丰富功能和稳定性的大型项目。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/26725.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

PC端剪映6.0免vip版本,功能随便用

下载解压后点击“JianyingPro.exe”图标即可使用&#xff0c;使用过程中无需登陆账号。操作很简单。 链接&#xff1a;https://pan.baidu.com/s/14bon1Ta9GOUFyUZDa2X3TA?pwd8h2b 提取码&#xff1a;8h2b

采用ava+B/S架构开发的工业级UWB(Ultra-Wideband)室内定系统源码UWB定位系统技术接口及技术特点

采用avaB/S架构开发的工业级UWB&#xff08;Ultra-Wideband&#xff09;室内定系统源码UWB定位系统技术接口及技术特点 UWB&#xff08;Ultra-Wideband&#xff09;定位技术本身并不直接连接蓝牙或其他无线通信技术进行定位。然而&#xff0c;在实际应用中&#xff0c;UWB定位技…

怎么用住宅代理IP?使用住宅代理IP有哪些好处?

如何使用住宅代理IP&#xff1a; 使用住宅代理IP主要涉及以下几个步骤&#xff1a; 选择合适的代理IP供应商&#xff1a; 考虑供应商的可靠性、代理IP的质量、速度、稳定性以及价格。选择信誉良好且服务稳定的供应商&#xff0c;确保获得高质量的代理IP服务。配置代理IP&#…

代理IP常见问题解答,新手必看手册

代理IP在互联网数据收集和业务开展中发挥着重要作用&#xff0c;它充当用户客户端和网站服务器之间的“屏障”&#xff0c;可以保护用户的真实IP地址&#xff0c;并允许用户通过不同的IP地址进行操作。然而&#xff0c;在使用代理IP的过程中&#xff0c;用户经常会遇到一些问题…

vue 中多个表单元素控一个校验规则

1. 场景一 <el-form-itemlabel"确认时长方式"prop"preSubResourceDurationDay" ><div class"confirmDurationDay">最晚使用日期前<el-input-numberv-model"form.preSubResourceDurationDay":precision"0"cla…

axure使用中继器画柱状图

源文件在顶部。 在axure通过读取中继器中的数据来画柱状图&#xff0c;如下图&#xff1a; 1&#xff09;创建一个中继器&#xff0c;在里面创建两列&#xff1a;1列是柱状图底部的名称、2列是柱的高度&#xff0c;如下图&#xff1a; 2&#xff09;双击中继器&#xff0c;画一…

ansible安装wordpress

1.回顾 yum安装wordpress 查看别名 [rootlocalhost ~]# type ll ll 是 ls -l --colorauto 的别名设置别名 aliasyum install -y alias ymyum install -y# 使用别名 ym nginx# 取消别名 unalias ym# 基于LNMP做一个wordpressnginx mysql 5.7 PHP 7.4#1、初始化过程 修改主机名…

【code-server】Code-Server 安装部署

Code-Server 安装部署 1.环境准备 可以参考 https://coder.com/docs/code-server/install code-server的安装流程进行安装&#xff0c;主机环境是 Centos7 建议使用 docker 方式进行安装&#xff0c;可能会出现如下报错&#xff0c;需要升级 GNC 的版本&#xff0c;由于影响交…

派能协议,逆变器测试问题记录

问题一&#xff1a;逆变器无法进行逆变 通过抓取逆变器与bms的通讯报文&#xff0c;如下&#xff1a; 根据派能协议&#xff0c;报文标黄的对应充放电状态&#xff0c;30 30对应的数据为0 0&#xff0c;说明充放电状态全部置0&#xff0c;导致逆变器无法逆变。 问题二&#xf…

推荐系统三十六式学习笔记:原理篇.近邻推荐09|协同过滤中的相似度计算方法有哪些?

目录 相似度的本质相似度的计算方法&#xff1a;1、欧式距离2、余弦相似度3、皮尔逊相关度4 、杰卡德&#xff08;Jaccard&#xff09;相似度 总结 相似度的本质 推荐系统中&#xff0c;推荐算法分为两个门派&#xff0c;一个是机器学习派&#xff0c;一个是相似度门派。机器学…

【记录】ChatGLM3-6B大模型部署、微调(一):部署

ChatGLM3介绍 源码连接&#xff1a; ChatGLM3 是智谱AI和清华大学 KEG 实验室联合发布的对话预训练模型。ChatGLM3-6B 是 ChatGLM3 系列中的开源模型&#xff0c;在保留了前两代模型对话流畅、部署门槛低等众多优秀特性的基础上&#xff0c;ChatGLM3-6B 引入了如下特性&#xf…

算法:模拟题目练习

目录 题目一&#xff1a;替换所有的问号 题目二&#xff1a;提莫攻击 题目三&#xff1a;N字形变换 题目四&#xff1a;外观数列 题目五&#xff1a;数青蛙 首先先解释一下模拟算法是什么&#xff0c;其实模拟算法就是题目让我们干什么我们就干什么&#xff0c;思路比较简…

noVNC 小记

1. 怎么查看Ubuntu版本

汽车行驶中是怎么保障轴瓦安全的?

汽车轴瓦是一种用于减少摩擦和支撑转动部件的关键零部件&#xff0c;通常用于发动机的曲轴、凸轮轴等转动部件上。主要作用是减少转动部件之间的摩擦&#xff0c;支撑和保护曲轴、凸轮轴等旋转部件&#xff0c;确保它们在高速旋转时的稳定性和耐用性。 在汽车轴瓦加工过程中&am…

PHP简约轻型聊天室留言源码

无名轻聊是一款phptxt的轻型聊天室。 无名轻聊特点&#xff1a; 自适应电脑/手机 数据使用txt存放&#xff0c;默认显示近50条聊天记录 采用jqueryajax轮询方式&#xff0c;适合小型聊天环境。 访问地址加?zhi进入管理模式&#xff0c;发送 clear 清空聊天记录。 修改在…

RuoYi: 企业级快速开发平台

目录 前言1 项目介绍1.1 简介1.2 特性 2 技术选型3 功能方面4 代码解释4.1 控制器层示例4.2 服务层示例4.3 数据访问层示例 4 推荐理由4.1 高效开发4.2 灵活性和扩展性4.3 完善的功能和安全性4.4 活跃的开源社区 结语 前言 在现代企业级应用开发中&#xff0c;高效、稳定、安全…

使用脚手架创建vue2项目(关闭eslint语法检查 、运行项目时自动打开网址、src文件夹简写方法)

使用脚手架创建vue2项目会默认安装的插件&#xff08;eslint) 这个插件是检查语法的。 假设我们在main.js中定义了一个变量&#xff0c;没有使用 eslint 就会检测出错误 &#xff08;事实是我们并没有写错而是eslint 给我们判断是错的&#xff0c;所以这样会很麻烦&#xff…

第19篇 Intel FPGA Monitor Program的使用<二>

Q&#xff1a;Intel FPGA Monitor Program里集成的Computer System是什么架构的呢&#xff1f; A&#xff1a;我们以DE2-115的DE2-115_Computer System为例介绍&#xff0c;简单说DE2-115_Computer System就是一个Qsys系统&#xff0c;该系统包含Nios II处理器以及DE2-115开发…

风控中的文本相似方法之余弦定理

一、 余弦相似概述 余弦相似性通过测量两个向量的夹角的余弦值来度量它们之间的相似性。0度角的余弦值是1&#xff0c;而其他任何角度的余弦值都不大于1&#xff1b;并且其最小值是-1。 从而两个向量之间的角度的余弦值确定两个向量是否大致指向相同的方向。结果是与向量的长…

Java 编程语言的核心知识点与特性

Java 是一种广泛使用的编程语言&#xff0c;自 1995 年发布以来&#xff0c;它已经成为了企业级应用开发、移动应用开发、大数据处理和云计算等领域的主流技术。本文将介绍 Java 编程语言的一些核心知识点和特性&#xff0c;帮助读者更好地理解和使用 Java。 面向对象编程&…