手写精简版TinyHttpd项目(一)

前言:

        我们在之前的TinyHttpd的精读(可以在首页去查看)中已经是基本的了解了显示一个网页的基本过程,那么我们学习后可以通过手写一个精简版的进行巩固下。

0.新工程的建立

        我们也可以顺带复习下如何通过cmake在ubuntu下新建一个工程(记得提前下载cmake)。

        1.新建文件夹My_Tinyhttpd。

        2.新建文件:CMakeLists.txt,service_socket.cpp。

        3.CMakeList.txt的内容:

cmake_minimum_required(VERSION 3.0.0)
project("Main")
add_executable(service service_socket.cpp)

          4.service_socket.cpp:

#include <iostream>
int main(){std::cout<<"hello world\n";return 1;
}

        5.执行cmake ./ 和 cmake。

                如果没有报错则成果物会被正常的生成出来为service,然后我们执行 ./service 就可以看到控制台输出hello world了。我们的项目就基本构建完成了。接下来就是具体的内容。

1.main函数:

         在这个main函数中我们的目的是新建一个socket链接,然后创建一个线程去接受信息并进行处理。最后当我们处理完信息后我们就关闭socket链接。具体代码如下:

void accept_request(int client_id){printf("Get Message...\n");
}
int main(){char buffer1[MAXNUM] = {0};int service_id,new_socket;struct sockaddr_in address;socklen_t addlen = sizeof(address);//socklen_t addlen;// service_id = start(address);// int service_id,new_socket;service_id = socket(AF_INET,SOCK_STREAM,0);//创建socketif(service_id == 0){printf("socket failed\n");return service_id;}address.sin_family = AF_INET;address.sin_addr.s_addr = INADDR_ANY;address.sin_port = htons(8008);printf("Bind...\n");//绑定if(bind(service_id, (struct sockaddr *)&address, sizeof(address)) < 0){printf("bind failed\n");printf("Error Message is %s\n",strerror(errno));return -1;}//监听printf("Listen...\n");if(listen(service_id,3) < 0){printf("listen error\n");return -1;}while(1){//接受链接:int new_socket = accept(service_id,(struct sockaddr*)&address,(socklen_t*)&addlen);if(new_socket <0){printf("accept client error\n");}std::thread m_thread(accept_request,new_socket);m_thread.detach();}printf("Close Socket...\n");close(service_id);return 1;
}

        我们按照这个写完代码后,我们执行make然后运行下service(./service).然后打开浏览器输入

http://localhost:8008/.然后看log是否会打印Get Message...。如果可以的话那么基本上我们的这段代码就基本OK了。然后我们把sokcet通信部分的代码封装在start函数中。

void accept_request(int client_id){printf("Get Message...\n");
}int start(struct sockaddr_in& address){int service_id,new_socket;service_id = socket(AF_INET,SOCK_STREAM,0);//创建socketif(service_id == 0){printf("socket failed\n");return service_id;}address.sin_family = AF_INET;address.sin_addr.s_addr = INADDR_ANY;address.sin_port = htons(8008);printf("Bind...\n");//绑定if(bind(service_id, (struct sockaddr *)&address, sizeof(address)) < 0){printf("bind failed\n");printf("Error Message is %s\n",strerror(errno));return -1;}//监听printf("Listen...\n");if(listen(service_id,3) < 0){printf("listen error\n");return -1;}return service_id;
}int main(){char buffer1[MAXNUM] = {0};int service_id,new_socket;struct sockaddr_in address;socklen_t addlen = sizeof(address);//socklen_t addlen;service_id = start(address);while(1){//接受链接:int new_socket = accept(service_id,(struct sockaddr*)&address,(socklen_t*)&addlen);if(new_socket <0){printf("accept client error\n");}std::thread m_thread(accept_request,new_socket);m_thread.detach();}printf("Close Socket...\n");close(service_id);return 1;
}

然后我们同样可以去验证下看看是否会有Get Message...信息。

2.accept_reques函数

        基本的sokcet通讯已经完成了我们接下来进行数据分析/处理函数的部分。这部分函数会涉及到别的函数,我们暂时先聚焦于这个函数的主体思路。

        主体思路:从我们的socket中提出method方法,来判断我们是显示静态网页和动态网页。

        基于以上思路,我们首先来看下我们从socket反馈中能获取到啥信息,这样才方便我们后面写代码的思路。

void print_buffer(char buffer[]){for(int i = 0;i < MAXNUM;i++){if(buffer[i] != '\0')std::cout<<buffer[i];}
}void accept_request(int client_id){char buffer_line[MAXNUM] = {0};char buffer[MAXNUM] = {0};char method[MAXNUM] = {0};char path[MAXNUM] = {0};int i = 0,j = 0;printf("Get Message...\n");auto getmessage = read(client_id,buffer,sizeof(buffer));if(getmessage <= 0){printf("wait client message\n");} else {std::cout<<"client say :";print_buffer(buffer);}
}

        结果如下:

我们发现我们要获取的信息(GET OR POST)是在这个信息的第一行,所以我们第一步得先获取第一行,然后再这行信息中获取GET或者POST方法。

2.1get_line函数:

void get_line(char buffer1[],char buffer2[]){int i = 0;//buffer1 = {0};while(buffer2[i] != '\n'){buffer1[i] = buffer2[i];i++;}buffer1[i] = '\0';
}

        思路:以换行符为行数的确定标记,来将第一行复制出来。

2.2获取method

        当我们获取到第一行后我们就需要考虑当前我们是收到的GET还是POST方法呢?从我们的获取到的buffer信息中可以看到当前网页给的第一次是GET方法。那么从一行字符串中获取到一个子串的方法就不在详细赘述了,直接看代码即可。

void accept_request(int client_id){char buffer_line[MAXNUM] = {0};char buffer[MAXNUM] = {0};char method[MAXNUM] = {0};char path[MAXNUM] = {0};int i = 0,j = 0;printf("Get Message...\n");auto getmessage = read(client_id,buffer,sizeof(buffer));if(getmessage <= 0){printf("wait client message\n");} else {std::cout<<"client say :";print_buffer(buffer);}get_line(buffer_line,buffer);printf("accept_request:");print_buffer(buffer_line);// //get methodwhile(buffer_line[i] != ' '){method[i] = buffer_line[i];i++;}print_buffer(method);
}

2.3判断当前的method方法

        这个就是直接判断是GET还是POST方法,如果是GET方法,我们就显示静态网页,如果是POST我们就显示动态网页。如果两者都不是我们就直接报错。

void accept_request(int client_id){char buffer_line[MAXNUM] = {0};char buffer[MAXNUM] = {0};char method[MAXNUM] = {0};char path[MAXNUM] = {0};int i = 0,j = 0;printf("Get Message...\n");auto getmessage = read(client_id,buffer,sizeof(buffer));if(getmessage <= 0){printf("wait client message\n");} else {std::cout<<"client say :";print_buffer(buffer);}get_line(buffer_line,buffer);printf("accept_request:");print_buffer(buffer_line);//get methodwhile(buffer_line[i] != ' '){method[i] = buffer_line[i];i++;}print_buffer(method);if(strcasecmp(method,"GET") && strcasecmp(method,"POST")){printf("error Method");}if(strcasecmp(method,"GET") == 0){headers(client_id);saver_file(client_id);}
}

至此,一个基本完整的accept_request函数就基本完成了。那么下一章我们就来处理网页的显示。

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

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

相关文章

【前端面经】数组算法题解

目录 题目一&#xff1a;两数之和题目二&#xff1a;最长无重复字符子串题目三&#xff1a;合并两个有序数组题目四&#xff1a;寻找数组中的峰值 题目一&#xff1a;两数之和 描述&#xff1a;给定一个整数数组 nums 和一个目标值 target&#xff0c;请你在该数组中找出和为目…

MyBatis逆向工程和MyBatisX插件的使用

文章目录 1.ORM思维2.逆向工程3.MyBatisX插件的使用 1.ORM思维 ORM&#xff08;Object-Relational Mapping&#xff0c;对象-关系映射&#xff09;是一种将数据库和面向对象编程语言中的对象之间进行转换的技术。它将对象和关系数据库的概念进行映射&#xff0c;最后我们就可以…

MySQL数据库与基本操作(增删改查)

一、数据库的基本概念 数据库要学习的四个基本概念&#xff0c;主要是&#xff1a;数据、数据库系统、数据库、数据管理系统。数据&#xff08;Date&#xff09;是描述事物的记录&#xff0c;数据库系统&#xff08;DBS&#xff09;&#xff0c;数据库管理系统&#xff08;DBMS…

微信小程序,分享和反馈功能

<button type"primary" open-type"share">分享</button> <button type"primary" open-type"feedback">反馈</button>

使用ReentrantLock和ThreadPoolExecutor模拟抢课

这里主要是在场景下帮助理解ReentrantLock和线程池的使用。 import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock;public class GrabCourseTask implements Runnable {private final String studentName;private static int availableS…

如何优雅地限制textarea的输入字数?

大家好&#xff0c;我是瑶山&#xff0c;今天聊聊textarea textarea 有基础的同学都知道<textarea>是HTML中的一个标签&#xff0c;用于定义多行的文本输入控件。它允许用户在表单中输入多行文本&#xff0c;相较于单行输入框可以输入更多的内容。 但是&#xff0c;如果…

【牛客面试必刷TOP101】Day33.BM70 兑换零钱(一)和BM71 最长上升子序列(一)

文章目录 前言一、BM70 兑换零钱(一)题目描述题目解析二、BM71 最长上升子序列(一)题目描述题目解析总结 前言 一、BM70 兑换零钱(一) 题目描述 描述&#xff1a; 给定数组arr&#xff0c;arr中所有的值都为正整数且不重复。每个值代表一种面值的货币&#xff0c;每种面值的货币…

7.华为交换机端口配置链路聚合Eth-trunk

目的&#xff1a;两台华为交换机端口配置链路聚合 LSW1配置 [Huawei]interface Eth-Trunk 1 [Huawei-Eth-Trunk1]q [Huawei]int g0/0/1 [Huawei-GigabitEthernet0/0/1]eth-trunk 1 [Huawei-GigabitEthernet0/0/1]int g0/0/2 [Huawei-GigabitEthernet0/0/2]eth-trunk 1LSW2配置…

计算机网络:运输层 - 概述

计算机网络&#xff1a;运输层 - 概述 运输层的任务端口号复用与分用UDP协议首部格式 TCP协议面向字节流 运输层的任务 物理层、数据链路层以及网络层&#xff0c;他们共同解决了将主机通过网络互联起来所面临的问题&#xff0c;实现了主机到主机的通信。 网络层的作用范围是…

如何使用GPT?初学者的指南

ChatGPT是一个非常先进的AI工具&#xff0c;它使用GPT-4架构&#xff0c;能够生成自然的语言回应。它的多功能性和理解复杂指令的能力&#xff0c;使得很多人用它来回答各种问题&#xff0c;就像用Google一样输入关键词。不过&#xff0c;ChatGPT还能做更多事情&#xff0c;下面…

智能网联汽车安全问题

随着数字技术及智能网联汽车产业的迅猛发展&#xff0c;智能网联汽车作为未来交通系统的重要组成部分&#xff0c;其网络安全性和可靠性问题日益凸显&#xff0c;与人们的生命财产安全息息相关。因此&#xff0c;深度分析智能网联汽车面临的网络安全风险&#xff0c;全面开展数…

ArcGIS arcpy代码工具——关于工具使用的软件环境说明

系列文章目录 ArcGIS arcpy代码工具——批量对MXD文件的页面布局设置修改 ArcGIS arcpy代码工具——数据驱动工具批量导出MXD文档并同步导出图片 ArcGIS arcpy代码工具——将要素属性表字段及要素截图插入word模板 ArcGIS arcpy代码工具——定制属性表字段输出表格 ArcGIS arc…

Linux中的进程控制

Linux中的进程控制 &#xff08;1&#xff09;C程序示例&#xff0c;使用fork()创建一个子进程&#xff1a; #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/wait.h> int main() { pid_t pid; int status; in…

【Redis】java客户端(SpringData和jedis)

https://www.oz6.cn/articles/58 https://www.bilibili.com/video/BV1cr4y1671t/?p16 redis官网客户端介绍&#xff1a;https://redis.io/docs/latest/develop/connect/clients/ jedis maven引入依赖 <dependencies><!--引入Jedis依赖--><dependency><…

cms XAMPP搭建帝国cms示例(用于代码审计)

网上大部分都是小皮因为是一键很省事&#xff0c;但本人一直用的xampp所以若有人也是用xampp搭建可以看此篇文章 这里示例为 帝国CMS -v7.5 xampp搭建过程中如果本机存在mysql服务则需要先将mysql服务停止在start xampp的mysql服务 任务管理器----->服务----->找到mys…

React Hooks深度解析:`useEffect`模拟生命周期

React Hooks深度解析&#xff1a;useEffect模拟生命周期 大家好&#xff0c;我是极客前端探索者&#xff0c;今天我们将一起深入探讨React中的useEffect Hook&#xff0c;以及如何利用它来模拟类组件的componentDidMount和componentDidUpdate生命周期方法。如果你对React Hook…

揭秘网络盗版游戏产业链,守护游戏安全 | 天堂1私服非法牟利,涉嫌洗黑钱!

近年来&#xff0c;网络盗版游戏现象日益猖獗&#xff0c;尤其是天堂1私服。这些盗版游戏不仅非法牟利&#xff0c;还存在偷税漏税、诱导消费等违法行为。本文将揭示这一产业链的真相&#xff0c;提醒广大游戏玩家保持警惕&#xff0c;并向相关部门举报&#xff0c;共同维护互联…

Vue3源码【三】—— createApp执行流程源码分析

使用 在vue3当中是通过createApp将页面给挂在到index.html文件根元素下。下面是一个使用的例子&#xff0c;那么他是怎么运行的呢&#xff1f;又是怎么做的一个链式调用呢&#xff1f;下面就来一一分析 createApp(App) // APP是一个vue组件.use(ElementPlus, { // 注册El-pl…

从0开始开发一个简单web界面的学习笔记(HTML类)

文章目录 什么是HTML页面vscode 开放工具搭建第一个HTML页面编写vscode 如何快速生成代码框架html标签——注释、标题、段落、换行标签格式化标签img 标签(src 属性01)img 属性02(alt、title、width/height、border)a标签href属性a标签target属性表格标签01 基本属性表格标签02…

【JAVA入门】Day08 - 静态变量

【JAVA入门】Day08 - 静态变量 文章目录 【JAVA入门】Day08 - 静态变量【补充】工具类 静态是面向对象中的一个概念&#xff0c;用英文标识符表示是 static。 在一个标准 JavaBean 类中&#xff0c;static 类型的变量和方法经常被使用。 public class Student {//属性…