c++ 一个简单的请求程序

news2024/11/24 20:37:09

https://github.com/AHUT-GeekTeam/ESP32CAM_BaiduAI/blob/master/demo.ino

在这里插入图片描述

HTTP格式

  • 请求行 回车+换行
  • 请求头 回车+换行
  • 请求头 回车+换行
  • 请求头 回车+换行
  • ……
  • 请求头 回车+换行 回车+换行
  • 数据

jichu daima

在这里插入图片描述

  • 参考黑马程序员的代码
  • MAIN.C
#include "b.h"
//#include <pthread.h>

int main(void) {

    int sock;
    struct sockaddr_in server_addr;
    sock = socket(AF_INET, SOCK_STREAM, 0);
    bzero(&server_addr, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    server_addr.sin_port = htons(SERVER_PORT);
    bind(sock, (struct sockaddr*)&server_addr, sizeof(server_addr));
    listen(sock, 128);
    printf("Wait conecting......\n");
    int done = 1;

    while (done) {
        struct sockaddr_in client;
        int client_socket;
        int len;
        char client_ip[64];
        char buf[256];




        socklen_t client_addr_len;
        client_addr_len = sizeof(client);
        client_socket = accept(sock, (struct sockaddr*)&client, &client_addr_len);
        printf("client address:%s\tport:%d\n", inet_ntop(AF_INET, &client.sin_addr.s_addr, client_ip, sizeof(client_ip)), ntohs(client.sin_port));

        //处理Http请求,读取客户端发来的数据
        do_http_request(client_socket);
        close(client_socket);

        //启动线程,处理HTTP请求

//        pthread_t id;//存储线程id//todo
//        int* pclient_sock = NULL;//todo   origian code use pthread ,so paramters is void*  ,use pointer so new and free

//        pclient_sock = (int*)malloc(sizeof(int));//todo
//        *pclient_sock = client_socket;//todo
//        pthread_create(&id,NULL,do_http_request,(void*)pclient_sock);//todo
      //done =0;
    }

    close(sock);

    return 0;
}

//#include <iostream>
//
//int main() {
//    std::cout << "Hello, World!" << std::endl;
//    return 0;
//}

  • B.H
//
// Created by m_kali on 2023/1/18.
//

#ifndef UNTITLED_B_H
#define UNTITLED_B_H

#include <stdio.h>
#include <stdlib.h> ///home/test/Dev/square/src/main.c:39:24: note: include ‘<stdlib.h>’ or provide a declaration of ‘malloc’
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <ctype.h>
#include <arpa/inet.h>
#include <errno.h>
#include <sys/stat.h>


#define SERVER_PORT 5001 //端口

static int debug = 1;


//处理请求的每行数据
//返回值:-1读取出错,=0表示读到空行,>0表示成功读取。
int get_line(int sock, char* buf, int size);

//读取客户端发来的http请求
void* do_http_request(int client_sock);

//根据请求返回内容
void do_http_response(int client_sock, const char* path);

//响应404
void not_found(int client_sock);

//返回请求头
int headers(int client_sock,FILE* resource);

//发送html文件中的内容
void cat(int client_sock,FILE* resource);

//服务器内部错误500
void iner_error(int client_sock);

//响应未定义的请求
void unimplemented(int client_sock);


#endif //UNTITLED_B_H

  • B.C
//
// Created by m_kali on 2023/1/18.
//

#include "b.h"

// #include "minihttp.h"

int get_line(int sock, char* buf, int size) {

    int count = 0;
    char ch = '\0';
    int len = 0;

    while ((count < size - 1) && ch != '\n') {
        len = read(sock,&ch,1);

        if (len == 1) {
            if (ch == '\r') {
                continue;
            } else if (ch == '\n') {

                break;//读取完毕
            }

            //这里处理一般的字符
            buf[count] = ch;
            count++;
        } else if(len == -1){//读取出错
            perror("read failed!");
            count = -1;
            break;
        } else {//返回0——客户端关闭socket链接
            fprintf(stderr,"clinet close\n");
            count = -1;
            break;
        }
    }
    if (count >= 0) {
        buf[count] = '\0';//添加字符串结束符
    }

    return count;
}


void* do_http_request(int pclient_sock){

    int len = 0;
    char buf[256];
    char method[64];
    char url[256];
    char path[256];

    int client_sock = pclient_sock;// *(int*)pclient_sock;  //todo

    struct  stat st;
    //读取请求行

    len = get_line(client_sock, buf, sizeof(buf));

    if (len > 0) {//读到了请求行数(第一行)
        int i = 0;
        int j = 0;

        while (!isspace(buf[j]) && i <sizeof(method)-1) {
            method[i] = buf[j];
            i++;
            j++;
        }

        method[i] = '\0';
        printf("request method:%s\n",method);


        if (strncasecmp(method, "GET", i) == 0) {//只处理get请求
            if (debug) {
                printf("method = GET\n");
            }

            //获取url
            while (isspace(buf[j++])) {//跳过空格
                i = 0;
            }

            while (!isspace(buf[j]) && i < sizeof(url) - 1) {
                url[i] = buf[j];
                i++;
                j++;
            }

            url[i] = '\0';

            if (debug) {
                printf("url:%s\n", url);
            }
            //继续读取http头部
            do
            {
                len = get_line(client_sock, buf, sizeof(buf));
                if(debug){
                    printf("read:%s\n",buf);
                }
            } while (len>0);

            //定位服务器本地的html文件


            //处理url中的?,过滤掉?后面的内容
            {
                char* pos = strchr(url, '?');
                if (pos) {
                    *pos = '\0';
                    printf("real url:%s\n",url);
                }
            }

            sprintf(path,"./html_docs/%s",url);

            if (debug) {
                printf("path:%s\n", path);
            }

            //get请求服务端回复
            //判断文件是否存在,如果存在就相应200 OK,同时发送相应的html文件
            //如果不存在就相应404 not found

            if (stat(path, &st) == -1) {//文件不存在或者出错
                fprintf(stderr,"stat %s failed,reason:%s\n",path,strerror(errno));
                not_found(client_sock);
            } else {//文件存在

                if (S_ISDIR(st.st_mode)) {//如果是目录,添加默认网页
                    strcat(path,"/index.html");
                }


                do_http_response(client_sock,path);
            }


        } else {//非get请求,读取http头部,并相应客户端501
            fprintf(stderr,"warning! other rquest [%s]\n",method);
            do
            {
                len = get_line(client_sock, buf, sizeof(buf));
            } while (len>0);

            unimplemented(client_sock);
        }
    } else {//请求格式有问题,出错处理。

        not_found(client_sock);
    }
//free sources come with the thread
 //   close(client_sock);//todo
//    if (pclient_sock) { //todo
//        free(pclient_sock);// origian code use pthread ,so paramters is void*  ,use pointer so new and free
//    }

    return NULL;// origian code use pthread ,so paramters is void*
}


void do_http_response(int client_sock, const char* path) {

    int ret = 0;

    FILE *resource = NULL;

    resource = fopen(path,"r");

    if (resource == NULL) {
        not_found(client_sock);
        return;
    }


    //发送http头部
    ret = headers(client_sock, resource);

    if (!ret) {
        //成功发送头部后
        //发送http body
        cat(client_sock, resource);
    }

    fclose(resource);
}

void not_found(int client_sock){
    const char* reply = "HTTP/1.0 404 NOT FOUND\r\n\
		Content - Type: text / html\r\n\
		\r\n\
		<HTML>\r\n\
		<HEAD>\r\n\
		<TITLE>NOT FOUND</TITLE>\r\n\
		</HEAD>\r\n\
		<BODY>\r\n\
		<P>The server could not fulfill your request because the resource specified is unavailable or nonexistent.\r\n\
		</BODY>\r\n\
		</HTML>\r\n";

    int len = write(client_sock,reply,strlen(reply));

    if (len <= 0) {
        fprintf(stderr,"send reply failed,reason:%s\n",strerror(errno));
    }

    //if (debug) {
    //	fprintf(stdout,reply);
    //}
}

int headers(int client_sock, FILE* resource) {

    struct stat st;

    int fileid = 0;

    char tmp[128];

    char buf[1024] = { 0 };

    strcpy(buf, "HTTP/1.0 200 OK\r\n");
    strcat(buf, "Server: XUANXUAN Server\r\n");
    strcat(buf, "Content-Type:text/html\r\n");
    strcat(buf, "Connection: Close\r\n");

    fileid = fileno(resource);						//拿到文件fd——文件描述符

    if (fstat(fileid, &st) == -1) {
        iner_error(client_sock);
        return -1;//失败
    }

    sprintf(tmp, "Content-Length:%ld\r\n\r\n", st.st_size);
    strcat(buf, tmp);

    if (debug) {
        fprintf(stdout, "header:%s\n", buf);
    }

    if (send(client_sock, buf, strlen(buf), 0) < 0) {//如果发送失败
        fprintf(stderr, "send failed.data:%s,reason:%s\n", buf, strerror(errno));
        return -1;
    }

    return 0;
}

void cat(int client_sock, FILE* resource) {

    char buf[1024];
    fgets(buf,sizeof(buf),resource);

    //没有到达文件尾部就一直读
    while (!feof(resource)) {
        int len = write(client_sock, buf, strlen(buf));

        if (len < 0) {//发送body的过程中出现问题
            fprintf(stderr,"send body error. reason:%s\n",strerror(errno));
            break;
        }

        if (debug) {
            fprintf(stdout,"%s",buf);
        }

        fgets(buf, sizeof(buf), resource);
    }

}

void iner_error(int client_sock) {
    const char* reply = "HTTP/1.0 500 Internal Sever Error\r\n\
		Content - Type: text / html\r\n\
		\r\n\
		<HTML>\
		<HEAD>\
		<TITLE>inner_error</TITLE>\
		</HEAD>\
		<BODY>\
		<P>Error prohibited CGI execution.\
		</BODY>\
		</HTML>";

    int len = write(client_sock, reply, strlen(reply));

    if (len <= 0) {
        fprintf(stderr, "send reply failed,reason:%s\n", strerror(errno));
    }

    /*if (debug) {
        fprintf(stdout, reply);
    }*/
}

void unimplemented(int client_sock) {
    const char* reply = "HTTP/1.0 404 NOT FOUND\r\n\
		Content - Type: text / html\r\n\
		\r\n\
		<HTML>\r\n\
		<HEAD>\r\n\
		<TITLE>NO Implemented</TITLE>\r\n\
		</HEAD>\r\n\
		<BODY>\r\n\
		<P>The server could not fulfill your request because the resource specified is unavailable or nonexistent.\r\n\
		</BODY>\r\n\
		</HTML>\r\n";

    int len = write(client_sock, reply, strlen(reply));

    if (len <= 0) {
        fprintf(stderr, "send reply failed,reason:%s\n", strerror(errno));
    }
}

CG

模拟发送 http/https 请求的工具推荐

windows端的实现

  • main 参考 https://cloud.tencent.com/developer/ask/sof/1530492
  • 请求头解析参考https://blog.csdn.net/sinat_16643223/article/details/120113054
  • 零基础入门学习Http协议与post实战开发 基于C/C++语言https://www.bilibili.com/video/BV1K4411C7Cz?
#include <iostream>
#include <WinSock2.h>
#include <WS2tcpip.h>
#include <string>

#pragma comment(lib, "ws2_32.lib")

int main()
{
	std::cout << "--- Tcp/ip Server ---" << std::endl;
	WSADATA wsa;
	WSAStartup(MAKEWORD(2, 2), &wsa);

	SOCKET server = socket(AF_INET, SOCK_STREAM, 0);
	if (server == INVALID_SOCKET)
	{
		std::cout << "error in SOCKET(): " << WSAGetLastError() << std::endl;
		WSACleanup();
	}
	sockaddr_in s;
	s.sin_family = AF_INET;
	s.sin_addr.s_addr = INADDR_ANY;
	s.sin_port = htons(52000);

	// bind
	if (bind(server, (sockaddr*)&s, sizeof(s)) == SOCKET_ERROR)
	{
		std::cout << "Error: bind()" << std::endl;
	}
	//listen
	if (listen(server, SOMAXCONN) == SOCKET_ERROR)
	{
		std::cout << "Error in listen(): " << WSAGetLastError() << std::endl;
		WSACleanup();
	}
	sockaddr_in from;
	int clientlen = sizeof(from);
	// accept
	SOCKET client = accept(server, (SOCKADDR*)&from, &clientlen);
	if (client == INVALID_SOCKET)
	{
		std::cout << "Error in accept(): " << WSAGetLastError << std::endl;
		WSACleanup();
	}
	else
	{

		char clientIp[17];
		if (inet_ntop(AF_INET, &from.sin_addr, clientIp, 17) == NULL)
		{
			std::cout << "Can't get the client's ip: " << WSAGetLastError() << std::endl;
		}

		std::cout << "ip connected: " << clientIp << std::endl;

		// the code isn't finished yet

		system("pause");
		WSACleanup();
	}
	return 0;
}

socket read函数

github上的开源程序

简单教程

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

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

相关文章

威纶通触摸屏复合式多功能按钮的使用方法

威纶通触摸屏复合式多功能按钮的使用方法 如下图所示,打开easy builder pro软件,新建一个测试项目,在元件中找到复合式多功能按钮,点击后放入画面中, 如下图所示,此时会弹出以下窗口,在动作中点击“+”图标,选择自己需要添加的动作, 如下图所示,首先添加一个位状…

C++类与对象—下

本期我们继续学习类与对象&#xff0c;没有看过上和中的小伙伴建议先看前两期内容 (2条消息) C类与对象—上_KLZUQ的博客-CSDN博客 (2条消息) C类与对象—中_KLZUQ的博客-CSDN博客 目录 1.再谈构造函数 1.1构造函数体赋值 1.2初始化列表 1.3 explicit关键字 2. static成员…

学成在线笔记+踩坑(12)——用户认证

导航&#xff1a; 【黑马Java笔记踩坑汇总】JavaSEJavaWebSSMSpringBoot瑞吉外卖SpringCloud黑马旅游谷粒商城学成在线牛客面试题 目录 1 需求分析 2 【认证模块】连接用户中心数据库 2.1 连接数据库认证 2.1.1 分析 2.1.2 实现&#xff0c;实现UserDetailsService接口 …

Golang每日一练(leetDay0064) 轮转数组、颠倒二进制位

目录 189. 轮转数组 Rotate Array &#x1f31f;&#x1f31f; 190. 颠倒二进制位 Reverse Bits &#x1f31f; &#x1f31f; 每日一练刷题专栏 &#x1f31f; Golang每日一练 专栏 Python每日一练 专栏 C/C每日一练 专栏 Java每日一练 专栏 189. 轮转数组 Rotate Ar…

小曾同学【五周年创作纪念日】——努力向前冲的菜鸟

&#x1f604;作者简介&#xff1a; 小曾同学.com,一个致力于测试开发的博主⛽️&#xff0c; 如果文章知识点有错误的地方&#xff0c;还请大家指正&#xff0c;让我们一起学习&#xff0c;一起进步。&#x1f60a; 座右铭&#xff1a;不想当开发的测试&#xff0c;不是一个好…

什么是UA?常见蜘蛛UA?怎么查询UA?

什么是UA? UA简介查看自己的UA修改它的常见用处搜索引擎蜘蛛UA大全常见蜘蛛UA标识 UA简介 UA其实是User Agent的简称。 所谓的User Agent其实就是浏览器在跟服务器通信的时候&#xff0c;一段百十来个字符的落款信息罢了。浏览器发送的每一个HTTP请求数据的头部都加了这个信息…

【C++】红黑树的插入分析及验证

文章目录 1. 红黑树概念2. 红黑树性质3. 结构定义关于默认节点为红/黑色的讨论 4. insert情况1—— uncle节点存在且为红色(g p c左斜形成一条直线)情况2——uncle节点不存在/存在且为黑色(g p c 左斜形成直线 右单旋)uncle节点不存在uncle节点存在并且为黑色 情况3——uncle节…

第7章链接:编译器驱动程序

示例程序由两个源文件组成&#xff0c;main.c 和 swap.c。 main函数初始化一个两元素的整数数组&#xff0c;然后调用swap函数来交换这一对数。 main.c void swap();int buf[2] {1, 2};int main() {swap();return 0; }swap.c extern int buf[];int *bufp0 &buf[0]; i…

【Java】Java中线程安全有哪些实现思路?

文章目录 1、使用 synchronized 关键字2、使用 ReentrantLock 类3、使用 ConcurrentHashMap 类4、使用 Atomic 类5、使用 ThreadLocal 类总结 在 Java 多线程编程中&#xff0c;线程安全是一个非常重要的概念。 线程安全通常指程序在多线程并发执行时&#xff0c;仍然能够保持正…

迄今为止,最强ChatGPT写论文技巧,总共6步,手把手告诉你

目录 第一步&#xff1a;现象确认 第三步&#xff1a;定位优质学术资源 第四步&#xff1a;对比分析 第五步&#xff1a;深挖启示 & 第六步&#xff1a;写论文 代写论文&#xff0c;不知道有多少朋友听说过&#xff0c;这是一门严格来说有点小众&#xff0c;但盈利空间…

常见问题解答:如何有效使用 Facebook 商务管理平台(BM)?

Facebook 商务管理平台&#xff08;BM&#xff09;是一个功能强大的工具&#xff0c;可帮助广告主在 Facebook 平台上管理和优化广告投放。然而&#xff0c;对于初次接触 BM 的用户来说&#xff0c;可能会遇到一些问题和困惑。本文将回答一些常见问题&#xff0c;帮助您更有效地…

如何使用分布式存储系统促进 AI 模型训练

在处理小型数据集和简单算法时&#xff0c;传统的机器学习模型可以存储在独立机器或本地硬盘驱动器上。然而&#xff0c;随着深度学习的发展&#xff0c;团队在处理更大的数据集和更复杂的算法时越来越多地遇到存储瓶颈。 这凸显了分布式存储在人工智能&#xff08;AI&#xf…

半监督学习笔记

聚类假设 假设输入数据点形成簇&#xff0c;每个簇对应于一个输出类&#xff0c;那么如果点在同一个簇中&#xff0c;则它们可以认为属于同一类。聚类假设也可以被视为低密度分离假设&#xff0c;即&#xff1a;给定的决策边界位于低密度地区。两个假设之间的关系很容易看出。一…

C++ 智能指针的原理、分类、使用

1. 智能指针介绍 为解决裸指针可能导致的内存泄漏问题。如&#xff1a; a&#xff09;忘记释放内存&#xff1b; b&#xff09;程序提前退出导致资源释放代码未执行到。 就出现了智能指针&#xff0c;能够做到资源的自动释放。 2. 智能指针的原理和简单实现 2.1 智能指针的原…

讯飞星火 VS 文心一言:谁是中文大语言模型的TOP1?

在百度发布文心一言一个多月后&#xff0c;科大讯飞也发布了自己的大模型“讯飞星火大模型”。本篇博客就测评一下这两个在中文圈最受好评的大语言模型&#xff0c;顺便辅以ChatGPT为参考。大家一起来看看到底谁是中文大语言模型的TOP1&#xff1f; 目录 体验网址 1、旅游攻…

Class类文件的结构

1 class文件介绍 Class文件是一组以8个字节为基础单位的二进制流&#xff1b; 各个数据项目严格按照顺序紧凑地排列在文件之中&#xff0c;中间没有添加任何分隔符; 采用一种类似C语言结构体的伪结构来存储数据&#xff0c;只要两种数据类型&#xff1a;“无符号数”和“表”…

execl函数总结以及扩展

为什么要用exec族函数&#xff0c;有什么作用&#xff1f; (1)一个父进程希望复制自己&#xff0c;使父、子进程同时执行不同的代码段。这在网络服务进程中是常见的一一父进程等待客户端的服务请求。当这种请求到达时&#xff0c;父进程调用fork&#xff0c;使子进程处理此请求…

移动机器人运动规划---基于图搜索的基础知识---图和图搜索算法的基本概念

移动机器人运动规划---基于图搜索的基础知识---图和图搜索算法的基本概念 图和图搜索算法的基本概念图的基础概念图搜索基本概念图搜索算法图搜索算法框架 图和图搜索算法的基本概念 图的基础概念 图是有节点和边的一种表达方式 各节点由边连起来 边可以是有向的&#xff0c;…

Java经典笔试题—day07

Java经典笔试题—day07 &#x1f50e;选择题&#x1f50e;编程题&#x1f95d;Fibonacci数列&#x1f95d;合法括号序列判断 &#x1f50e;结尾 &#x1f50e;选择题 (1)Java属于&#xff08; &#xff09; A.操作系统 B.办公软件 C.数据库系统 D.计算机语言 D (2)类声明中&a…

大数据Doris(十八):Properties配置项和关于ENGINE

文章目录 Properties配置项和关于ENGINE 一、Properties配置项 二、关于ENGINE Properties配置项和关于ENGINE 一、Properties配置项 在创建表时,可以指定properties设置表属性,目前支持以下属性: replica