zoukankan      html  css  js  c++  java
  • 初体验开发一个HttpServer雏形

    记得迷上Python的那段时间,同时也关注了IronPython一段时间,IronPython项目的源代码中就包含了一个简单的HttpServer,因为一直都对Web服务器的运行机制很感兴趣,因此研究了一下源代码并跟踪调试,也让我这服务器开发的门外汉体验了一把。
    熟话说,看归看,写归写,写程序远比看懂代码有难度多了,于是乎堆码热情澎湃,堆了一个HttpServer雏形(实现原理的模型)

    一、阻塞模型

    阻塞模型,当您的程序运行到某条代码时(请求I/O操作),当前进程将等待在调用处,后面的语句将不继续执行,直到引起阻塞的语句执行完毕后,等待出后面的语句将可继续执行,从这里我们可以知道,阻塞模型严重浪费计算机的资源,然而非阻塞将是该方案的替代者。我们先看看阻塞模型的实现代码:
    首先,我们开启一个接受来自客户端请求的Socket并与IP地址和端口绑定,然后监听该Socket。

    public static void OpenServer()
    {
        server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        server.Bind(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8000));
        server.Listen(0);
    }
    
    接着我们用死循环接受来自客户端的请求并处理。注意:当程序运行后,如果客户端没有发起请求,下面的程序将在server.Accpet()处阻塞,直到有客户发起请求,程序才继续向下执行。

    public static void BlockingSelect()
    {
       string response = "HTTP/1.0 200 OK\r\nContent-Type:text/html\r\n\r\n";
       response += "<html><head><title>服务器</title></head><body><p style='color:red'>Hello World</p></body></html>";
       while (true)
       {
            Socket temps = server.Accept();
            byte[] buffer = new byte[server.SendBufferSize];
            temps.Receive(buffer);
            string request=System.Text.Encoding.Default.GetString(buffer);
            Console.WriteLine(request);
            temps.Send(System.Text.Encoding.Default.GetBytes(response));
            temps.Close();
        }
    }
    
    
    通过上面的这2段代码,我们就可以使用浏览器向服务器端发送请求了。如果正常,那么您的浏览器将显示已标红的"Hello World",至于上面的代码中response为什么要这样赋值,请读者阅读Http协议rfc。上面的程序是能够跑起来了,但是细心的读者并把上面的程序Run一遍,会发现如果前一个请求没有结束,后面的请求将无法执行,也就是说像排队一样,必须一个一个执行完。这样很明显是很不科学并严重浪费资源的。

    二、非阻塞模型

    非阻塞模型,在Linux下一个很受大家欢迎的是epoll,一般开源项目(网络开发)使用到epoll的话,基本上都是好东西。而在windows下下提供了5种选择(Select,WSAAsyncSelect,WSAEventSelect,Overlapped I/O,Completion Port),本小段代码就使用异步选择(WSAAsyncSelect),因为它是最简单的,一个主线程就可以搞定,这可都要归功于Windows的(事件)消息机制。代码如下:

    public static void OpenServer()
    {
        tcpServer = new TcpListener(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8000));
        tcpServer.Start(1000);
    }
    
    public static void NoBlockingSelect()
    {
        while (true)
        {
            if (tcpServer.Pending())(1)
            {
                tcpServer.BeginAcceptSocket(new AsyncCallback(CallBack), tcpServer);(2)
            }
         }
    }
    
    public static void CallBack(IAsyncResult obj)
    {
        if (obj.IsCompleted)
        {
            string response = "HTTP/1.0 200 OK\r\nContent-Type:text/html\r\n\r\n";
            response += "<html><head><title>服务器</title></head><body><p style='color:red'>Hello World" + DateTime.Now.ToString("hh:mm:ss") + "</p></body></html>";
            Socket tempserver = tcpServer.EndAcceptSocket(obj);
            byte[] buffer = new byte[tempserver.ReceiveBufferSize];
            tempserver.Receive(buffer, tempserver.ReceiveBufferSize, SocketFlags.None);
            string request = System.Text.Encoding.Default.GetString(buffer);
            Console.WriteLine(request.Trim());
            tempserver.Send(System.Text.Encoding.Default.GetBytes(response));
            tempserver.Close();
         }
    }
    
    
    通过上面的代码,您现在可以通过浏览器发起请求了,该程序将最大接受1000个挂起的处理,每个请求将不会影响它后续的请求,程序将以异步方式执行,上面的代码中,我标记了(1)、(2),其中,代码(1)将是检查是否有需要处理的请求,如果有待处理的请求那么才会开始以个异步接受,这里值得注意,如果没有这个检查,可以开起任务管理器,您将看到内存在跳舞且还激情四射;代码(2)将执行一个异步Socket,并注册一个回调方法,以便当I/O请求完毕,通过消息信号的方式执行该方法。

    三、总结

    通过上面的2种Socket编程模型,玩成了一个HttpServer的雏形,如果想象力丰富一点,我们可以使用上面的非阻塞模型改造成一个Web游戏服务器,我现在就在使用Python+epoll进行试验,您不妨也体验一番。

  • 相关阅读:
    Spinnerd的功能和用法
    vagrant up ----失败 问题解决
    Yii2.0基础框架
    linux上nginx新建站点
    vagrant(二)配置文件vagrantfile详解 以及安装php、nginx、mysql
    vagrant(一)初识与安装
    cmd 使用gii的命令行用法
    mysql 使用shell时出现 ERROR 2006 (HY000): MySQL server has gone away 解决方法
    c++ virtual总结
    kartikgridGridView 合计,多选,导出excel,header修改 等方法集合!
  • 原文地址:https://www.cnblogs.com/cbbukn/p/1878250.html
Copyright © 2011-2022 走看看