Http协议封装
Myhttp封装http协议
源代码
#include <iostream>
#include <cstring>
#include <string>
#include <thread>
#include <atomic>
#include <fstream> // 添加文件操作头文件#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#pragma comment(lib, "ws2_32.lib")
typedef int socklen_t;
#else
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <arpa/inet.h> // 包含 inet_pton 函数
#define closesocket close
#endifstruct hostent *AutoGetIp(std::string domain, std::string &target_ip)
{struct hostent *host = gethostbyname(domain.c_str());if (host == nullptr){std::cerr << "Get IP address error for domain: " << domain << std::endl;return nullptr;}std::cout << "Initialized domain to IP: " << host->h_name;if (host->h_addr_list[0]){target_ip = inet_ntoa(*(struct in_addr *)host->h_addr_list[0]); // 将域名返回的可用ip列表第一个赋值给ipstd::cout << " --> " << target_ip << std::endl;}return host;
}class HttpRequest
{
private:int client_fd = -1;std::atomic<bool> stopListening{false};public:struct hostent *host; // 主机结构体std::string domain;std::string ip;int ip_version = AF_INET; // 默认使用ipv4int port = 80; // 默认http协议是80端口HttpRequest() : host(nullptr) {}HttpRequest(std::string domain_) : HttpRequest(domain_, 80) {}HttpRequest(std::string domain_, int port_) : domain(domain_), port(port_){std::string target_ip;host = AutoGetIp(domain, target_ip);if (host == nullptr){std::cerr << "Failed to get IP address for domain: " << domain << std::endl;return;}ip = target_ip;ip_version = host->h_addrtype;std::string ip_str = ip_version == AF_INET ? "IPv4" : "IPv6";std::cout << "IP version: " << ip_str << std::endl;}HttpRequest(std::string ip_, int ip_v, int port_) : ip(ip_), ip_version(ip_v), port(port_) // 如果只知道ip和ip协议的版本{struct in_addr addr; // ipv4地址结构体if (inet_pton(ip_version, ip.c_str(), &addr) <= 0){std::cerr << "Invalid address/ Address not supported." << std::endl;return;}host = gethostbyaddr((const char *)&addr, sizeof(addr), ip_version);if (host == nullptr){std::cerr << "Get host by address error for IP: " << ip << std::endl;return;}domain = host->h_name;printf("Hostname: %s\n", host->h_name);}~HttpRequest(){stopListening = true;if (client_fd != -1){closesocket(client_fd);}
#ifdef _WIN32WSACleanup();
#endif}void setIP(std::string ip_) { ip = ip_; }void setPort(int port_) { port = port_; }int connect_to(){
#ifdef _WIN32WSADATA wsaData;if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0){std::cerr << "Failed to initialize Winsock." << std::endl;return -1;}
#endifclient_fd = socket(ip_version, SOCK_STREAM, 0);if (client_fd == INVALID_SOCKET){std::cerr << "Socket creation failed." << std::endl;
#ifdef _WIN32WSACleanup();
#endifreturn -1;}struct sockaddr_in server_address;server_address.sin_family = AF_INET; // 使用 IPv4 协议server_address.sin_port = htons(port);if (inet_pton(ip_version, ip.c_str(), &server_address.sin_addr) <= 0){std::cerr << "Invalid address/ Address not supported." << std::endl;closesocket(client_fd);
#ifdef _WIN32WSACleanup();
#endifreturn -1;}if (connect(client_fd, (struct sockaddr *)&server_address, sizeof(server_address)) < 0){std::cerr << "Connection failed." << std::endl;closesocket(client_fd);
#ifdef _WIN32WSACleanup();
#endifreturn -1;}std::cout << "Connected to server." << std::endl;sendContent();std::ofstream outFile("server_response.txt", std::ios::app); // 创建或打开文件以追加内容if (!outFile.is_open()){std::cerr << "Failed to open file for writing." << std::endl;return -1;}std::cout << "File opened successfully: server_response.txt" << std::endl;std::thread t([this, &outFile](){char buffer[1024] = {0};std::cout << "Listening for msg" << std::endl;while (!stopListening){int valread = recv(client_fd, buffer, sizeof(buffer) - 1, 0);if (valread < 0){std::cerr << "Receive failed." << std::endl;break;}else if (valread == 0){std::cout << "Connection closed by server." << std::endl;break;}else{buffer[valread] = '\0';std::cout << "Received message from server: " << buffer << std::endl;outFile << buffer; // 将接收到的数据写入文件}memset(buffer, 0, sizeof(buffer));}outFile.close(); // 关闭文件std::cout << "File closed successfully: server_response.txt" << std::endl;closesocket(client_fd); });t.join();#ifdef _WIN32WSACleanup();
#endifreturn 0;}void sendContent(){std::string msg = "GET / HTTP/1.1\r\nHost: " + domain + "\r\nConnection: Close\r\n\r\n";int result = send(client_fd, msg.c_str(), msg.length(), 0);if (result < 0){std::cerr << "Send failed." << std::endl;}else{std::cout << "Successfully sent " << result << " bytes\n";}}
};int main()
{
#ifdef _WIN32WSADATA wsaData;if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0){std::cerr << "Failed to initialize Winsock." << std::endl;return -1;}
#endifHttpRequest httprequest("www.baidu.com", 80);httprequest.connect_to();#ifdef _WIN32WSACleanup();
#endifreturn 0;
}
API函数
gethostbyname()
gethostbyname
函数用于通过域名或主机名获取其对应的IP地址信息。它返回一个指向hostent
结构体的指针,该结构体包含了主机的相关信息。
gethostbyname
函数原型
#include <netdb.h>
struct hostent *gethostbyname(const char *name);
hostent
结构体内容
hostent
结构体定义如下:
struct hostent {char *h_name; // 官方主机名char **h_aliases; // 主机别名列表int h_addrtype; // 地址类型(如AF_INET表示IPv4)int h_length; // 地址长度char **h_addr_list; // 地址列表
};
- h_name:官方主机名。例如,
www.baidu.com
的官方主机名可能是www.a.shifen.com
。 - h_aliases:主机的别名列表。一个主机可以有多个别名,这些别名也用于访问该主机。
- h_addrtype:地址类型,通常为
AF_INET
表示IPv4地址。 - h_length:地址长度,IPv4地址长度为4字节。
- h_addr_list:地址列表,包含了主机的所有IP地址。对于IPv4地址,可以使用
inet_ntoa
函数将其转换为点分十进制格式。
工作原理
gethostbyname
首先检查本地的/etc/hosts
文件,如果找到匹配的主机名,则返回相应的IP地址。- 如果未在
hosts
文件中找到匹配项,它会向DNS服务器发送查询请求,以获取主机名对应的IP地址。
注意事项
gethostbyname
只能返回IPv4地址。如果需要获取IPv6地址或同时获取IPv4和IPv6地址,应使用getaddrinfo
函数。- 返回的
hostent
结构体的内存由系统管理,因此在使用完毕后不需要手动释放。
gethostbyaddr()
在Linux系统中,将IP地址转换成域名(即反向DNS解析)可以使用gethostbyaddr
函数。这个函数是POSIX标准的一部分,用于根据IP地址查找对应的主机名。以下是关于gethostbyaddr
函数的详细说明和使用示例:
函数原型
#include <netdb.h>
struct hostent *gethostbyaddr(const void *addr, socklen_t len, int type);
参数说明
- addr:指向IP地址的指针。对于IPv4地址,应该是一个指向
struct in_addr
的指针;对于IPv6地址,应该是一个指向struct in6_addr
的指针。 - len:地址的长度。对于IPv4地址,长度为
sizeof(struct in_addr)
;对于IPv6地址,长度为sizeof(struct in6_addr)
。 - type:地址类型,可以是
AF_INET
(IPv4)或AF_INET6
(IPv6)。
返回值
- 成功时返回指向
hostent
结构体的指针,该结构体包含了主机的相关信息。 - 失败时返回
NULL
,可以通过h_errno
获取错误原因(例如使用herror
函数)。
示例代码
以下是一个使用gethostbyaddr
函数进行反向DNS解析的示例:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netdb.h>
#include <arpa/inet.h>int main() {struct in_addr ip_addr;struct hostent *host;// 示例IP地址inet_pton(AF_INET, "8.8.8.8", &ip_addr);// 执行反向DNS解析host = gethostbyaddr(&ip_addr, sizeof(ip_addr), AF_INET);if (host == NULL) {herror("gethostbyaddr failed");return EXIT_FAILURE;}// 输出主机名printf("Hostname: %s\n", host->h_name);return EXIT_SUCCESS;
}
注意事项
- 在使用
gethostbyaddr
之前,确保系统中已经配置了DNS服务器,并且DNS服务器能够响应反向查询请求。 gethostbyaddr
函数可能不是线程安全的,如果需要在多线程环境中使用,可以考虑使用getaddrinfo
函数的反向解析功能。
inet_ntoa()
-
功能:将IPv4地址的网络字节序二进制形式转换为点分十进制的字符串表示形式。
-
参数:
struct in_addr in
:包含IPv4地址的in_addr
结构体。
-
返回值:
- 返回指向转换后的字符串的指针。该字符串是静态分配的,因此每次调用
inet_ntoa
都会覆盖上一次的结果
- 返回指向转换后的字符串的指针。该字符串是静态分配的,因此每次调用
-
注意事项
inet_ntoa
只支持IPv4地址,且返回的字符串是静态分配的,因此在多线程环境中使用时需要特别注意。- 对于IPv6地址或需要线程安全的场景,推荐使用
inet_pton
和inet_ntop
。
struct in_addr ip_addr;
inet_pton(AF_INET, "192.168.1.1", &ip_addr);
char *ip_str = inet_ntoa(ip_addr);
printf("IP address: %s\n", ip_str);
inet_ntop()
- 功能:将IP地址的网络字节序二进制形式转换为字符串表示形式。
- 参数:
int af
:地址族,可以是AF_INET
(IPv4)或AF_INET6
(IPv6)。const void *src
:指向二进制IP地址的指针。char *dst
:指向用于存储转换后的字符串的缓冲区的指针。socklen_t size
:缓冲区的大小。
- 返回值:
- 成功时返回指向
dst
的指针。 - 失败时返回
NULL
。
- 成功时返回指向
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>int main() {struct in_addr ip_addr;inet_pton(AF_INET, "192.168.1.1", &ip_addr);char ip_str[INET_ADDRSTRLEN];const char *result = inet_ntop(AF_INET, &ip_addr, ip_str, INET_ADDRSTRLEN);if (result == NULL) {perror("inet_ntop");exit(EXIT_FAILURE);}printf("IP address in string format: %s\n", ip_str);return 0;
}
inet_pton()
- 功能:将IP地址的字符串表示形式转换为网络字节序的二进制形式。
- 参数:
int af
:地址族,可以是AF_INET
(IPv4)或AF_INET6
(IPv6)。const char *src
:指向IP地址字符串的指针。void *dst
:指向存储转换后的二进制地址的缓冲区的指针。
- 返回值:
- 成功时返回1。
- 输入字符串无效时返回0。
- 出错时返回-1。
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>int main() {struct in_addr ip_addr;int result = inet_pton(AF_INET, "192.168.1.1", &ip_addr);if (result != 1) {perror("inet_pton");exit(EXIT_FAILURE);}printf("IP address in binary format: %u.%u.%u.%u\n",(unsigned char)ip_addr.s_addr,(unsigned char)(ip_addr.s_addr >> 8),(unsigned char)(ip_addr.s_addr >> 16),(unsigned char)(ip_addr.s_addr >> 24));return 0;
}
相关文章:
Http协议封装
Myhttp封装http协议 源代码 #include <iostream> #include <cstring> #include <string> #include <thread> #include <atomic> #include <fstream> // 添加文件操作头文件#ifdef _WIN32 #include <winsock2.h> #include <ws2t…...

el-date-picker 禁用一个月前、一个月后(当天之后)的时间 datetimerange
文章目录 功能需求今天是 2025-01-09示例1示例2 代码 Vue2 功能需求 时间范围选择器,最大时间选择尺度为一个月。 今天是 2025-01-09 示例1 选择 2025-01-02 日 禁用未来日期(2025-01-09之后日期) 禁用上月2号(31日之前&#…...

【C】编译与链接
在本文章里面,我们讲会讲解C语言程序是如何从我们写的代码一步步变成计算机可以执行的二进制指令,并最终执行的。C语言程序运行主要包括两大步骤 -- 编译和链接,接下来我们就来一一讲解。 目录 1 翻译环境和运行环境 2 翻译环境 1&#…...

Github上传项目
写在前面: 本次博客仅仅是个人学习记录,不具备教学作用。内容整理来自网络,太多了,所以就不放来源了。 在github页面的准备: 输入标题。 往下滑,创建 创建后会跳出下面的页面 进入home就可以看到我们刚…...
webrtc之rtc::ArrayView<const uint8_t>
rtc::ArrayView<const uint8_t> 是 WebRTC(或其他基于 rtc 命名空间的库)中常见的一个类型,它通常用于表示一块 只读的内存区域,该内存区域由一系列 uint8_t 类型(无符号 8 位整数)元素组成。 1. rt…...

Zemax 序列模式下的扩束器
扩束器结构原理 扩束器用于增加准直光束(例如激光束)的直径,同时保持其准直。它通常用于激光光学和其他需要修改光束大小或发散度的应用。 在典型的扩束器中,输入光束是准直激光器,或光束进入第一个光学元件。当光束开…...

Flink系统知识讲解之:如何识别反压的源头
Flink系统知识之:如何识别反压的源头 什么是反压 Ufuk Celebi 在一篇古老但仍然准确的文章中对此做了很好的解释。如果您不熟悉这个概念,强烈推荐您阅读这篇文章。如果想更深入、更低层次地了解该主题以及 Flink 网络协议栈的工作原理,这里有…...

RK3568平台(USB篇)禁用USB端口
一.linux中怎样查看usb的端口号 在USB口插入U盘: [ 198.141319][ T106] usb 3-1.3: new SuperSpeed Gen 1 USB device number 5 using xhci-hcd [ 198.161695][ T106] usb 3-1.3: New USB device found, idVendor=0781, idProduct=5591, bcdDevice= 1.00 [ 198.161721]…...
洛谷 P3000 [USACO10DEC] Cow Calisthenics G
思路 题目要求断若干条边后形成的连通块中,最大的直径最小,很明显的二分。关键就在于如何写 c h e c k check check 函数了。 可以用 d f s dfs dfs 来判断要断哪条边。 一、 d [ u ] d[u] d[u] 定义 设 d [ u ] d[u] d[u] 为从 u u u 出发到子树…...

Web渗透测试之XSS跨站脚本攻击 盲打 详解
目录 XSS盲打 什么是盲打: 盲打主要目的 XSS盲打 什么是盲打: 发现某个页面有xss漏洞 但是注入后没看到效果 而是在其它页面进行xss显示的效果 这种就叫盲打. 我注册了一个网站的用户 注册页面存在xss漏洞跳转到首页 看不到注册信息的输出 当管理员打开页面查看什么用户…...
经典编程题:服务器广播
题目描述: 服务器连接方式包括直接相连,间接连接。A 和 B 直接连接,B 和 C 直接连接,则 A 和 C 间接连接。直接连接和间接连接都可以发送广播。 给出一个 N*N 数组,代表 N 个服务器,matrix[i][j]1…...

【网络协议】静态路由详解
网络中的路由器通过以下两种方式之一发现远程网络: 静态配置路由动态路由协议 在本文,我们将学习关于静态路由的各种概念,例如如何配置静态路由、路由表如何进行决策、路由接口等相关知识。 文章目录 引言直连网络静态路由路由表原则原则1原…...

朝天椒USB服务器在银泰证券虚拟化超融合场景的应用案例
在数字化浪潮席卷金融行业的今天,银泰证券作为业内知名的金融机构,始终致力于提升业务运营效率与数据安全性。面对虚拟化超融合场景下各种认证U盾的管理挑战,银泰证券选择了朝天椒USB服务器作为其解决方案,成功实现了U盾在虚拟机中…...

.NET framework、Core和Standard都是什么?
对于这些概念一直没有深入去理解,以至于经过.net这几年的发展进化,概念越来越多,越来越梳理不容易理解了。内心深处存在思想上的懒惰,以为自己专注于Unity开发就好,这些并不属于核心范畴,所以对这些概念总是…...

FairGuard游戏安全2024年度报告
导 读:2024年,国内游戏市场实际销售收入3257.83亿元,同比增长7.53%,游戏用户规模6.74亿人,同比增长0.94%,市场收入与用户规模双双实现突破,迎来了历史新高点。但游戏黑灰产规模也在迅速扩大&…...
JetBrains IDEs和Visual Studio Code的对比
JetBrains IDEs和Visual Studio Code的对比 JetBrains IDEs是捷克JetBrains公司开发的一系列集成开发环境(IDE)。以下是具体介绍:IntelliJ IDEA是JetBrains 公司的一款产品 主要产品 IntelliJ IDEA:一款功能强大且广泛应用的Java集成开发环境,有开源免费的社区版和商业收…...

文件剪切走:深度解析与高效恢复策略
一、文件剪切走现象解读 在计算机的日常使用中,“文件剪切走”这一术语形象地描述了文件在移动过程中意外丢失的现象。当用户尝试将文件从一个位置“剪切”并粘贴到另一个位置时,如果操作不当或系统出现异常,可能会导致文件在源位置消失&…...

Win32汇编学习笔记09.SEH和反调试
Win32汇编学习笔记09.SEH和反调试-C/C基础-断点社区-专业的老牌游戏安全技术交流社区 - BpSend.net SEH - structed exception handler 结构化异常处理 跟筛选一样都是用来处理异常的,但不同的是 筛选器是整个进程最终处理异常的函数,但无法做到比较精细的去处理异常(例如处理…...
[人工智能]CSDN创作助手体验
一、什么是智能体 智能体是一种能够感知环境、学习、推理和行动的实体。它可以是一个计算机程序、机器人或其他类似的系统。智能体的目标是通过与环境的交互来实现特定的任务或目标。 智能体通常由以下几个组件组成: 感知器:感知器是智能体与环境之间的…...

vue3中el-table实现多表头并表格合并行或列
1、el-table中添加事件 :span-method"genderSpanCity" <el-table :span-method"genderSpanCity":data"data.tableData":fit"true" table-layout"fixed" header-align"center" stripestyle"width:100%;he…...
【位运算】消失的两个数字(hard)
消失的两个数字(hard) 题⽬描述:解法(位运算):Java 算法代码:更简便代码 题⽬链接:⾯试题 17.19. 消失的两个数字 题⽬描述: 给定⼀个数组,包含从 1 到 N 所有…...

理解 MCP 工作流:使用 Ollama 和 LangChain 构建本地 MCP 客户端
🌟 什么是 MCP? 模型控制协议 (MCP) 是一种创新的协议,旨在无缝连接 AI 模型与应用程序。 MCP 是一个开源协议,它标准化了我们的 LLM 应用程序连接所需工具和数据源并与之协作的方式。 可以把它想象成你的 AI 模型 和想要使用它…...

linux arm系统烧录
1、打开瑞芯微程序 2、按住linux arm 的 recover按键 插入电源 3、当瑞芯微检测到有设备 4、松开recover按键 5、选择升级固件 6、点击固件选择本地刷机的linux arm 镜像 7、点击升级 (忘了有没有这步了 估计有) 刷机程序 和 镜像 就不提供了。要刷的时…...

Keil 中设置 STM32 Flash 和 RAM 地址详解
文章目录 Keil 中设置 STM32 Flash 和 RAM 地址详解一、Flash 和 RAM 配置界面(Target 选项卡)1. IROM1(用于配置 Flash)2. IRAM1(用于配置 RAM)二、链接器设置界面(Linker 选项卡)1. 勾选“Use Memory Layout from Target Dialog”2. 查看链接器参数(如果没有勾选上面…...

NFT模式:数字资产确权与链游经济系统构建
NFT模式:数字资产确权与链游经济系统构建 ——从技术架构到可持续生态的范式革命 一、确权技术革新:构建可信数字资产基石 1. 区块链底层架构的进化 跨链互操作协议:基于LayerZero协议实现以太坊、Solana等公链资产互通,通过零知…...
汇编常见指令
汇编常见指令 一、数据传送指令 指令功能示例说明MOV数据传送MOV EAX, 10将立即数 10 送入 EAXMOV [EBX], EAX将 EAX 值存入 EBX 指向的内存LEA加载有效地址LEA EAX, [EBX4]将 EBX4 的地址存入 EAX(不访问内存)XCHG交换数据XCHG EAX, EBX交换 EAX 和 EB…...

SpringTask-03.入门案例
一.入门案例 启动类: package com.sky;import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCach…...
JVM暂停(Stop-The-World,STW)的原因分类及对应排查方案
JVM暂停(Stop-The-World,STW)的完整原因分类及对应排查方案,结合JVM运行机制和常见故障场景整理而成: 一、GC相关暂停 1. 安全点(Safepoint)阻塞 现象:JVM暂停但无GC日志,日志显示No GCs detected。原因:JVM等待所有线程进入安全点(如…...
使用Matplotlib创建炫酷的3D散点图:数据可视化的新维度
文章目录 基础实现代码代码解析进阶技巧1. 自定义点的大小和颜色2. 添加图例和样式美化3. 真实数据应用示例实用技巧与注意事项完整示例(带样式)应用场景在数据科学和可视化领域,三维图形能为我们提供更丰富的数据洞察。本文将手把手教你如何使用Python的Matplotlib库创建引…...

Docker 本地安装 mysql 数据库
Docker: Accelerated Container Application Development 下载对应操作系统版本的 docker ;并安装。 基础操作不再赘述。 打开 macOS 终端,开始 docker 安装mysql之旅 第一步 docker search mysql 》〉docker search mysql NAME DE…...