获取本服务器完整的源码
首先,要实现一个Web服务器,必须要有一定的理论基础,才知道要做什么事情(如何写代码)

理论知识

首先,我们要知道什么是客户端和服务器

客户端

指与服务器相对应,为客户提供本地服务的程序。除了一些只在本地运行的应用程序之外,一般安装在普通的客户机上,需要与服务端互相配合运行               --摘自百度百科复制代码

举个例子,我们常常用的浏览器就是一个客户端

服务器

与客户端相对的,提供服务的。一般服务器上面都放有客户端需要的资源。当客户端请求服务器上的某些资源的时候,如果服务器允许的话,那么服务器可以返回这些资源给客户端。例如,浏览器去访问www.baidu.com的时候,百度的服务器就会返回一个html文件给浏览器,然后经过浏览器的渲染,呈现给用户一个美丽的页面

客户端与服务器进行交流的本质

我们知道,无论是客户端的程序还是服务器的程序,本质都是程序。那么当程序跑起来之后,就是进程了。而进程之间进行交流就需要使用进程通信的一些方法了。并且,这两个进程是处于不同的位置对吧(可能在世界的两端),不是简单的由父进程fork一下,然后使用类似于管道、信号之类的进程通信手段就可以完成通信的。既然它们是在网络中的,就需要遵循网络协议

网络协议

HTTP是一个客户端和服务器端请求和应答的标准协议。通常,由HTTP客户端发起一个请求,建立一个到服务器指定端口(默认是80端口)的TCP连接

因此我们要做的工作就是利用Linux系统提供的TCP通信接口来实现HTTP协议。此时我们用到的就是socket(套接字)

每一对网络连接称为一个socket对,包括两个端点的socket地址

socket处理请求与响应示意图

我们接下来要写的代码就是围绕这幅图进行的

IP和端口号

IP是用来在互联网中寻找主机用的,端口号则是用来区分应用的。比如说,我要访问www.baidu.com这个网页,我是需要知道它的IP地址才能访问的,除此之外,我还必须知道端口号。为什么呢?我们可以把IP地址想象成,而我不可能和家通信吧,我还必须知道我要通信的这个人在哪里对吧,此时端口号就起了作用,用来标识哪个人

实现接受GET请求的功能

代码实现

#include <iostream>
#include <string>
#include <cstring>
#include <cstdlib>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/unistd.h>
#include <netinet/in.h>
#include <fstream>using namespace std;const int BUFFSIZE = 1024;
const int MAXLINK = 10; // 未经过处理的连接请求队列可以容纳的最大数目
const int DEFAULT_PORT = 8080;char* get_file_name (char* buff) {char* file_name = buff + 5;char *space = strchr(file_name, ' ');*space = '\0';return file_name;
}void deal_get_http(int connect_fd, char* buff) {char* file_name = get_file_name(buff);const char http_correct_header[] = "HTTP/1.1 200 OK\r\nContent-type: text/html\r\n\r\n";int res = write(connect_fd, http_correct_header, strlen(http_correct_header));if (res > 0) {cout<<"send success"<<endl;}
}bool is_get_http(char* buff) {if (!strncmp(buff, "GET", 3)) { // 如果是GET请求return true;}else {return false;}
}int main(int argc, char const *argv[])
{int socket_fd, connect_fd;struct sockaddr_in servaddr;char buff[BUFFSIZE];socket_fd = socket(AF_INET, SOCK_STREAM, 0);if (socket_fd == -1) {cout<<"create socket error"<<endl;return -1;}memset(&servaddr, 0, sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_addr.s_addr = htonl(INADDR_ANY); // IP必须是网络字节序,INADDR_ANY是绑定本机上所有IPservaddr.sin_port = htons(DEFAULT_PORT); // 端口号必须是网络字节序if (bind(socket_fd, (struct sockaddr*)&servaddr, sizeof(servaddr)) == -1) {cout<<"bind error"<<endl;return -1;}if (listen(socket_fd, MAXLINK) == -1) {cout<<"listen error"<<endl;}connect_fd = accept(socket_fd, (struct sockaddr*)NULL, NULL);if (connect_fd == -1) {cout<<"accept error"<<endl;}else {cout<<"连接成功"<<endl;}memset(buff, '\0', sizeof(buff));recv(connect_fd, buff, BUFFSIZE - 1, 0); // 把请求头(或发送的消息)写入buff中send(connect_fd, buff, BUFFSIZE - 1, 0); // 向客户端发送消息(发送buff中的内容)cout<<"recive message from client: "<<buff<<endl;if (is_get_http(buff)) {cout<<"it is get http"<<endl;deal_get_http(connect_fd, buff);}close(connect_fd);  close(socket_fd);return 0;
}复制代码

好的,到这里,我们就已经写完了一个可以接收GET请求的服务器了,我们来测试一下:

在上面,我们只是模拟了使用telnet发送一个GET请求,这个请求去请求index.html文件,然后我们返回一部分响应头给客户端,此时并没有返回index.html的内容给客户端。接下来,我们就来完成这部分功能,一步一步的让这个服务器健全起来。

返回请求文件的内容

代码实现

void deal_get_http(int connect_fd, char* request_header) {char* file_name = get_file_name(request_header);int file_size = get_file_size(file_name);char file_type[BUFFSIZE];get_filetype(file_name, file_type);int fd = open(file_name, O_RDONLY);void* file_in_mem_addr = mmap(0, file_size, PROT_READ, MAP_PRIVATE, fd, 0); // 存储映射close(fd);char buff[BUFFSIZE];strcat(buff, "HTTP/1.0 200 OK\r\n");strcat(buff, "Server: HHTWS Web Server\r\n");strcat(buff, "Connection: close\r\n");strcat(buff, "Content-length: \r\n");strcat(buff, "Content-type: \r\n\r\n");send(connect_fd, buff, strlen(buff), 0);send(connect_fd, file_in_mem_addr, file_size, 0);munmap(file_in_mem_addr, file_size);
}复制代码

我们来看看效果:

存储映射机制

除了标准文件I/O,内核提供了另一种高级的I/O方式,允许应用程序将文件映射到内存中,即内存和文件中数据是一一对应的。程序员可以直接通过内存来访问文件,就像操作内存的数据块一样,甚至可以写入内存数据区,然后通过透明的映射机制将文件写入磁盘。

当映射一个文件描述符的时候,描述符引用计数增加。如果映射文件后关闭文件,你的进程依然可以访问该文件。当你取消映射或者进程终止时,对应的文件引用计数会减1。

遇到的问题

读取整个文件

开始的时候是想到了常规的方法,也就是使用fgets()函数等等,但是,因为它会给每一个字符串加上'\0'。所以当我使用它的时候,出现了一些乱码。之后我突然想起了我最近在《Linux系统编程》中看到的一个存储映射机制,于是就用上了它。非常方便的把文件的内容获取到了。

Segmentation fault问题

我在运行这个服务器的时候,出现了这个错误。最后经过排查,发现是由于存在野指针。开始的时候,我是这样定义一个文件类型的:

char* file_type;复制代码

然后我就直接把这个野指针给传进get_filetype函数里面去了。导致问题发生。

好了,到这里,我们就写完了一个可以说是部分的支持GET请求的Web服务器了。那小伙伴们是不是想在浏览器里面试一试效果!!看看能不能看到这个HTML文件被浏览器渲染出来!!

我们来试试!!

咦( ′◔ ‸◔`)?为什么不能在浏览器上面看到呢?小伙伴们,我将在下面一篇文章中继续为大家讲解。happy ending

(未完--持续更新加入新功能中)

转载于:https://juejin.im/post/59bfd8306fb9a00a5474e48c

跟我一起来用C++写Web服务器吧相关推荐

  1. 自己动手写web服务器一(浏览器的访问信息)

    要协议一个web服务器,需要了解http协议,下面我们来看一下当浏览器请求网张的时候向web服务器发送的数据,我使用的是ubuntu 中telent展现一个下过程.我需要一个简单的网站来演示一下,我装 ...

  2. 手写Web服务器(三)

    15.解决浏览器传递中文问题 由于HTTP协议只支持ISO8859-1, 此字符集不支持中文, 导致请求中包含中文时, 无法正确传递中文. 在UTF-8中每个中文用三个字节表示, 一个方案是在请求前, ...

  3. 手写Web服务器(二)

    6.实现响应404页面 上一个版本中我们已经实现了根据浏览器中用户在地址栏上输入的URL中的抽象路径去 static目录下寻找对应资源进行响应的工作. 但是会存在路径输入有误,导致定位不对(要么定位的 ...

  4. IIS Web 服务器/ASP.NET 运行原理基本知识概念整理

    前言: 记录 IIS 相关的笔记还是从公司笔试考核题开始的,问 Application Pool 与 AppDomain 的区别? 促使我对进程池进了知识的学习,所以记录一下学习的笔记. 我们知道现在 ...

  5. python开发web服务器——搭建简易网站

    转自:http://blog.csdn.net/baidu_35085676/article/details/69807145?%3E 目标 用已有的丰富图片资源建一个看图网站 条件 开发语言: py ...

  6. 手写webserver服务器

    手写webserver服务器 文章目录 手写webserver服务器 前言 一.web server执行流程 组件说明 项目地址 二.代码实现 三. 效果展示 四.总结 前言 webserver 服务 ...

  7. C10K问题:是时候让Web服务器同时处理一万个客户端了

    原文:http://www.kegel.com/c10k.html 转载:https://rtoax.blog.csdn.net/article/details/117317900 译文:https: ...

  8. 简单的web服务器实现视频播放

    准备写一个web服务器专门供宿舍看电影用. 之前已经实现基本的web服务器,今天又把视频播放器弄好了,接下来就是整合了. 视频播放器,用的CuPlayer,改改demo就行,之前不成功可能是没在loc ...

  9. 使用java自制简易web服务器

    微信公众号:进击的蛋糕(dangao123coding) 什么是web服务器 记得好多年前,刚刚开始学javaweb的时候,老师教的第一件事是安装jdk,第二件事就是安装tomcat了. 当时老师的操 ...

  10. php写项目,php写web项目

    写web项目,页面中的js是单独拿出来放在一个js文件中比较好,还是直接写在html页面中比较好?有什么优缺点? 回复讨论(解决方案) 肯定是单独拿出来好啊,出现错误便于查找 单独放便于开发,可多页面 ...

最新文章

  1. 引入外部样式失败的可能原因
  2. 迁移学习(Transfer learning)、重用预训练图层、预训练模型库
  3. Java内存管理和客户加载过程_Java内存管理的进一步理解-模拟过程图解
  4. QT的QAssociativeIterable类的使用
  5. 一张纸一幅图,竟然提高了10倍的学习和工作效率!?
  6. seo专题之开篇有益
  7. 暴风集团:冯鑫因涉嫌对非国家工作人员行贿被公安机关拘留
  8. 【零基础学Java】—List集合(三十九)
  9. 通过EPPlus导出Excel文件
  10. 什么是xserver和xclient
  11. ps快捷键_学习笔记
  12. 台式低速常温离心机S400操作规程
  13. JAVA中创建线程的三种方法及比较
  14. 祝大家新年快乐,鼠年平安健康、阖家幸福如意!
  15. 企业办理两化融合有什么优势?
  16. 塔望食业洞察|轻食代餐消费洞察、市场现状、竞争格局及未来趋势
  17. 大厂机密,30 提升团队研发效能的锦囊
  18. 利用蒙特卡洛法求π的近似值:
  19. Unity 3D 可展开公告牌
  20. Windows远程代码执行漏洞(CVE-2020-16898) 高危漏洞加固指南

热门文章

  1. 「LibreOJ β Round #4」多项式 (广义欧拉数论定理)
  2. struts转换器详解
  3. STM32F0xx_TIM基本延时配置详细过程
  4. Mysql管理之二进制日志文件的管理
  5. windows service 2008 R2 安装net4.6环境失败,windows service 2008 R2 升级sp1问题
  6. 解决Oracle EM 乱码问题
  7. gcc 找不到 boot python 链接库的问题: /usr/bin/ld: cannot find -lboost_python
  8. MySQL--当事务遇到DDL命令
  9. Android之登录那点事
  10. Javascript模块化编程:require.js的用法