当前位置: 首页 > news >正文

如何用C语言写一个web服务器的基础功能

我们都知道,学一门语言,只是单独看了就不写的话是很容易出现眼高手低的,所以,今天摩杜云要给大家分享的内容,就是如何用C语言写一个web服务器的基础功能,希望大家看完有所收获。

服务器架构

目标架构

以nginx的思想来考虑本服务器架构,初步考虑如下图:
在这里插入图片描述

当然php进程也可以替换为其他的脚本语言,可以更改源码中的command变量实现。

服务器有一个master进程,其有多个子进程为worker进程,master进程受理客户端的请求,然后分发给worker进程,worker进程处理http头信息后将参数传递给php进程处理后,将结果返回到上层,再响应给客户端。

也考虑过使用php-fpm的worker进程池方式,那样的话php-fpm进程也要仿写了,目前还不熟悉其内部构造,如果可以简单化,自然向其靠拢。目前对PHP的SAPI接口不熟,了解一下再考虑。

当前状态

当前状态的服务器还极其简单,总结下来有以下地方待优化:

当前还是单进程,需要改成多进程,最终为worker进程池方式;
优化socket IO模型,考虑epoll、事件驱动方式;
只支持HTTP GET请求方法,未进行太多的异常处理来定义http状态码;
与php进程的交互方式,考虑如nginx使用unix domain socket方式。
协议目前只考虑了http,后续会考虑一些基于TCP的协议;
虽然简单,但服务器已经有基本的功能了:

它监听本地地址的8080端口,将接收到的http头中的path信息提出出来交给php进程,php进程将参数信息处理后返回给服务器,服务器拼装http响应信息再将结果返回给客户端。

下面介绍各个功能的实现:

功能实现

socket系列方法

在介绍函数之间先用一张图来介绍一次http请求中客户端与服务器之间的交互:
在这里插入图片描述

如图:服务器创建要进行:

1.调用socket()创建一个连接;int socket(int domain, int type, int protocol);

2.调用bind()给套接字命名,绑定端口;int bind( int socket, const struct sockaddr *address, size_t address_len);

3.调用listen()监听此套接字;int listen(int socket, int backlog);

4.调用accept()接受客户端的连接;int accept(int socket, struct sockaddr *address, size_t *address_len);

5.调用recv()接收客户端的信息;int recv(int s, void *buf, int len, unsigned int flags);

6.调用send()将响应信息发送给客户端;int send(int s, const void * msg, int len, unsigned int falgs);

socket间的接收和发送信息在 C 中有几个系列:write() / read() 、send() / recv() 、sendto() / recvfrom()、 sendmsg() / recvmsg(),可以自行选用。

另外函数参数释义和要点,都被我注释在代码中了,感兴趣的可以拉下来看一下,这些在网上也多有介绍,这里不再赘述。

服务器与PHP cli交互

然后是C进程和php进程的交互,考虑到简单易用,目前在C进程中直接执行php脚本:

一开始使用system()函数: int system(const char *command);

system函数会fork一个子进程,在子进程中以cli方式执行php脚本,并将错误码或返回值返回。由于其结果类型不可控,编译时会报一个warning。而且它将结果返回给父进程时,还会在标准输出中打印结果,在服务器执行时会抛出异常。

于是找到了另一个方法popen, FILE * popen(const char * command, const char * type);:

popen同样会fork一个子进程来执行command ,然后建立管道连到子进程的标准输出设备或标准输入设备,然后返回一个文件指针。随后进程便可利用此文件指针来读取子进程的输出设备或是写入到子进程的标准输入设备中。

其type参数便是控制连接到子进程的标准输入还是标准输出。我们想要子进程的标准输出,于是传入type参数为字符 “r” (read)。同理,如果想写入子进程标准输入的话,可以传值 “w”(write)。

另外在接收缓冲区内容的时候也出现了一点小意外:由于使用的fgets()方法会以换行符 为一段的结尾,在接收php进程输出时遇到换行会结束,这里使用了一个中间字符串数组line来接收每一行的信息,将每一行的信息拼装到结果中。

代码如下:
在这里插入图片描述

报文数据处理

socket处于应用层和传输层之间的虚拟层,由于设置服务器socket协议类型为TCP,那么TCP的握手挥手、数据读取等步骤对于我们都是透明的。我们拿到的数据即HTTP报文,关于HTTP报文结构和其字段解释的文章非常多,这里也不再多提。

首先使用C的strtok()方法,获取到HTTP头的第一行,获取到其http方法和path信息,将这些信息处理后,再使用sprintf()方法拼合HTTP响应报文,主要替换了响应内容长度和响应内容。

以上就是关于“如何用用C写一个web服务器的基础功能”的详细内容介绍,希望大家看望之后有所帮助,如若有不清楚的地方或者想了解更多知道可以关注摩杜云,领先的云计算及人工智能服务提供商,十几年行业经验,专业可靠!另外,如果大家觉得这篇文章不错的话,可以分享给更多的人看到。

相关文章:

  • 摩杜云将出席2021亚太内容分发大会暨CDN峰会
  • 如何在centos7环境下二进制安装包安装mysql5.6
  • 如何在MySQL中使用limit方式实现分页
  • 摩杜云全年营收超5亿元,比过去增长近15倍
  • 教你如何在Mysql中,实现双机热备和负载均衡
  • 如何将dede织梦搭建的网站首页index.html去掉?
  • 热潮中的云计算行业,摩杜云如何与巨头角逐?
  • 5G加速云游戏趋势,摩杜云游戏解决方案解决核心痛点
  • 摩杜云对象存储MOS:打造新一代存储技术底座,为海量数据创造无限可能
  • 如何在MySQL中创建数据库及添加用户并授权用户
  • 2021亚太内容分发大会 摩杜云荣获“融合CDN创新奖”
  • 如何在MySQL中实现自增序列?简单易懂的教程推荐!
  • 摩杜云出席2021亚太CDN峰会,荣获“融合CDN创新奖”
  • 摩杜云将出席CDEC2021中国数字智能生态大会
  • 如何在CentOS中安装Redis和MySQL
  • 【RocksDB】TransactionDB源码分析
  • CentOS 7 修改主机名
  • CSS进阶篇--用CSS开启硬件加速来提高网站性能
  • HTTP传输编码增加了传输量,只为解决这一个问题 | 实用 HTTP
  • PAT A1092
  • ViewService——一种保证客户端与服务端同步的方法
  • vue:响应原理
  • 阿里云购买磁盘后挂载
  • 百度小程序遇到的问题
  • 关于使用markdown的方法(引自CSDN教程)
  • 开放才能进步!Angular和Wijmo一起走过的日子
  • 聊聊hikari连接池的leakDetectionThreshold
  • 排序(1):冒泡排序
  • 使用iElevator.js模拟segmentfault的文章标题导航
  • 使用Swoole加速Laravel(正式环境中)
  • 用element的upload组件实现多图片上传和压缩
  • 用Visual Studio开发以太坊智能合约
  • 《天龙八部3D》Unity技术方案揭秘
  • python最赚钱的4个方向,你最心动的是哪个?
  • !!java web学习笔记(一到五)
  • # C++之functional库用法整理
  • #中国IT界的第一本漂流日记 传递IT正能量# 【分享得“IT漂友”勋章】
  • (31)对象的克隆
  • (HAL)STM32F103C6T8——软件模拟I2C驱动0.96寸OLED屏幕
  • (Java岗)秋招打卡!一本学历拿下美团、阿里、快手、米哈游offer
  • (附表设计)不是我吹!超级全面的权限系统设计方案面世了
  • (三)elasticsearch 源码之启动流程分析
  • (算法设计与分析)第一章算法概述-习题
  • (一)Java算法:二分查找
  • (一一四)第九章编程练习
  • ./mysql.server: 没有那个文件或目录_Linux下安装MySQL出现“ls: /var/lib/mysql/*.pid: 没有那个文件或目录”...
  • .chm格式文件如何阅读
  • .class文件转换.java_从一个class文件深入理解Java字节码结构
  • .NET CF命令行调试器MDbg入门(三) 进程控制
  • .Net 垃圾回收机制原理(二)
  • .NET 使用 ILMerge 合并多个程序集,避免引入额外的依赖
  • .NET 中使用 Mutex 进行跨越进程边界的同步
  • @RequestBody与@ResponseBody的使用
  • [<事务专题>]
  • [2019.3.20]BZOJ4573 [Zjoi2016]大森林