search
HomeBackend DevelopmentPHP TutorialImplementing high-concurrency server with PHP

Implementing high-concurrency server with PHP

Jun 19, 2019 am 10:55 AM
phpHigh concurrency

Implementing high-concurrency server with PHP

When it comes to high concurrency, there is no way to bypass I/O multiplexing and then specify the specific platform Linux, there is no way to bypass epoll. I won’t go into the principle of why epoll is efficient. Interested students can search and study it by themselves.

How to play epoll in php? First, you must install a libevent library, and then install an event extension or libevent extension, and you can play happily.

Some people are confused about the difference between the libevent library and the libevent extension. Simply put, the libevent library It is the encapsulation of epoll in C language and has nothing to do with PHP; the libevent extension is the communication bridge between PHP and the libevent library. In fact, many extensions of PHP do this. There are some excellent C language libraries. If PHP wants to use them directly, it can be connected to PHP through PHP extensions.

Choose between libevent extension and event extension. Personally, I prefer event extension because it is more object-oriented. Go to http://pecl.php.net and search for extensions corresponding to your PHP version, download it, compile and install it and it will be OK. When compiling with multiple versions of PHP installed on your computer, pay attention to the version of phpize that matches the one. , make no mistake, the typical five steps:

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

The transport layer of the server we want to implement is the TCP protocol. There are too many application layer protocols and are too complicated. Due to space limitations, we will simply use the HTTP server as an example. For example, the HTTP protocol itself is very complex. There are many details to implement, and we will not fully implement the HTTP protocol.

First, create a socket, three steps, socket_create, socket_bind, socket_listen. Why these three steps? It's very simple. No matter what your transport layer protocol is, you have to choose a version of the network layer protocol below, IPV4 or IPV6. You have to choose a transport layer working method, full duplex, half duplex or simplex, TCP. Or UDP, you have to choose one, socket_create is these three options; after determining the network layer and transport layer, you have to tell me which port to listen to, which corresponds to socket_bind; then you have to enable monitoring and specify a client Queue length, this is what socket_listen does.

After creation, we will not introduce synchronous blocking. A process can hold at most one connection at the same time. If more connections are requested at the same time, you have to wait. If the queue length specified by socket_listen is exceeded, 504 must be returned. . The same goes for multiple processes. Several processes have several concurrent processes. Processes are expensive resources, and the context switching of processes is time-consuming and laborious, resulting in inefficiency of the entire system.

It doesn't matter, we have epoll, it is not a dream to hold thousands of requests, first implement a Reactor. The libevent library is the Reactor mode. Calling the function directly is using the Reactor mode, so there is no need to worry about how to implement the Reactor mode in PHP.

<?php use Event;
use EventBase;

class Reactor
{
    protected $reactor;

    protected $events;

    public static $instance = null;

    const READ = Event::READ | Event::PERSIST;

    const WRITE = Event::WRITE | Event::PERSIST;

    public static function getInstance()
    {
        if (is_null(self::$instance)) {
            self::$instance = new self();
            self::$instance->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();
    }
}

The above code is very simple. Let me briefly explain the concept. EventBase is a container, which contains Event instances. In this way, the above code is very easy to understand. Then a Server.

<?php  use Throwable;use Monolog\Handler\StreamHandler;class Server{	protected $ip;	protected $port;	protected $socket;	protected $reactor;	public function __construct($ip, $port)
	{		$this->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

<?phpclass  Connection{    protected $conn;    protected $read_buffer = &#39;&#39;;    protected $write_buffer = &#39;&#39;;    public function __construct($conn)
    {        $this->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");
        }
    }

}

first creates a Socket in three steps and sets it to non-blocking mode. Then add the socket to the Reactor to listen for readable events. Readable means that it can only be read when there is data in the buffer. A readable event occurs, indicating that a new connection is coming. Use stream_socket_accept to receive the new connection Conn, and put Conn in Reactor to monitor readable events. If a readable event occurs, it indicates that the client has data sent. Read in a loop until there is no data, and then put Conn in the Reactor to listen for writable events. If a writable event occurs, it means that the client data has been sent. Assemble the protocol and write the response.

If the application layer is HTTP protocol, please pay attention to the Connection: keep-alive header, because the connection needs to be reused, so do not close the connection as soon as it is finished.

After finishing the work, use ab to test the concurrency, and add the -k parameter to multiplex the connection. There is no problem with i5 8G, 3W concurrency, of course we don’t have it here. Disk I/O, the actual situation is to read files from the disk, and read files through Linux system calls, and there are several file copy operations, which is relatively expensive. The common solution is sendfile, zero copy directly from an FD To another FD, the efficiency is relatively high. The disadvantage is that PHP does not have a ready-to-implement sendfile extension, so you have to do it yourself, and the development cost is a bit high.

ab test PO picture:

Implementing high-concurrency server with PHP

This is the idea of ​​​​implementing a high-concurrency server in PHP. As long as it is solved with EPOLL, the idea is the same. It is a three-step process. Put it under Reactor to monitor FD events. Of course, this is just the simplest model, and there are many areas that can be improved. For example, multi-process, copy nginx, one main process and N worker processes. The purpose of multi-process is to use multi-core parallel work. The same is true for C language implementation, but you may not use the libevent library and encapsulate EPOLL yourself. After all, the libevent library is a bit heavy, and you can’t use many things in libevent; of course, the C language has a bunch of data structures and functions defined on the data structures. The operations need to be written, there is no GC, the memory must be managed by yourself, and there must be good design. When running multiple processes, you need to work on IPC inter-process communication. The development difficulty is much greater than that of PHP, and the development cycle is also very long. If you are interested Students can play with one by themselves.

For more PHP related technical articles, please visit the PHP Tutorial column to learn!

The above is the detailed content of Implementing high-concurrency server with PHP. For more information, please follow other related articles on the PHP Chinese website!

Statement
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
What is the best way to send an email using PHP?What is the best way to send an email using PHP?May 08, 2025 am 12:21 AM

ThebestapproachforsendingemailsinPHPisusingthePHPMailerlibraryduetoitsreliability,featurerichness,andeaseofuse.PHPMailersupportsSMTP,providesdetailederrorhandling,allowssendingHTMLandplaintextemails,supportsattachments,andenhancessecurity.Foroptimalu

Best Practices for Dependency Injection in PHPBest Practices for Dependency Injection in PHPMay 08, 2025 am 12:21 AM

The reason for using Dependency Injection (DI) is that it promotes loose coupling, testability, and maintainability of the code. 1) Use constructor to inject dependencies, 2) Avoid using service locators, 3) Use dependency injection containers to manage dependencies, 4) Improve testability through injecting dependencies, 5) Avoid over-injection dependencies, 6) Consider the impact of DI on performance.

PHP performance tuning tips and tricksPHP performance tuning tips and tricksMay 08, 2025 am 12:20 AM

PHPperformancetuningiscrucialbecauseitenhancesspeedandefficiency,whicharevitalforwebapplications.1)CachingwithAPCureducesdatabaseloadandimprovesresponsetimes.2)Optimizingdatabasequeriesbyselectingnecessarycolumnsandusingindexingspeedsupdataretrieval.

PHP Email Security: Best Practices for Sending EmailsPHP Email Security: Best Practices for Sending EmailsMay 08, 2025 am 12:16 AM

ThebestpracticesforsendingemailssecurelyinPHPinclude:1)UsingsecureconfigurationswithSMTPandSTARTTLSencryption,2)Validatingandsanitizinginputstopreventinjectionattacks,3)EncryptingsensitivedatawithinemailsusingOpenSSL,4)Properlyhandlingemailheaderstoa

How do you optimize PHP applications for performance?How do you optimize PHP applications for performance?May 08, 2025 am 12:08 AM

TooptimizePHPapplicationsforperformance,usecaching,databaseoptimization,opcodecaching,andserverconfiguration.1)ImplementcachingwithAPCutoreducedatafetchtimes.2)Optimizedatabasesbyindexing,balancingreadandwriteoperations.3)EnableOPcachetoavoidrecompil

What is dependency injection in PHP?What is dependency injection in PHP?May 07, 2025 pm 03:09 PM

DependencyinjectioninPHPisadesignpatternthatenhancesflexibility,testability,andmaintainabilitybyprovidingexternaldependenciestoclasses.Itallowsforloosecoupling,easiertestingthroughmocking,andmodulardesign,butrequirescarefulstructuringtoavoidover-inje

Best PHP Performance Optimization TechniquesBest PHP Performance Optimization TechniquesMay 07, 2025 pm 03:05 PM

PHP performance optimization can be achieved through the following steps: 1) use require_once or include_once on the top of the script to reduce the number of file loads; 2) use preprocessing statements and batch processing to reduce the number of database queries; 3) configure OPcache for opcode cache; 4) enable and configure PHP-FPM optimization process management; 5) use CDN to distribute static resources; 6) use Xdebug or Blackfire for code performance analysis; 7) select efficient data structures such as arrays; 8) write modular code for optimization execution.

PHP Performance Optimization: Using Opcode CachingPHP Performance Optimization: Using Opcode CachingMay 07, 2025 pm 02:49 PM

OpcodecachingsignificantlyimprovesPHPperformancebycachingcompiledcode,reducingserverloadandresponsetimes.1)ItstorescompiledPHPcodeinmemory,bypassingparsingandcompiling.2)UseOPcachebysettingparametersinphp.ini,likememoryconsumptionandscriptlimits.3)Ad

See all articles

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Tools

SublimeText3 Linux new version

SublimeText3 Linux new version

SublimeText3 Linux latest version

mPDF

mPDF

mPDF is a PHP library that can generate PDF files from UTF-8 encoded HTML. The original author, Ian Back, wrote mPDF to output PDF files "on the fly" from his website and handle different languages. It is slower than original scripts like HTML2FPDF and produces larger files when using Unicode fonts, but supports CSS styles etc. and has a lot of enhancements. Supports almost all languages, including RTL (Arabic and Hebrew) and CJK (Chinese, Japanese and Korean). Supports nested block-level elements (such as P, DIV),

SecLists

SecLists

SecLists is the ultimate security tester's companion. It is a collection of various types of lists that are frequently used during security assessments, all in one place. SecLists helps make security testing more efficient and productive by conveniently providing all the lists a security tester might need. List types include usernames, passwords, URLs, fuzzing payloads, sensitive data patterns, web shells, and more. The tester can simply pull this repository onto a new test machine and he will have access to every type of list he needs.

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

MantisBT

MantisBT

Mantis is an easy-to-deploy web-based defect tracking tool designed to aid in product defect tracking. It requires PHP, MySQL and a web server. Check out our demo and hosting services.