Linux C/C++ 开发(学习笔记十 ):实现http请求器(TCP客户端)

简介: Linux C/C++ 开发(学习笔记十 ):实现http请求器(TCP客户端)

一、需要实现的内容和方式

比如进入百度,可以看见右侧web界面的必要信息,这就需要通过http客户端去请求获取。

在网页上打开,比如在chrome浏览器中,按F12即可进入开发者模式,可以看见发送的请求

实现方式

二、完整代码

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<netdb.h>
#include <fcntl.h>
#define HTTP_VERSION "HTTP/1.1"
#define CONNECTION_TYPE "Connection:close\r\n"
#define BUFFER_SIZE 4096
char* host_to_ip(const char* hostname){
    hostent *host_entry=gethostbyname(hostname);
    //14.215.177.39 -->usigned int(因为ipv4是32位的,每个点分隔,值为0~255.正好可以用unsigned int表示,每8位表示一个0~255,共4个)
    //inet_nota 是把 0x12121212 --->"18.18.18.18" 也就是将网络地址转换成“.”点隔的字符串格式
    if(host_entry){
        return inet_ntoa(*(in_addr*)*host_entry->h_addr_list);//由于h_addr_list可能有几个ip地址,这边取第一个,因此加*,然后强转成in_addr*,由于inet_ntoa为值传递,因此还要加*
    }
    return NULL;
}
int http_create_socket(char* ip){
    int sockfd=socket(AF_INET,SOCK_STREAM,0);//sockfd的结果就是int类型,是一个文件句柄。TCP要用SOCK_STREAM,UDP用SOCK_DGRAM
    sockaddr_in sin={0};
    sin.sin_family=AF_INET;
    sin.sin_port=htons(80);//http协议端口为80
    sin.sin_addr.s_addr=inet_addr(ip);//"字符串的ip"地址转为uint32_t和上面的inet_ntoa正好相反
    // int ret=connect(sockfd,(sockaddr*)&sin,sizeof(sockaddr_in));
    // if(ret!=0) return -1;
    if (0 != connect(sockfd, (struct sockaddr*)&sin, sizeof(struct sockaddr_in))) {
    return -1;
  }
    fcntl(sockfd,F_SETFL,O_NONBLOCK);//设置为非阻塞(如果socket是阻塞,read(),会阻塞挂起。如果socket是非阻塞,read()也是立刻返回)(设置文件状态标志用F_GETFL,读取文件状态标志用F_SETFL)
    return sockfd;
}
//hostname:github.com
//resource:/wangbojing
char* http_send_request(const char* hostname,const char* resource){
    char* ip=host_to_ip(hostname);
    int sockfd=http_create_socket(ip);
    char buffer[BUFFER_SIZE]={0};
    sprintf(buffer,
"GET %s %s\r\n\
Host:%s\r\n\
%s\r\n\
\r\n",
    resource,HTTP_VERSION,
    hostname,
    CONNECTION_TYPE
    );
    send(sockfd,buffer,strlen(buffer),0);
    // recv()//因为是非阻塞状态,如果用recv会快速过去
    //select
    fd_set fdread;
    FD_ZERO(&fdread);//用来清空fd_set集合,即让fd_set集合不再包含任何文件句柄
    FD_SET(sockfd,&fdread);//将sockfd置为检测的状态(用来将一个给定的文件描述符加入集合之中)
    timeval tv;
    tv.tv_sec=5;//5秒间隔 select采集一次
    tv.tv_usec=0;
    char* result=(char*)malloc(sizeof(int));
    memset(result,0,sizeof(int));
    while(1){
        int selection=select(sockfd+1,&fdread,NULL,NULL,&tv);//第一个参数为所有文件描述符的最大值+1   用select去监测,这个io里面有无数据
        if(!selection||!FD_ISSET(sockfd,&fdread)){//FD_ISSET判断描述符fd是否在给定的描述符集fdset中
            break;
        }else{
            memset(buffer,0,BUFFER_SIZE);
            int len=recv(sockfd,buffer,BUFFER_SIZE,0);//接受数据
            if(len==0){//disconnect
                break;
            }
            result=(char*)realloc(result,(strlen(result)+len+1)*sizeof(char));//重新分配内存重建(+1是为了末尾'\0',不是最后一个的话会被覆盖)
            strncat(result,buffer,len);//把buffer数据copy到resulut中
        }
    }
    return result;
}
int main(int argc,char* argv[]){
    if(argc<3) return -1;
    char* response = http_send_request(argv[1],argv[2]);
    printf("response:%s\n",response);
    free(response);
}

三、补充

1.hostname和resource的区别

hostname 相当于前面的github.com

resource(资源) 是后面的/wangbojing,

2.fd_set的作用

实际上可能不止一个io,有一个fd_set,如果某个值为1,那么就代表该fd有数据过来了。比如sockfd=5,

并且当前sockfd有数据了,那么fd_set的为5的索引的值为1。如果没有数据则为0。

因此通过select来选择io。


相关文章
|
Rust 前端开发 API
Tauri 开发实践 — Tauri HTTP 请求开发
本文介绍了如何在 Tauri 中发起 HTTP 请求。首先通过安装 Tauri 生态中的工具包并配置 `tauri.conf.json` 文件来允许特定域名的 HTTP 通信。接着封装了一个简单的 HTTP 客户端类,并在页面中使用该客户端实现 GET 和 POST 请求。最后提供了完整的源码地址以供参考。此功能使得桌面应用能够与远程服务器进行交互,增强了应用的实用性。
1544 1
Tauri 开发实践 — Tauri HTTP 请求开发
|
JSON 中间件 Go
Go 网络编程:HTTP服务与客户端开发
Go 语言的 `net/http` 包功能强大,可快速构建高并发 HTTP 服务。本文从创建简单 HTTP 服务入手,逐步讲解请求与响应对象、URL 参数处理、自定义路由、JSON 接口、静态文件服务、中间件编写及 HTTPS 配置等内容。通过示例代码展示如何使用 `http.HandleFunc`、`http.ServeMux`、`http.Client` 等工具实现常见功能,帮助开发者掌握构建高效 Web 应用的核心技能。
646 61
|
Linux C语言 iOS开发
C语言结合AWTK开发HTTP接口访问界面
这样,我们就实现了在C语言中使用libcurl和AWTK来访问HTTP接口并在界面上显示结果。这只是一个基础的示例,你可以根据需要添加更多的功能和优化。例如,你可以添加错误处理机制、支持更多HTTP方法(如POST、PUT等)、优化用户界面等。
791 82
|
C# 图形学 开发者
Unity开发中使用UnityWebRequest从HTTP服务器下载资源。
总之,UnityWebRequest就是游戏开发者手中的万能钓鱼竿,既可以获取文本数据,也能钓上图片资源,甚至是那声音的涟漪。使用UnityWebRequest的时候,你需要精心准备,比如确定URL、配置请求类型和头信息;发起请求;巧妙处理钓获的数据;还需要机智面对网络波澜,处理各种可能出现的错误。按照这样的过程,数据的钓取将会是一次既轻松愉快也效率高效的编程钓鱼之旅。
829 18
|
安全 网络协议 Linux
Linux网络应用层协议展示:HTTP与HTTPS
此外,必须注意,从HTTP迁移到HTTPS是一项重要且必要的任务,因为这不仅关乎用户信息的安全,也有利于你的网站评级和粉丝的信心。在网络世界中,信息的安全就是一切,选择HTTPS,让您的网站更加安全,使您的用户满意,也使您感到满意。
480 19
|
XML JSON Linux
Reqable:跨平台HTTP开发与调试工具
Reqable是一款功能强大且易于使用的跨平台HTTP开发与调试工具,具有多平台支持、全面的HTTP请求构建与解析、请求历史记录和环境管理等功能。它简化了HTTP请求的构建、发送和响应分析过程,为开发者提供了极大的便利。通过Reqable,开发者可以更高效地进行HTTP开发和调试,提高工作效率和代码质量。
1431 26
|
人工智能 网络协议 API
开发效率翻倍!Apipost这些协议调试秘籍,从HTTP到金融报文全搞定
Apipost是一款强大的API研发管理工具,支持多种协议与数据格式,包括HTTP(s)、WebSocket、SSE、gRPC、TCP及金融协议(如ISO 8583、FIX)。它内置国密算法库,提供HTTP文件秒传、全局参数配置等实用功能。在SSE调试中,可轻松处理AI模型流式响应;WebSocket与Socket.IO实现高效实时通信;GraphQL支持可视化Query编写;TCP模块解决金融报文编码难题;gRPC则具备服务反射与流式调试能力。Apipost不仅简化了多协议切换的复杂性,还自动生成文档,显著提升开发效率,让开发者专注于核心业务逻辑。
|
缓存 安全 数据处理
Objective-C开发:从HTTP请求到文件存储的实战
Objective-C开发:从HTTP请求到文件存储的实战
|
Web App开发 Linux 应用服务中间件
【DrissionPage】Linux上如何将https改为http
通过上述步骤,可以在Linux上将DrissionPage从HTTPS改为HTTP。关键在于修改DrissionPage配置、代码中的HTTPS设置、URL以及Web服务器配置,确保所有部分都正确使用HTTP协议。通过合理配置和测试,能够确保系统在HTTP环境下稳定运行。
782 1