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;
}