Http协议封装

news2025/1/10 22:33:44

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
#endif

struct 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列表第一个赋值给ip
        std::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; // 默认使用ipv4
    int 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 _WIN32
        WSACleanup();
#endif
    }

    void setIP(std::string ip_) { ip = ip_; }
    void setPort(int port_) { port = port_; }

    int connect_to()
    {
#ifdef _WIN32
        WSADATA wsaData;
        if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
        {
            std::cerr << "Failed to initialize Winsock." << std::endl;
            return -1;
        }
#endif

        client_fd = socket(ip_version, SOCK_STREAM, 0);
        if (client_fd == INVALID_SOCKET)
        {
            std::cerr << "Socket creation failed." << std::endl;
#ifdef _WIN32
            WSACleanup();
#endif
            return -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 _WIN32
            WSACleanup();
#endif
            return -1;
        }

        if (connect(client_fd, (struct sockaddr *)&server_address, sizeof(server_address)) < 0)
        {
            std::cerr << "Connection failed." << std::endl;
            closesocket(client_fd);
#ifdef _WIN32
            WSACleanup();
#endif
            return -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 _WIN32
        WSACleanup();
#endif
        return 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 _WIN32
    WSADATA wsaData;
    if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
    {
        std::cerr << "Failed to initialize Winsock." << std::endl;
        return -1;
    }
#endif

    HttpRequest httprequest("www.baidu.com", 80);
    httprequest.connect_to();

#ifdef _WIN32
    WSACleanup();
#endif

    return 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_ptoninet_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://www.coloradmin.cn/o/2274579.html

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

相关文章

uniapp 微信小程序内嵌h5实时通信

描述&#xff1a; 小程序webview内嵌的h5需要向小程序实时发送消息&#xff0c;有人说postMessage可以实现&#xff0c;所以试验一下&#xff0c;结果是实现不了实时&#xff0c;只能在特定时机后退、组件销毁、分享时小程序才能接收到信息&#xff08;小程序为了安全等考虑做了…

腾讯云AI代码助手编程挑战赛-厨房助手之AI大厨

腾讯云AI代码助手编程挑战赛-厨房助手之AI大厨 作品简介 身处当今如火箭般迅猛发展的互联网时代&#xff0c;智能聊天助手已然化身成为提升用户体验的关键利器&#xff0c;全方位渗透至人们的数字生活。 紧紧跟随着这股汹涌澎湃的时代浪潮&#xff0c;我毅然投身于极具挑战性…

网易云音乐登录两部手机:IP属地归属何方?

在数字化生活日益普及的今天&#xff0c;音乐平台成为了我们日常娱乐不可或缺的一部分。网易云音乐&#xff0c;作为众多音乐爱好者的首选&#xff0c;其丰富的音乐资源和个性化的推荐算法深受用户喜爱。然而&#xff0c;随着多设备登录成为常态&#xff0c;一个问题也随之浮现…

[工具]git克隆远程仓库到本地快速操作流程

一、新建空目录 二、初始化本地仓库 git init 初始化成功后&#xff0c;会在当前目录生成一个.git的目录。 三、关联远程仓库 git remote add origin <URL>这一步让本地仓库与远程仓库进行关联&#xff0c;origin是远程仓库的别名&#xff0c;可以自定义。 四、克隆…

如何在 Ubuntu 22.04 上集成 Collabora Online 教程

简介 在本教程中&#xff0c;我们将详细讲解如何在 Ubuntu 22.04 操作系统上安装 Collabora Online。 Collabora Online 是一个基于 LibreOffice 技术的开源办公套件。它提供了许多功能&#xff0c;其中最有用的一个功能是 Collabora 提供了 Word 文档、电子表格、演示文稿等…

Linux的内核空间中的日志打印函数printk的详解;如果设置`printk` 函数的默认日志级别和是否输出到终端控制台

引言 首先&#xff0c;要知道&#xff0c;内核空间是没有printf函数的&#xff0c;printf函数是是用户空间的标准 I/O 函数&#xff0c;而不是内核空间中的。 所以在运行于内核空间的程序中(比如驱动程序)&#xff0c;是不能使用printf函数的&#xff0c;但有时候我们又需要打…

Python编程实例-特征向量与特征值编程实现

特征向量与特征值编程实现 文章目录 特征向量与特征值编程实现1、什么是特征向量2、特征向量背后的直觉3、为什么特征向量很重要?4、如何计算特征向量?4、特征向量Python实现5、可视化特征向量6、总结线性代数是许多高级数学概念的基石,广泛应用于数据科学、机器学习、计算机…

202-01-06 Unity 使用 Tip1 —— UnityHub 模块卸载重装

文章目录 1 卸载模块2 更新配置文件3 重启 UnityHub 起因&#xff1a; ​ WebGL 平台打包程序报错&#xff0c;懒得修复了&#xff0c;因此粗暴地删了重装。但是 UnityHub 不支持卸载模块&#xff0c;因此手动配置。 1 卸载模块 ​ 以 Unity 6000.0.26f1c1 为例&#xff0c;其…

Git的简单介绍与如何安装Git

文章目录 前言一、初始git1.git是什么2.为什么要使用git(出现的问题)3.git是如何解决问题的 二、git的安装与卸载1.centos系统2.ubuntu系统3.windows 三、搭建git本地环境1.创建git本地仓库2.配置用户信息 总结 前言 本文简单引入git的相关内容。 一、初始git 1.git是什么 g…

Linux 进程入门:带你走进操作系统的核心地带(1)

&#x1f31f; 快来参与讨论&#x1f4ac;&#xff0c;点赞&#x1f44d;、收藏⭐、分享&#x1f4e4;&#xff0c;共创活力社区。&#x1f31f; &#x1f6a9;用通俗易懂且不失专业性的文字&#xff0c;讲解计算机领域那些看似枯燥的知识点&#x1f6a9; 在 Linux 操作系…

C#版OpenCv常用函数大全

OpenCvSharp 是 OpenCV 的NET封装&#xff0c;提供了丰富的图像处理和计算机视觉功能。以下是一些常用函数及其详细说明。 1. 图像读取与显示 Cv2.ImRead 功能&#xff1a;读取图像文件并返回一个 Mat 对象。用法&#xff1a;Mat image Cv2.ImRead("path/to/image.jpg&…

【初阶数据结构】线性表之单链表

文章目录 前言 一、单链表的概念与结构 1.概念 2.结点 3.性质 二、实现单链表 1.结构的定义 2.链表的打印和结点的申请 3.单链表的尾插和头插 4.单链表的尾删和头删 5.单链表的查找 6.指定位置之前插入数据和指定位置之后插入数据 7.删除pos结点和删除pos之后的结…

DB-Engines Ranking 2025年1月数据库排行

DB-Engines Ranking 2025年1月数据库排行 DB-Engines排名根据数据库管理系统的受欢迎程度进行排名。排名每月更新一次。 2025年1月&#xff0c;共有423个数据库进入排行。 排行榜 Oracle Oracle 连续三月稳居榜首&#xff0c;排名稳定。2025 年 1 月分数较上月增 5.03&#x…

Hadoop3.x 万字解析,从入门到剖析源码

&#x1f496; 欢迎来到我的博客&#xff01; 非常高兴能在这里与您相遇。在这里&#xff0c;您不仅能获得有趣的技术分享&#xff0c;还能感受到轻松愉快的氛围。无论您是编程新手&#xff0c;还是资深开发者&#xff0c;都能在这里找到属于您的知识宝藏&#xff0c;学习和成长…

鸿蒙的APP真机调试以及发布

目录&#xff1a; 1、创建好鸿蒙项目2、创建AGC项目3、实现自动签名3.1、手动方式创建签名文件和密码 4、运行项目5、无线真机调试 1、创建好鸿蒙项目 2、创建AGC项目 &#xff08;1&#xff09;在File->Project Structure->Project->Signing Configs中进行登录。(未…

Swin Transformer模型详解(附pytorch实现)

写在前面 Swin Transformer&#xff08;Shifted Window Transformer&#xff09;是一种新颖的视觉Transformer模型&#xff0c;在2021年由微软亚洲研究院提出。这一模型提出了一种基于局部窗口的自注意力机制&#xff0c;显著改善了Vision Transformer&#xff08;ViT&#xf…

穷举vs暴搜vs深搜vs回溯vs剪枝系列一>字母大小写全排列

题目&#xff1a; 解析&#xff1a; 代码&#xff1a; private List<String> ret;private StringBuffer path;public List<String> letterCasePermutation(String s) {ret new ArrayList<>();path new StringBuffer();dfs(s,0);return ret;}private voi…

LabVIEW软件侵权分析与应对

问&#xff1a;如果涉及到LabVIEW软件的仿制或模仿&#xff0c;特别是在功能、界面等方面&#xff0c;如何判断是否构成侵权&#xff1f;该如何应对&#xff1f; 答&#xff1a;LabVIEW软件的侵权问题&#xff0c;尤其是在涉及到仿制或模仿其功能、界面、设计等方面&#xff0…

玩转 JMeter:Random Order Controller让测试“乱”出花样

嘿&#xff0c;各位性能测试的小伙伴们&#xff01;今天咱要来唠唠 JMeter 里超级有趣又超实用的 Random Order Controller&#xff08;随机顺序控制器&#xff09;&#xff0c;它就像是性能测试这场大戏里的“魔术棒”&#xff0c;轻轻一挥&#xff0c;就能让测试场景变得千变…

探秘MetaGPT:革新软件开发的多智能体框架(22/30)

一、MetaGPT 引发的 AI 变革浪潮 近年来&#xff0c;人工智能大模型领域取得了令人瞩目的进展&#xff0c;GPT-3、GPT-4、PaLM 等模型展现出了惊人的自然语言处理能力&#xff0c;仿佛为 AI 世界打开了一扇通往无限可能的大门。它们能够生成流畅的文本、回答复杂的问题、进行创…