手写精简版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,一经查实,立即删除!

相关文章

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…

如何优雅地限制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;下面…

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

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

【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…

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

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

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

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

AV1:帧间预测(一)参考帧管理

​AV1中帧类型 在H.26X系列标准中&#xff0c;根据帧允许的预测模式可以将帧分为I帧、P帧和B帧&#xff0c;根据帧在码流中前后的参考关系又可以分为IRAP、RADL等。AV1也类似地将帧分为4种类型&#xff0c;在码流中用frame_type来标识帧类型。 KEY_FRAME&#xff1a;相当于IDR帧…

HTB Editorial

Editorial User Nmap ┌──(kali㉿kali)-[~/…/machine/SeasonV/linux/Editorial] └─$ nmap -A 10.129.24.67 -T 4 Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-06-16 21:54 EDT Nmap scan report for 10.129.2…

C#使用轻量级深度学习模型进行车牌颜色识别和车牌号识别

看到这个文章时候请注意这个不涉及到车牌检测&#xff0c;这个仅仅是车牌颜色和车牌号识别&#xff0c;如果想涉及到车牌检测可以参考这个博客&#xff1a;[C#]winform部署yolov7CRNN实现车牌颜色识别车牌号检测识别_c# yolo 车牌识别-CSDN博客 【训练源码】 https://github.…

DBeaver windows下载、安装与连接数据库

下载 官网下载地址&#xff1a;https://dbeaver.io/download/ 安装 1、双击安装 2、下一步…… 选择所有用户 3、组件选择 配置连接数据库 下载驱动

【记录44】【案例】echarts地图

效果&#xff1a;直接上效果图 环境&#xff1a;vue、echarts4.1.0 源码 // 创建容器 <template><div id"center"></div> </template>//设置容器大小&#xff0c;#center { width: 100%; height: 60vh; }这里需注意&#xff1a;笔者在echar…

Git的下载安装及可视化工具小乌龟

一、 Git 的下载 第1步&#xff1a;下载Git&#xff0c;下载地址&#xff1a;Git for Windows 这个就需要去 Git 官网下载对应系统的软件了&#xff0c;下载地址为 git-scm.com或者gitforwindows.org&#xff0c;或者阿里镜像&#xff08;感谢评论区的星悸迷航同学&#…

什么是云恶意软件攻击,如何进行有效的防护

一切都在向云转移。云端数据越多&#xff0c;恶意攻击者攻击云平台的兴趣就越大。 攻击者使用恶意软件窃取数据并破坏服务。虽然恶意软件在云端可能不像在个人电脑上那么普遍&#xff0c;但大行其道的云恶意软件令人担忧。此外&#xff0c;组织不像您预料的那样意识到这点。 …

鸿蒙开发网络管理:【@ohos.request (上传下载)】

上传下载 说明&#xff1a; 本模块首批接口从API version 6开始支持。后续版本的新增接口&#xff0c;采用上角标单独标记接口的起始版本。 导入模块 import request from ohos.request;限制与约束 默认支持https&#xff0c;如果要支持http&#xff0c;需要在config.json里…