• 用 PHP 编写 http 服务器


      概述

    众所周知,我们一般使用 PHP 开发Web程序时需要使用到比如Apache或Nginx等Web服务器来支持,那么有没有办法直接使用PHP开发HTTP服务器,答案当然是可以的,最近看了一遍Workerman框架的源码,于是自己仿照写了一个简易的HTTP服务器,学习为主。本文涉及到知识点包括:

    • PHP Socket编程
    • 网络 IO 模型
    • PHP libevent
    • PHP 多进程
    • PHP 扩展信号

      如何编写 HTTP 服务器

    下面是一个简易版HTTP服务器,HTTP 是应用层,其实底层用的是 TCP,在TCP 的基础上包了一层 HTTP的协议。代码如下:

    require_once 'Http.php';
    $socket = stream_socket_server("0.0.0.0:2345", $errno, $errstr);
    
    if (!$socket) {
        echo "$errstr ($errno)<br />
    ";
    } else {
        while (true) {
            $conn = @stream_socket_accept($socket);
            if ($conn)
            {
                $data = Http::encode('Hi world');
                fwrite($conn, $data);
                fclose($conn);
            } else {
                echo "no newSocket
    ";
            }
        }
    }

    几行代码就可以实现一个简单的 web 服务器,在 shell 下面执行下面命令,在浏览器输入:http://127.0.0.1:2345/ 即可看到 Hi world。

    php  simple_http_server.php

    上面那那种构架,阻塞模式,要等前一个处理完了,才能处理下一个。所以流量稍微大一点,就会处理不过来。那我们可以改进一下,变成多进程模式。

    require_once 'Http.php';
    $socket = stream_socket_server("0.0.0.0:2345", $errno, $errstr);
    
    if (!$socket) {
        echo "$errstr ($errno)<br />
    ";
    } else {
        while (true) {
           
           if (pcntl_fork() == 0)
           {
                $conn = @stream_socket_accept($socket);
                
                if ($conn)
                {
                    $data = Http::encode('Hi world');
                    fwrite($conn, $data);
                    fclose($conn);
                } else {
                    echo "no newSocket
    ";
                }
           }
        }
    }

    这种模式最大的问题是,进程/线程创建和销毁的开销很大。所以上面的模式没办法应用于非常繁忙的服务器程序

      高性能的服务器

    其实IO复用的历史和多进程一样长,Linux很早就提供了 select 系统调用,可以在一个进程内维持1024个连接。后来又加入了poll系统调用,poll做了一些改进,解决了 1024 限制的问题,可以维持任意数量的连接。但select/poll还有一个问题就是,它需要循环检测连接是否有事件。这样问题就来了,如果服务器有100万个连接,在某一时间只有一个连接向服务器发送了数据,select/poll需要做循环100万次,其中只有1次是命中的,剩下的99万9999次都是无效的,白白浪费了CPU资源。

    直到Linux 2.6内核提供了新的epoll系统调用,可以维持无限数量的连接,而且无需轮询,这才真正解决了 C10K 问题。现在各种高并发异步IO的服务器程序都是基于epoll实现的,比如Nginx、Node.js、Erlang、Golang。像 Node.js 这样单进程单线程的程序,都可以维持超过1百万TCP连接,全部归功于epoll技术。

    libevent是一个轻量级的基于事件驱动的高性能的开源网络库,并且支持多个平台,依据系统提供的select,poll和epoll方法来进行I/O复用,但是针对于多个系统平台上的不同的I/O复用实现方式,libevent进行了重新的封装,并提供了统一的API接口。libevent在实现上使用了事件驱动这种机制。

    我们通过 多进程 + libevent 来构架 web 服务器,结构图如下:

    具体的代码可以到   demo, 执行 php demo.php start 即可。

      压力测试

     硬件是自己 Mac pro,依据 1000 并发重复 100次进行测试:

     先测试一个 Nginx + fpm ,siege -c 1000 -r 100 http://yii2.localhost/  结果如下:

    再测试自己写的服务器 siege -c 1000 -r 100 http://127.0.0.0:2345

    自己写的服务器成功率几乎是 Nginx + fpm 的 2 倍 。

  • 相关阅读:
    使用VIRTUALBOX安装ANDROID系统 | 图文教程 | 相关设置
    android-x86 下载地址
    java 返回某一天的周日和现在这一周的周日
    使用github上的开源框架SlidingMenu环境的搭建,以及getSupportActionBar方法不能找到的问题
    UI 组件
    git 初始化
    Android,visibility属性
    android去掉标题栏
    error opening trace file: No such file or directory (2) ,can't load transform_config.xml
    Ubuntu下解压缩文件
  • 原文地址:https://www.cnblogs.com/liuzhang/p/9243063.html
Copyright © 2020-2023  润新知