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上的开源程序

简单教程

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐