使用C++从零开始,自己写一个MiniWeb

第一步:新建项目

1、打开VS点击创建新项目

2、选择空项目并点下一步(切记不能选错项目类型)

3、填写项目名称和路径,点击创建即可

 

新建好后项目是这样的比较干净 

4、右击源文件,点击添加,新建http.cpp文件

第二步:前期准备

在http.cpp最上面引入依赖,并撰写main方法,打印错误日志的方法

#include<stdio.h>
#include<string.h>
#include<WinSock2.h>
#include<sys/types.h>
#include<sys/stat.h>
#pragma comment(lib,"WS2_32.lib")
#define PRINTF(str) printf("[%s - %d]"#str"%s",__func__,__LINE__,str);//打印错误日志
void error_die(const char* str) {perror(str);exit(1);}int main(void) {return 0;
}

第三步:网络初始化

初始化可以分为五步:1、网络通讯初始化===>>>2、创建套接字===>>>3、绑定端口===>>>4、绑定套接字===>>>5、创建监听队列

代码实现如下:

int startup(unsigned short *port) {//1、网络通讯初始化WSADATA data;int res = WSAStartup(MAKEWORD(1,1), &data);if (res) {error_die("init fail");}//2、创建套接字int server_socket = socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);if (server_socket == -1) {error_die("sock create fail");}//3、绑定端口int opt = 1;res = setsockopt(server_socket,SOL_SOCKET,SO_REUSEADDR,(const char*) & opt, sizeof(opt));if (res) {error_die("port bing fail");}//4、绑定套接字struct sockaddr_in server_addr;memset(&server_addr,0,sizeof(server_addr));server_addr.sin_family = AF_INET;server_addr.sin_port = htons(*port);server_addr.sin_addr.s_addr = htonl(INADDR_ANY);res = bind(server_socket,(struct sockaddr*) &server_addr, sizeof(server_addr));if (res<0) {error_die("sock bing fail");}//5、创建监听队列int nameLen = sizeof(server_addr);if (*port == 0) {res = getsockname(server_socket, (struct sockaddr*)&server_addr,&nameLen);if (res) {error_die("dynamic sock create fail");}*port = server_addr.sin_port;}res = listen(server_socket, 5);if (res < 0) {error_die("listen queque create fail");}return server_socket;};

main方法修改如下:

int main(void) {//1、初始化unsigned short port = 8000;int server_sock = startup(&port);printf("http have benn started ,listening [%d] port...",port);return 0;
}

第四步:处理用户请求

1、报文背景知识

浏览器发起新的访问时,会向服务器端发送一个请求报文。例如,在浏览器地址输入 127.0.0.1:8000 回车后,服务器端收到的完整报文如下:

GET / HTTP/1.1\n
Host: 127.0.0.1:8000\n
Connection: keep-alive\n
Cache-Control: max-age=0\n
Upgrade-Insecure-Requests: 1\n
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36\n
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9\n
Sec-Fetch-Site: none\n
Sec-Fetch-Mode: navigate\n
Sec-Fetch-User: ?1\n
Sec-Fetch-Dest: document\n
Accept-Encoding: gzip, deflate, br\n
Accept-Language: zh-CN,zh;q=0.9\n
\n

请求报文由4四个部分组成:请求行、请求头部行、空行、请求数据。具体格式如下:

2、具体处理

具体处理代码如下:

//从指定的客户端套接字读取一行数据,保持到buff中,返回实际读取到了字节数
int get_line(int sock, char* buff, int size) {char c = 0;int i = 0;while (i < size - 1 && c != '\n') {int n = recv(sock, &c, 1, 0);if (n > 0) {if (c == '\r') {n = recv(sock, &c, 1, MSG_PEEK);if (n > 0 && c == '\n') {recv(sock, &c, 1, 0);}else {c = '\n';}}buff[i++] = c;}else {c = '\n';}}buff[i] = 0;return 0;
}//向指定套接字,发送一个未支持提示还没有实现的错误页面
void unimplement(int client) {char buf[1024];sprintf(buf, "HTTP/1.0 501 Method Not Implemented\r\n");send(client, buf, strlen(buf), 0);sprintf(buf, SERVER_STRING);send(client, buf, strlen(buf), 0);sprintf(buf, "Content-Type: text/html\r\n");send(client, buf, strlen(buf), 0);sprintf(buf, "\r\n");send(client, buf, strlen(buf), 0);sprintf(buf, "<HTML><HEAD><TITLE>Method Not Implemented\r\n");send(client, buf, strlen(buf), 0);sprintf(buf, "</TITLE></HEAD>\r\n");send(client, buf, strlen(buf), 0);sprintf(buf, "<BODY><P>HTTP request method not supported.\r\n");send(client, buf, strlen(buf), 0);sprintf(buf, "</BODY></HTML>\r\n");send(client, buf, strlen(buf), 0);}//向指定套接字,发送一个未支持提示还没有实现的错误页面
void not_found(int client) {char buf[1024];sprintf(buf, "HTTP/1.0 404 NOT FOUND\r\n");send(client, buf, strlen(buf), 0);sprintf(buf, SERVER_STRING);send(client, buf, strlen(buf), 0);sprintf(buf, "Content-Type: text/html\r\n");send(client, buf, strlen(buf), 0);sprintf(buf, "\r\n");send(client, buf, strlen(buf), 0);sprintf(buf, "<HTML><TITLE>Not Found</TITLE>\r\n");send(client, buf, strlen(buf), 0);sprintf(buf, "<BODY><P>The server could not fulfill\r\n");send(client, buf, strlen(buf), 0);sprintf(buf, "your request because the resource specified\r\n");send(client, buf, strlen(buf), 0);sprintf(buf, "is unavailable or nonexistent.\r\n");send(client, buf, strlen(buf), 0);sprintf(buf, "</BODY></HTML>\r\n");send(client, buf, strlen(buf), 0);}//发送响应的头信息
void headers(int client) {char buff[1024];strcpy(buff, "HTTP/1.0 200 OK\r\n");send(client, buff, strlen(buff), 0);strcpy(buff, "Server:MyHttpd/0.1\r\n");send(client, buff, strlen(buff), 0);strcpy(buff, "Content-type:text/html\n");send(client, buff, strlen(buff), 0);strcpy(buff, "\r\n");send(client, buff, strlen(buff), 0);}//发送文件
void cat(int client,FILE* resource) {char buff[4096];int count = 0;while (1) {int ret = fread(buff, sizeof(char), sizeof(buff), resource);if (ret <= 0) {break;}send(client, buff, ret, 0);count += ret;}printf("total send [%d] to client\n",count);
}void server_file(int client,const char* fileName) {char numchars = 1;char buff[1024];while (numchars > 0 && strcmp(buff, "/n")) {numchars = get_line(client, buff, sizeof(buff));PRINTF(buff);}FILE*  resource = fopen(fileName,"r");if (resource==NULL) {not_found(client);}else {//发送头信息headers(client);//发送文件cat(client, resource);printf("file send success");}fclose(resource);}DWORD WINAPI accept_request(LPVOID arg) {char buff[1024];int client = (SOCKET)arg;//1、获取第一行int numchars = get_line(client, buff,sizeof(buff));PRINTF(buff);char method[255];int j = 0 ,i =0;while (!isspace(buff[j])&&i < sizeof(method)-1) {method[i++] = buff[j++];}method[i] = 0;PRINTF(method);//2、检查请求方法是否支持if (stricmp(method,"GET")&& stricmp(method, "POST")) {//向浏览器返回错误提示页面unimplement(client);return 0;}//3、解析资源路径char url[255];i = 0;while (isspace(buff[j]) && j < sizeof(buff)) {j++;}while (!isspace(buff[j])&& sizeof(url)-1 && j < sizeof(buff)) {url[i++] = buff[j++];}url[i] = 0;PRINTF(url);char path[512] = "";sprintf(path, "htdocs%s", url);if (path[strlen(path)-1]=='/') {strcat(path, "index.html");}PRINTF(path);struct stat status ;if (stat(path,&status)==-1) {//把请求包里的东西读完while (numchars>0&&strcmp(buff,"/n")) {numchars = get_line(client, buff, sizeof(buff));}PRINTF(buff);not_found(client);}else {if ((status.st_mode & S_IFMT)==S_IFDIR) {strcat(path, "index.html");}server_file(client,path);}closesocket(client);return 0;
}

github地址:

https://github.com/1756336885/miniWeb.git

gitee地址:

miniWeb: 迷你版的web,用C++撰写,后期会添加数据库,中间件相关的操作

参考文章:

2-创建项目_哔哩哔哩_bilibili

C语言手写HTTPD网站服务器_126775241csdn-CSDN博客

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

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

相关文章

最简单的基于 FFmpeg 的视频编码器(YUV 编码为 H.264)

最简单的基于 FFmpeg 的视频编码器&#xff08;YUV 编码为 H.264&#xff09; 最简单的基于 FFmpeg 的视频编码器&#xff08;YUV 编码为 H.264&#xff09;正文结果工程文件下载 最简单的基于 FFmpeg 的视频编码器&#xff08;YUV 编码为 H.264&#xff09; 参考雷霄骅博士的…

[leetcode经典算法题]删除有序数组中的重复项(双指针)

删除有序数组中的重复项 给你一个 非严格递增排列 的数组 nums &#xff0c;请你 原地 删除重复出现的元素&#xff0c;使每个元素 只出现一次 &#xff0c;返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。然后返回 nums 中唯一元素的个数。 考虑 nums 的唯一元素…

Nginx+React在Docker中实现项目部署

一、引言 Nginx 是一个高性能的 HTTP 和反向代理服务器&#xff0c;也能够处理 IMAP/POP3/SMTP 服务&#xff0c;由 Igor Sysoev 开发并在 2004 年首次公开发布。它以处理静态内容、提供反向代理服务以及其高稳定性、低资源消耗而广受欢迎。Nginx 能够通过非阻塞方式处理多个连…

第78讲 修改密码

系统管理实现 修改密码实现 前端 modifyPassword.vue&#xff1a; <template><el-card><el-formref"formRef":model"form":rules"rules"label-width"150px"><el-form-item label"用户名&#xff1a;&quo…

《CSS 简易速速上手小册》第2章:CSS 布局与定位(2024 最新版)

文章目录 2.1 Flexbox&#xff1a;灵活的布局解决方案2.1.1 基础知识2.1.2 重点案例&#xff1a;创建一个响应式导航菜单2.1.3 拓展案例 1&#xff1a;卡片布局2.1.4 拓展案例 2&#xff1a;中心对齐的登录表单 2.2 Grid 布局&#xff1a;网格系统的魔力2.2.1 基础知识2.2.2 重…

C语言求解猴子分桃子

问题&#xff1a;海滩上有一堆桃子&#xff0c;五只猴子来分。第一只猴子把这堆桃子平均分为五份&#xff0c;多了一个&#xff0c;这只 猴子把多的一个扔入海中&#xff0c;拿走了一份。第二只猴子把剩下的桃子又平均分成五份&#xff0c;又多了 一个&#xff0c;它同样把多的…

english_syntax

文章目录 什么是英语的句子&#xff1f;英语句子的结构句子的成分&#xff08;词性问题&#xff09;谓语系动词主语宾语表语 并列句从句引导词名词性从句形容词性从句&#xff08;定语从句&#xff09;副词性从句&#xff08;状语从句&#xff09; 特殊结构强调句型倒装句型虚拟…

C#log4net日志保存到Sqlserver数据库表(16)

要将log4net的日志保存到SQL Server数据库表中&#xff0c;你需要配置log4net使用一个数据库追加器&#xff08;appender&#xff09;&#xff0c;通常是AdoNetAppender。以下是一个示例配置&#xff0c;展示如何将log4net的日志输出配置为写入SQL Server数据库表。 首先&…

9.手写bind

bind 函数的实现步骤&#xff1a; 判断调用对象是否为函数&#xff0c;即使我们是定义在函数的原型上的&#xff0c;但是可能出现使用 call 等方式调用的情况。保存当前函数的引用&#xff0c;获取其余传入参数值。创建一个函数返回函数内部使用 apply 来绑定函数调用&#xf…

在CE和MSE损失函数中使用置信度的方法

以下是在一个半监督情景中 weak_output_ul为弱扰动出来的logits ,strong_output_ul为强扰动出来的logits 两者尺寸都可看作[8,2,256,256] CE: weak_x_ul self.encoder(A_ul, B_ul) weak_output_ul self.main_decoder(weak_x_ul) weak_targets …

PostgreSQL导出导入

导出常用方法 pg_dumpall&#xff1a;适合导出cluster中所有业务库 pg_dump&#xff1a;适合单个库、schema级、表级导出 copy&#xff1a;适合单表或带条件sql结果导出&#xff08;可导出为csv或txt格式&#xff09; 一、 pg_dumpall pg_dumpall可以转储cluster里的所有数…

C#面:Sleep() 和 Wait() 有什么区别

Sleep() 和 Wait() 是两个不同的方法&#xff0c;用于控制线程的执行。 Sleep() 方法&#xff1a; 是线程类 Thread 的静态方法&#xff0c;它使当前线程暂停执行一段时间。 Sleep() 方法接受一个参数&#xff0c;表示线程暂停的时间长度&#xff0c;单位是毫秒。 在暂停期…

C++ 11新特性之语法甜点4

概述 C 11中引入了许多简化编程工作的语法上的新特性&#xff0c;我们暂且美其名曰&#xff1a;“语法甜点”。书接上篇&#xff0c;我们继续介绍C 11中的这些“语法甜点”&#xff0c;也是最后一篇关于“语法甜点”的文章。 语法甜点16&#xff1a;新的字符串字面值 C 03提供了…

VitePress-13- 配置-title的作用详解

作用描述 1、title 是当前站点的标题&#xff1b;2、默认值是 &#xff1a;VitePress&#xff1b;3、当使用默认主题时&#xff0c;会直接展示在 页面的【导航条】中&#xff1b;4、一个特殊的作用 &#xff1a; 会作为单个页面的默认标题后缀&#xff01;除非又指定了【title…

WSL下如何使用Ubuntu本地部署Vits2.3-Extra-v2:中文特化修复版(新手从0开始部署教程)

环境&#xff1a; 硬&#xff1a; 台式电脑 1.cpu:I5 11代以上 2.内存16G以上 3.硬盘固态500G以上 4.显卡N卡8G显存以上 20系2070以上 本案例英伟达4070 12G 5.网络可连github 软&#xff1a; Win10 专业版 19045以上 WSL2 -Ubuntu22.04 1.bert-Vits2.3 Extra-v2:…

CSP-201912-1-报数

CSP-201912-1-报数 知识点总结 整数转化为字符串#include <string> string str_num to_string(num);字符串中查找是否包含字符‘7’&#xff1a;str_num.find(7) 未找到返回-1找到返回返回该字符在字符串中的位置&#xff08;即第一次出现的索引位置&#xff09; #i…

腾讯云4核8G服务器够用吗?容纳多少人同时访问?

腾讯云4核8G服务器支持多少人在线访问&#xff1f;支持25人同时访问。实际上程序效率不同支持人数在线人数不同&#xff0c;公网带宽也是影响4核8G服务器并发数的一大因素&#xff0c;假设公网带宽太小&#xff0c;流量直接卡在入口&#xff0c;4核8G配置的CPU内存也会造成计算…

java nio零拷贝

零拷贝是一种计算机执行IO操作的优化技术&#xff0c;其核心目标是减少数据拷贝次数&#xff0c;从而提高系统性能。它主要体现在以下几个方面&#xff1a; 1. **定义与原理**&#xff1a;零拷贝字面上的意思包括“零”和“拷贝”。其中&#xff0c;“拷贝”是指数据从一个存储…

西工大计算机学院复试问题整理

1. DMA DMA是一种无须CPU参与就可以让外设与系统内存之间进行双向数据传输的硬件机制1&#xff0c;而中断是指CPU在执行程序的过程中&#xff0c;出现了某些突发事件时必须暂停执行当前的程序&#xff0c;转去处理突发事件1。两者的主要区别是&#xff1a; 中断方式是在每个数据…

读千脑智能笔记11_保存人类遗产

1. 智能生物通常能延续多久 1.1. SETI和METI计划的可行性在很大程度上取决于智能生物通常能延续多久 1.1.1. 搜寻地外文明&#xff08;以下简称SETI&#xff09;计划的目标 1.1.1.1. 这是一个力图寻找宇宙其他地方智能生物存在证据的研究项目 1.1.1.2. SETI计划旨在寻找含有…