0

0

用PHP实现高并发服务器

步履不停

步履不停

发布时间:2019-06-19 10:55:23

|

4242人浏览过

|

来源于php中文网

原创

用PHP实现高并发服务器

一提到高并发,就没有办法绕开I/O复用,再具体到特定的平台linux, 就没办法绕开epoll. epoll为啥高效的原理就不讲了,感兴趣的同学可以自行搜索研究一下。

php怎么玩epoll?首先得安装个libevent库,再装个event扩展或者libevent扩展就可以愉快地玩耍了.

有些人搞不清楚libevent库跟libevent扩展的区别,简单来说,libevent库是C语言对epoll的封装,跟PHP毛关系都没有;libevent扩展就是PHP跟libevent库的沟通桥梁。实际上PHP的很多扩展就是干这个事的,有一些优秀的C语言库,PHP想直接拿来用,就通过PHP扩展的方式接入到PHP。

libevent扩展和event扩展随便选一个装,我个人更喜欢event扩展,因为更面向对象一点。自己去http://pecl.php.net里面搜跟自己PHP版本对应的扩展,下好编译安装一下就OK了.电脑装了多个版本的PHP编译的时候注意一下,phpize的版本要对应上,别搞错了,典型的五步曲:

立即学习PHP免费学习笔记(深入)”;

phpize
./configure
make
make install
php -m | grep event #看看装上了没

我们要实现的服务器,传输层是TCP协议,应用层协议太多太复杂,限于篇幅,会简单地以HTTP服务器举个例子,HTTP协议本身就很复杂,要实现起来细节上有很多考究,我们也不会完全实现HTTP协议。

首先,创建一个socket,三步曲,socket_create、socket_bind、socket_listen,为什么是这三步曲呢?很简单,不管你传输层协议是啥,你下面的网络层协议你得选个版本吧,IPV4还是IPV6,传输层工作方式你得选一个吧,全双工、半双工还是单工,TCP还是UDP你也得选一个吧,socket_create就是这三个选项;确定了网络层和传输层,你得告诉我监听哪个端口吧,这就对应了socket_bind;然后你得开启监听,并指定一个客户端的队列长度吧,这就是socket_listen干的事。

创建完了,同步阻塞咱就不介绍了,一个进程同时最多hold处一个连接,多几个连接同时请求,就得等呗,超过了socket_listen指定的队列长度,就得返回504了。多进程也一样,几个进程就有几个并发,进程又是昂贵资源,而且进程的上下文切换费时费力,导致整个系统效率低下。

没关系,咱有epoll,hold住万千请求不是梦,先实现一个Reactor。libevent库就是Reactor模式,直接调用函数就是在使用Reactor模式,所以无需纠结到底php怎么实现Reactor模式。

reactor = new EventBase;
        }

        return self::$instance;
    }

    public function add($fd, $what, $cb, $arg = null)
    {
        switch ($what) {
            case self::READ:
                $event = new Event($this->reactor, $fd, self::READ, $cb, $arg);
                break;
            case self::WRITE:
                $event = new Event($this->reactor, $fd, self::WRITE, $cb, $arg);
                break;
            default:
                $event = new Event($this->reactor, $fd, $what, $cb, $arg);
                break;
        }

        $event->add();
        $this->events[(int) $fd][$what] = $event;
    }

    public function del($fd, $what = 'all')
    {
        $events = $this->events[(int) $fd];
        if ($what == 'all') {
            foreach ($events as $event) {
                $event->free();
            }
        } else {
            if ($what != self::READ && $what != self::WRITE) {
                throw new \Exception('不存在的事件');
            }

            $events[$what]->free();
        }
    }

    public function run()
    {
        $this->reactor->loop();
    }

    public function stop()
    {
        foreach ($this->events as $events) {
            foreach ($events as $event) {
                $event->free();
            }
        }
        $this->reactor->stop();
    }
}

上面的代码很简单,简单解释一下概念,EventBase就是个容器,里面装的Event实例,这么一说,上面的代码就非常好懂了。 然后一个Server.

mallcloud商城
mallcloud商城

mallcloud商城基于SpringBoot2.x、SpringCloud和SpringCloudAlibaba并采用前后端分离vue的企业级微服务敏捷开发系统架构。并引入组件化的思想实现高内聚低耦合,项目代码简洁注释丰富上手容易,适合学习和企业中使用。真正实现了基于RBAC、jwt和oauth2的无状态统一权限认证的解决方案,面向互联网设计同时适合B端和C端用户,支持CI/CD多环境部署,并提

下载
ip = $ip;		$this->port = $port;
	}	public function start()
	{
	    $socket = $this->createTcpConnection();
	    stream_set_blocking($socket, false);

	    Reactor::getInstance()->add($socket, Reactor::READ, function($socket) {
                $conn = stream_socket_accept($socket);
                stream_set_blocking($conn, false);
                (new Connection($conn))->handle();
        });

            Reactor::getInstance()->run();
	}	public function createTcpConnection()
	{
		$schema = sprintf("tcp://%s:%d", $this->ip, $this->port);
		$socket = stream_socket_server($schema, $errno, $errstr);		if ($errno) {			throw new \Exception($errstr);
		}		return $socket;
	}
}

Connection

conn = $conn;
    }    public function handle()
    {
        Reactor::getInstance()->add($this->conn, Reactor::READ, \Closure::fromCallable([$this, 'read']));
    }    private function read($conn)
    {        $this->read_buffer = '';        if (is_resource($conn)) {            while ($content = fread($conn, 65535)) {                $this->read_buffer .= $content;
            }
        }        if ($this->read_buffer) {
            Reactor::getInstance()->add($conn, Reactor::WRITE, \Closure::fromCallable([$this, 'write']));
        } else {
            Reactor::getInstance()->del($conn);
            fclose($conn);
        }
    }    private function write($conn)
    {        if (is_resource($conn)) {
            fwrite($conn, "HTTP/1.1 200 OK\r\nContent-Type: text/html;charset=utf8\r\nContent-Length:11\r\nConnection: keep-alive\r\n\r\nHello!world");
        }
    }

}

先创建Socket的三步曲,设置成非阻塞模式。然后把socket加到Reactor中监听可读事件,可读的意思就是,缓冲区有数据了,才可读。可读事件发生,说明有新连接来了,用stream_socket_accept接收新连接Conn,把Conn放到Reactor中监听可读事件,可读事件发生,说明客户端有数据发送过来了,循环读直到没数据,然后把Conn放到Reactor中监听可写事件,可写事件发生,说明客户端数据发送完了,把协议组装一下写入响应。

应用层如果是HTTP协议要注意一下Connection: keep-alive头,因为要复用连接,不要一写完就关闭连接。

撸完收工,用ab测一下并发,加-k参数复用连接,i5+8G,3W的并发没啥问题,当然我们这儿没有磁盘I/O,实际情况要从磁盘读取文件,读文件要通过linux的系统调用,而且有几次的文件拷贝操作,花销比较大,常用的解决思路是sendfile,零拷贝直接从一个FD到另一个FD,效率比较高,缺点就是PHP没有现成的已经实现sendfile的扩展,得自己动手,开发成本有点高。

ab测试PO图:

用PHP实现高并发服务器

这就是PHP实现高并发服务器的思路了,只要是用EPOLL解决的,思路都一样,都是三步曲,放到Reactor下监听FD事件。当然这个只是最简单的模型,还有很多可以改进的地方,比如说多进程,抄袭一下nginx,一个主进程+N个工作进程,多进程的目的还是想利用多核并行工作。C语言实现也是这样,只是你可能不用libevent库,自己封装EPOLL,毕竟libevent库有点重,你也用不到libevent的很多东西;当然了,C语言有一堆的数据结构以及定义在数据结构上的操作要写,没有GC,自己管理内存,还要有良好的设计,上多进程还得搞一搞IPC进程间通信的东西,开发难度比PHP要大地多,开发周期也很长,有兴趣的同学可以自己撸一个玩。

更多PHP相关技术文章,请访问PHP教程栏目进行学习!

相关文章

PHP速学教程(入门到精通)
PHP速学教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

php

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
Golang gRPC 服务开发与Protobuf实战
Golang gRPC 服务开发与Protobuf实战

本专题系统讲解 Golang 在 gRPC 服务开发中的完整实践,涵盖 Protobuf 定义与代码生成、gRPC 服务端与客户端实现、流式 RPC(Unary/Server/Client/Bidirectional)、错误处理、拦截器、中间件以及与 HTTP/REST 的对接方案。通过实际案例,帮助学习者掌握 使用 Go 构建高性能、强类型、可扩展的 RPC 服务体系,适用于微服务与内部系统通信场景。

8

2026.01.15

公务员递补名单公布时间 公务员递补要求
公务员递补名单公布时间 公务员递补要求

公务员递补名单公布时间不固定,通常在面试前,由招录单位(如国家知识产权局、海关等)发布,依据是原入围考生放弃资格,会按笔试成绩从高到低递补,递补考生需按公告要求限时确认并提交材料,及时参加面试/体检等后续环节。要求核心是按招录单位公告及时响应、提交材料(确认书、资格复审材料)并准时参加面试。

44

2026.01.15

公务员调剂条件 2026调剂公告时间
公务员调剂条件 2026调剂公告时间

(一)符合拟调剂职位所要求的资格条件。 (二)公共科目笔试成绩同时达到拟调剂职位和原报考职位的合格分数线,且考试类别相同。 拟调剂职位设置了专业科目笔试条件的,专业科目笔试成绩还须同时达到合格分数线,且考试类别相同。 (三)未进入原报考职位面试人员名单。

58

2026.01.15

国考成绩查询入口 国考分数公布时间2026
国考成绩查询入口 国考分数公布时间2026

笔试成绩查询入口已开通,考生可登录国家公务员局中央机关及其直属机构2026年度考试录用公务员专题网站http://bm.scs.gov.cn/pp/gkweb/core/web/ui/business/examResult/written_result.html,查询笔试成绩和合格分数线,点击“笔试成绩查询”按钮,凭借身份证及准考证进行查询。

11

2026.01.15

Java 桌面应用开发(JavaFX 实战)
Java 桌面应用开发(JavaFX 实战)

本专题系统讲解 Java 在桌面应用开发领域的实战应用,重点围绕 JavaFX 框架,涵盖界面布局、控件使用、事件处理、FXML、样式美化(CSS)、多线程与UI响应优化,以及桌面应用的打包与发布。通过完整示例项目,帮助学习者掌握 使用 Java 构建现代化、跨平台桌面应用程序的核心能力。

65

2026.01.14

php与html混编教程大全
php与html混编教程大全

本专题整合了php和html混编相关教程,阅读专题下面的文章了解更多详细内容。

36

2026.01.13

PHP 高性能
PHP 高性能

本专题整合了PHP高性能相关教程大全,阅读专题下面的文章了解更多详细内容。

75

2026.01.13

MySQL数据库报错常见问题及解决方法大全
MySQL数据库报错常见问题及解决方法大全

本专题整合了MySQL数据库报错常见问题及解决方法,阅读专题下面的文章了解更多详细内容。

21

2026.01.13

PHP 文件上传
PHP 文件上传

本专题整合了PHP实现文件上传相关教程,阅读专题下面的文章了解更多详细内容。

35

2026.01.13

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PHP课程
PHP课程

共137课时 | 8.7万人学习

JavaScript ES5基础线上课程教学
JavaScript ES5基础线上课程教学

共6课时 | 7万人学习

PHP新手语法线上课程教学
PHP新手语法线上课程教学

共13课时 | 0.9万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号