模拟实现Web服务器

因为最近想对HTTP协议里面的操作细节有更深层更详细的的理解,就自己模拟实现了一个基于HTTP协议线程池版本的Web服务器的小项目。

开发环境是CentOS Linux release 7.4.

  • 设计思路:

1.首先http协议是基于TCP通信的,所以我们得先实现TCP通信(socket编程通信部分代码)。

class Server{//封装成一个类
    private:
        int port;
        int sock;
    public:
        Server(int _port=8080):port(_port),sock(-1)
        {}
        void Init()
        {
        sock=socket(AF_INET,SOCK_STREAM,0);
        if(sock<0)
        {
        cerr<<"socket err!"<<endl;
        exit(2);
        }
        struct sockaddr_in local;
        local.sin_family=AF_INET;
        local.sin_addr.s_addr=htonl(INADDR_ANY);
        local.sin_port=htons(port);
        if(bind(sock,(struct sockaddr *)&local,sizeof(local))<0)//绑定
        {
        cerr<<"bind err!"<<endl;
        exit(3);
        }
        if(listen(sock,8)<0)//监听
        {
        cerr<<"listen err!"<<endl;
        exit(4);
        }
        }
        void Run()
        {
            struct sockaddr_in peer;
            socklen_t len=0;
        while(1)
        {
            int nsock=accept(sock,(struct sockaddr *)&peer,&len);//接收新连接
            if(nsock<0)
            {
            cerr<<"accept err!"<<endl;
            exit(5);
            }
            cout<<"Get a new link..."<<endl;
            
            pthread_t pd;//让线程去处理,后面改成线程池版本。
            int *p=&nsock;
            pthread_create(&pd,NULL,Entry::HandleRequest,(void *)p);//在HandleRequest函数里面进行请求处理,它在另一个类中。
           
        }
        }
        ~Server()
        {
        if(sock>=0)
        {
        close(sock);
        }
        }
};

2.当通信建立好了之后,客户端可以向服务端发起请求,客户端可以使用GET,POST方法请求资源。因为将来可能同时有很多的用户同时访问服务器,所以在服务器端可以维护一个线程池,实现多用户高效率,而当服务器收到一个请求后,就从线程池里面唤醒一个线程,让这个线程为用户请求提供服务。接下来服务端需要对请求进行相应的分析。比如分析得到请求的方法,请求的资源路径url,判断资源是否合法并产生出相应的错误码,以及判断是否携带参数,如果有参数,参数在哪个部分等等。(可在源码中查看具体代码实现)

3.如果这个请求携带参数或者请求的资源是一个可执行程序等情况,则要调用CGI程序。

4.之后服务器将客户端请求的资源以html页面的形式响应给客户端,并可以差错处理。比如,客户端请求的资源不存在时,返回一个404页面。大致思路就是这个样子,其中实现起来也有很多细节需要注意。

  • 项目特点:

1、支持客户端/服务器模式,客户端能够使用 GET、POST 方法请求资 源,并利用线程池实现多用户,高效率。
2、客户向服务器请求服务时,只需传送请求方法和路径。
3、允许传输多种类型的数据对象,正在传输的类型由 Content-Type 加以 标记处理。

当然啦在项目中也遇见了一些问题。
第一个问题,我原本的思路的是,收到不带参的请求时,服务器构造响应的html页面就是服务器的首页,在这个html文件中,标题和正文部分有中文,但是开始的时候我没有注意编码格式的问题,就导致后面测试的结果页面出现乱码,那这个问题如何解决呢。如果你的网页里面出现了中文,在头部没有加 meta charset=“UTF-8”,将会导致中文乱码,这是编码格式,相当于是告诉给浏览器用什么方式来读这页代码。meta charset="UTF-8"是设置网页文件展示时使用的字符集(编码),那其实除了网页文件展示时有编码以外,网页文件本身还有编码。必须两者统一时才不会乱码。
第二个问题,不能显示图片(这个问题是没有将所有发送的情况考虑完全,只考虑到目录、可执行程序,但没有考虑到如果请求的是一个路径明确的普通文件) 后来的解决办法是,测试请求一个路径明确的test.html文件,加入调试信息 ,将问题定位在:如果请求的资源存在,应该如何处理。对于普通文件,找到后并回显给浏览器;如果是目录,应答的是默认页面;如果是可执行程序,执行后返回结果 就可以了

  • 测试功能:

可以在本地浏览器上面做测试,浏览器为客户端。
1.在测试之前需要先关闭Linux的防火墙,在命令行输入命令systemctl status firewalld可查看防火墙情况,输入命令 systemctl stop firewalld 关闭防火墙,如果弹出下面窗口,你输入当前用户的密码完成认证就可以了。
在这里插入图片描述
2.在Linux命令行上可用命令 ifconfig 查看当前Linux下的网络情况,找到它的ip.
在这里插入图片描述
3.启动服务器端(用到了端口号),然后用本地浏览器连接这个ip,加端口号,此时浏览器(客户端)发起请求,服务器端收到请求构造响应发送响应。因为是以html的形式响应的,故在浏览器(客户端)可直接看到响应的页面。
这个是请求的是首页:
在这里插入图片描述
如果请求的资源不存在等情况,会返回一个404页面,如下图:
在这里插入图片描述
完整的项目源码模拟Web服务器
若有问题 欢迎交流~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值