自主开发的小型Web服务器
自主开发的小型Web服务器
- 1. 技术特点
- 2. 具体步骤
- 3. CGI技术
- 4. Mysql连接
- 5. Gitee原码链接
- 6. 参考Blog
1. 技术特点
- 网络编程(http协议,TCP/IP协议,socket流式套接字)
- 多线程技术(线程池)
- CGI技术
- Mysql
2. 具体步骤
- HttpServer.hpp
- InitServer()
- Start()
- 并且将我们的HttpServer设计为单例模式中的懒汉模式(是一个线程安全的单例模式,既要保证安全所以要加锁,但是还要保证效率所以需要双检测)
- 守护进程(守护进程就是通常讲Daemon进程,是linux后台执行的一种服务进程,特点是独立于控制终端、周期性地执行某种任务或等待处理某些发生事件,不会随终端关闭而停止,直到接受停止信息才会结束,且一般采用以d结尾的名字。)
- Sock.hpp,对于网络接口的分装
- socket()
- bind()
- listen()
- accept()
- 线程池技术进行处理所监听到的sock
- Getline()一个专门从套接字中一次读取一行的接口,因为Http的request都是以行为分隔符来区分请求行、请求报头、空行、正文。
补充知识:但是不同的浏览器可能传过来的分隔符是不相同的,有可能是\r、\r\n、\n三种,对于recv的第四个参数flags可以设置为MSG_PEEK,这相当于一个窥探的功能,也就是从内核上把数据读到,但是并没有拷贝到用户缓冲区中
- Log.hpp
- 【日志级别】【message】【时间戳】【filename】【line】
- 日志级别:Notice、Warning、Error、fatal4个级别,级别属性依次增加
- message:解释
- Protocol.hpp(最重要)
- Entry class 可以进行条件编译的一个类
- HttpRequest class 专门处理接收上来的请求文本
- HttpResponse class 专门处理准备发送的响应文本
- EndPoint class 专门负责通信
- RecvRequest()
- 从socket读取到请求行、请求报头、空行、正文分别设置进HttpRequest class。
- MakeResponse() 分析并且制作响应
从请求行需要得到method、url、version,对于本次的method只考虑POST和GET方法,如果不是这两种方法,则会直接返回响应,且错误码为404,对于url如果是GET方法需要区分是否带参数)(考虑到传过来的方式大小写要忽略的问题可以使用strcasecmp()接口,如果相等就返回0,不相等返回-1)
首先应该得到完整的path,有可能发过来的是一个目录,但是对于任意的一个Web服务器上的目录都有一个默认的index.html(/a/b这个b文件是一个目录,所以首先应该给它拼接上一个/然后再加上index.html),也有可能访问的就是一个普通的html(/a/b/html),还有可能会是访问一个可执行程序(a/b/exe)
补充知识:struct stat {
mode_t st_mode; // file type & mode(permissions)
ino_t st_ino; // i-node number(serial number)
dev_t st_dev; // device number(filesystem)
dev_t st_rdev; // device number for specials files
nlink_t st_nlink; // number of links
uid_t st_uid; // user ID of owner
gid_t st_gid; // group ID of owner
off_t st_size; // size in bytes, for regular files
time_t st_atime; // time of last access
time_t st_mtime; // time of last modification
time_t st_ctime; // time of last file status change
long st_blksize; // best I/O block size
long st_blocks; -//number of 512-byte blocks allocated
};在GET方法url中有参数,POST方法正文有数据,或者是要取访问一个可执行程序的时候就会触发CGI技术。
- SendResponse()
- 因为已经将制作好的状态行、响应报头设置进了HttpResponse class中,所以可以直接调用所提供的接口进行发送状态行和响应报头
- 此时就剩下发送HttpResponse body了,但是需要判断是否CGI模式①GET方法中url有参数②POST方法有正文部分③分析出来的路径最终想要访问的是一个可执行程序。
- 判断完是否是CGI模式以后,执行两个不同的函数ExecCgi()或者ExecNonCgi(),对于执行ExecNonCgi()函数来说,目的就是打开一个文件然后通过socket返回(这里使用了一个sendfile()的系统调用接口,可以直接在内核进行两个文件的交互,不需要在先拷贝到用户再从用户拷贝给内核)
ssize_t sendfile(int out_fd,int in_fd, off_t *offset,size_t count);
在这里面in_fd should be file descriptor opend for reading- 在处理ExecCgi()函数的时候,创建子进程,然后要把父进程的数据传递给子进程,并且想要这里严格的遵守CGI的传参标准,对于GET方法就是环境变量传参,对于POST因为有可能body很长,所以选择使用管道进行传参。环境变量具有全局属性,所以method可以通过putenv()进行设置,创建子进程,对于这个子进程最大的作用就是要去做程序替换,所以真正意义上是WEB服务器在和CGI程序打交道。这里使用到了进程间通信、进程替换、重定向技术。对于子进程分析方法如果是GET,那么就把query_string通过环境变量传递给CGI,但是对于CGI程序来说,在POST方法下,使用管道进行传参,传递给的只是子进程,CGI程序并拿不到数据,所以这里做了一个约定就是CGI程序可以从标准输入中读取,从标准输出中写入,那么这里就要使用到dup2()重定向接口。
- Util.hpp
- 里面有一个Util class 存放个中方法比如StringToInt()等接口,来使用
- ThreadPool.hpp
- 每监听到一个socket,就把该套接字封装成一个Task,然后塞进任务队列中,然后就是唤醒线程去执行特定的函数,检测到任务队列不为空拿出该任务进行Run()。
- wwwroot(web根目录)
- 每一个目录都有一个默认的index.html
- 在W3C上下载了一个静态网页
程序流程解析图
3. CGI技术
CGI(Common Gateway Interface) 是WWW技术中最重要的技术之一,有着不可替代的重要地位。CGI是外部应用程序(CGI程序)与WEB服务器之间的接口标准,是在CGI程序和Web服务器之间传递信息的过程。
浏览器除了从服务器下获得资源(网页,图片,文字等),有时候还有能上传一些东西(提交表单,注册用户之类的),看看我们目前的http只能进行获得资源,并不能够进行上传资源,所以目前http并不具有交互式。为了让我们的网站能够实现交互式,我们需要使用CGI完成,时刻记着,我们目前是要写一个http,所以,CGI的所有交互细节,都需要我们来完成。
在我们实现上,要理解CGI,首先的理解GET方法和POST方法的区别:
- GET方法从浏览器传参数给http服务器时,是需要将参数跟到URI后面的,具体如下:
- POST方法从浏览器传参数给http服务器时,是需要将参数放的请求正文的。
- GET方法,如果没有传参,http按照一般的方式进行,返回资源即可
- GET方法,如果有参数传入,http就需要按照CGI方式处理参数,并将执行结果(期望资源)返回给浏览器
- POST方法,一般都需要使用CGI方式来进行处理
需要使用到创建子进程,然后数据还在父进程上,要传给子进程所以使用进程间通信,在程序替换(进程替换),去帮你执行,然后拿到想要的结果在返回给Web服务器,Web服务器在返回给浏览器的过程。
4. Mysql连接
- 在官网中下载适合自己平台的Mysql connect库(指明include库路径和动态库路径以及要具体链接的动态库中的哪一个库,ldd命令可以查看文件所依赖的动态库,如果还找不到所以要导入一个环境变量export LD_LIBRARY_PATH=/…/…/…)
- 通过mysql_get_client_info()函数,来验证我们的引入是否成功
- Mysql接口介绍
- 初始化mysql_init(),如:MYSQL *mfp = mysql_init(NULL) 生成一个MYSQL的句柄
- 初始化完毕之后,必须先链接数据库,在进行后续操作。
- 下发mysql命令mysql_query()
int mysql_query(MYSQL *mysql, const char *q);
第一个参数上面已经介绍过,第二个参数为要执行的sql语句,如“select * from table”。(增删改相对简单一些,直接封装成sql语句就好,查询反而还更复杂一些) - 获取执行结果mysql_store_result() ,因为你查询出来的结果还保存在sql的缓冲区当中,所以需要一个这个接口能够从Mysql的缓冲区当中把数据读出来,原型:
MYSQL_RES *mysql_store_result(MYSQL *mysql);同时该函数会返回MYSQL_RES 这样一个变量,该变量主要用于保存查询的结果。同时该函数malloc了一片内存空间来存储查询过来的数据,所以我们一定要记的 free(result),不然是肯定会造成内存泄漏的。 执行完mysql_store_result以后,其实数据都已经在MYSQL_RES 变量中了,下面的api基本就是读取MYSQL_RES 中的数据。 - 获取结果行数mysql_num_rows
原型:my_ulonglong mysql_num_rows(MYSQL_RES *res); - 获取结果列数mysql_num_fields
原型:unsigned int mysql_num_fields(MYSQL_RES *res); - 获取列名mysql_fetch_fields
原型:MYSQL_FIELD *mysql_fetch_fields(MYSQL_RES *res); - 获取行结果内容mysql_fetch_row
原型:MYSQL_ROW mysql_fetch_row(MYSQL_RES *result);
- 简单来说使用方式:比如表单形式提交name和passward,那么CGI程序获得http所发过来的query_string(name和passward),然后进行数据库连接,然后把name和passward封装成一条sql语句然后插入。如果是查询是否存在,那么前面步骤一样,只是封装成一个sql以后去查询,如果在那么验证通过,如果不存在那么就给返回一个注册的页面。但是在本次中只是通过url的类似方式直接显示的访问cgi目录下的sql_cgi的可执行程序。
5. Gitee原码链接
Gitee原码链接: https://gitee.com/meanswer/tiny-web-server
主体框架:自主开发的小型WEB服务器,可以获取静态以及交互式网页的请求与返回,服务器主要使用的是http协议和套接字以及多线程加上系统编程所实现。
6. 参考Blog
开源Tinyhttp原码链接: link.
MSG_PEEK详解链接: link.
Linux 中的struct stat结构体详解链接: link.
gettimeofday()函数详解链接: link.
sendfile()函数详解链接: link.
CGI获取POST方法和GET方法传参详解链接: link.
管道链接: link.
单例模式链接: link.
线程池链接: link.
守护进程链接: link.
压测工具(无法确定到底是服务器的上限还是带宽的上限)链接: link.
自主开发的小型Web服务器相关推荐
- 自主小型Web服务器实现——TinyHttp
目录 一.功能 二.技术特点 三.主要框架 四.CGI技术 五.流程 六.具体实现细节 6.1 套接字部分 6.2 线程池部分 6.3 协议处理部分(主要部分) 七.测试结果 一.功能 实现一个自主开 ...
- mysql 花生壳 2003_基于HTTP协议实现的小型web服务器的方法
这篇文章主要介绍了基于HTTP协议实现的小型web服务器的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧 我们先了解一下这个 ...
- 项目--基于http协议的小型web服务器
在我们对网络的学习过程中,会接触到网络编程,我们在网络中可以深刻认识到服务器与客户端的交互,当我们输入网址时背后发生的一系列后端操作,为了加深我们对网络部分的学习,我们找到了一个开源项目TinyWeb ...
- 安卓手机安装php服务器地址,利用Android手机搭建小型Web服务器
使用背景 手头有一个项目的网页需要跨终端展示,考虑到一些数据的保密性,不能放在公网上的虚拟主机上面,所以需要在局域网中搭建一个小型的Web服务器 现在电子设备更新换代的很快,手里有一些闲置的安卓设备使 ...
- Java Web基础入门第八讲 Java Web开发入门——初始WEB服务器
WEB开发的相关知识 WEB,在英语中web即表示网页的意思,它用于表示Internet主机上供外界访问的资源.Internet上供外界访问的Web资源分为: 静态web资源(如html页面):指we ...
- Linux下小型web服务器boa的使用
boa是一个小型的web服务器,可以用于多种平台,在嵌入式中比较常见. boa的官方网站为www.boa.org,可以在上面下载最新版本的boa:boa-0.94.13.tar.gz (不过这个&qu ...
- 迅为IMX6ULL开发板搭建Web服务器(二)
boa 拷贝到开发板的 bin 目录下 接下来在开发板根目录下建立 www 文件夹,如图 80.15. 然后在开发板上面建立的 www 目录下面建立文件夹 cgi-bin 目录,如图 80.16: 然 ...
- arduino 网页服务器,如何将Arduino开发板用作Web服务器
通过使用以太网扩展板(Ethernet shield),您可以将Arduino开发板用作一个Web服务器. 通过向Arduino开发板配备一个以太网扩展板,您可以将其变成简易的Web服务器,并通过在与 ...
- 基于HTTP实现的小型web服务器
主要流程为:服务器获得请求–>响应并处理请求–>返回结果. 完整的HTTP过渡到TCP实现客户端与服务器的交互过程 1.当客户端执行网络请求的时候,从url中解析出url的主机名,并将主机 ...
最新文章
- PYTHON高级全栈开发工程师-老男孩教育
- 查看unlix服务器host文件,php代码优化及php相关问题总结
- 我的第一份vPlan衍变路线
- java中的locksupport_详解Java多线程编程中LockSupport
- Modbus网口设备接入多比物联网云平台教程
- Controller 如果能保持单例,尽量使用单例
- PHP中text里数字相加,excel文字数字如何混合求和
- C语言数组学完学啥,我的c语言学习-数组专题
- PAT L3-007 天梯地图
- 【转】c#数字图像处理(二)彩色图像灰度化,灰度图像二值化
- opencv 图像几何变换
- # 设置当前标注样式_CAD图纸不会标注?模型空间如何标注,标注样式设置规范解析...
- excel文件撤销工作表保护
- 关于jxls2.6.0的学习以及遇到的问题(八)
- Windows 配置 Aria2教程
- 【转载】js 对表格进行各种操作(转)
- HTML超大图片加载显示解决方案--图片切割转换成瓦片地图(BaiduMapTileCutter)
- 图片合成雾的方法概述
- 动态渲染页面的爬取(项目案例:爬取今日头条热点新闻)
- 计算机组装与系统安装实验目的,计算机原理与系统组装实验