詳解PHP實(shí)現(xiàn)HTTP服務(wù)器過(guò)程
PHP并非不能實(shí)現(xiàn)HTTP服務(wù),一般來(lái)講,這叫網(wǎng)絡(luò)編程或Socket編程。在學(xué)習(xí)到其他語(yǔ)言的這部分的時(shí)候,一般的思路就是如何監(jiān)聽(tīng)TCP實(shí)現(xiàn)一個(gè)服務(wù)器,并處理HTTP協(xié)議。
PHP也可以這樣做,同時(shí)一般伴隨著高性能這樣的關(guān)鍵字出現(xiàn)。
原生Socket編程
我們可以通過(guò)PHP的Socket函數(shù),很簡(jiǎn)單的實(shí)現(xiàn)出HTTP服務(wù)。
function run()
{
//創(chuàng)建服務(wù)端的socket套接流,net協(xié)議為IPv4,protocol協(xié)議為TCP
$socket = socket_create(AF_INET,SOCK_STREAM,SOL_TCP);
/*綁定接收的套接流主機(jī)和端口,與客戶端相對(duì)應(yīng)*/
if(socket_bind($socket,"0.0.0.0", 9502) == false){
echo 'server bind fail:'.socket_strerror(socket_last_error());exit();
}
//監(jiān)聽(tīng)套接流
if(socket_listen($socket,4)==false){
echo 'server listen fail:'.socket_strerror(socket_last_error());exit();
}
//非阻塞
socket_set_nonblock($socket);
call_user_func('onAccept',$socket);
}
run();
然后通過(guò)Socket處理收到的數(shù)據(jù)以及作出響應(yīng):
function onMessage($connection)
{
//拼裝返回的html內(nèi)容
$content = '<html><title>hello,world</title><body>hello,world,http</body></html>';
//拼裝頭信息
$header = '';
$header .= "HTTP/1.1 200 OK\r\n";
$header .= "Date: ".gmdate('D, d M Y H:i:s T')."\r\n";
$header .= "Content-Type: text/html;charset=utf-8\r\n";
$header .= "Content-Length: ".strlen($content)."\r\n\r\n";//必須2個(gè)\r\n表示頭部信息結(jié)束
$header .= $content;
socket_write($connection,$header,strlen($header));
}
function onAccept($socket)
{
//接收客戶端傳遞過(guò)來(lái)的信息
while(true)
{
$accept_resource = socket_accept($socket);
if($accept_resource !== false)
{
$string = socket_read($accept_resource,1024);
echo 'server receive is :'.$string.PHP_EOL;
if($string != false)
{
call_user_func('onMessage',$accept_resource);
}
}
}
}
流行項(xiàng)目
實(shí)際上,PHP有很多在項(xiàng)目都在實(shí)現(xiàn)HTTP服務(wù)器,而且他們一般也都宣稱是高性能的。
Workerman系
Workerman是一款純PHP開(kāi)發(fā)的開(kāi)源高性能的PHP 應(yīng)用容器。幾乎能夠?qū)崿F(xiàn)任何類型的網(wǎng)絡(luò)編程,并且內(nèi)置了一個(gè)HTTP協(xié)議。
$worker = new Worker('http://0.0.0.0:1221');Workerman的官方在21年出品了Webman,一個(gè)基于Workerman實(shí)現(xiàn)的高性能HTTP服務(wù)框架。替代傳統(tǒng)PHP-FPM架構(gòu),提供高性能的HTTP服務(wù)。可以用來(lái)開(kāi)發(fā)網(wǎng)站、接口、微服務(wù)。
Webman實(shí)際上是一個(gè)開(kāi)發(fā)框架,項(xiàng)目的目錄結(jié)構(gòu)都已經(jīng)設(shè)定好了,按照文檔開(kāi)發(fā)就行,最后只要通過(guò)命令就能運(yùn)行起來(lái)。
php start.php start
Webman支持是一個(gè)MVC框架,支持命名空間自動(dòng)加載,所以代碼像這樣:
<?php
namespace app\controller;
use support\Request;
class UserController
{
public function hello(Request $request)
{
$default_name = 'webman';
// 從get請(qǐng)求里獲得name參數(shù),如果沒(méi)有傳遞name參數(shù)則返回$default_name
$name = $request->get('name', $default_name);
// 向?yàn)g覽器返回字符串
return response('hello ' . $name);
}
}
除了高性能等特點(diǎn),他的上手難度很低,并且風(fēng)格與現(xiàn)代的MVC風(fēng)格一致,支持PSR標(biāo)準(zhǔn),代碼精簡(jiǎn)高效。如果你是ThinkPHP的開(kāi)發(fā)者,你會(huì)發(fā)現(xiàn)很容易上手Webman。
Swoole系
說(shuō)道高性能HTTP服務(wù),總是繞不開(kāi)swoole的,他也是國(guó)內(nèi)最早火熱起來(lái)的PHP高性能解決方案。
使用swoole實(shí)現(xiàn)HTTP服務(wù)的代碼也很簡(jiǎn)單:
$http = new Swoole\Http\Server('0.0.0.0', 9501);
$http->on('Request', function ($request, $response) {
$response->header('Content-Type', 'text/html; charset=utf-8');
$response->end('<h1>Hello Swoole. #' . rand(1000, 9999) . '</h1>');
});
$http->start();
swoole實(shí)際上是一個(gè)PHP的擴(kuò)展,近幾年基于他發(fā)展起了很多的高性能框架,比如easyswoole、Hyperf、Swoft、MixPHP等等。它們都基于Swoole實(shí)現(xiàn)框架,可以很容易的創(chuàng)建完整度很成熟的系統(tǒng)。
ReactPHP系
ReactPHP 是用于 PHP 事件驅(qū)動(dòng)編程的底層庫(kù)。也可以用來(lái)實(shí)現(xiàn)各類網(wǎng)絡(luò)編程,包括HTTP服務(wù)。用它實(shí)現(xiàn)HTTP服務(wù)也很簡(jiǎn)單:
require __DIR__ . '/vendor/autoload.php';
$http = new React\Http\HttpServer(function (Psr\Http\Message\ServerRequestInterface $request) {
return React\Http\Message\Response::plaintext(
"Hello World!\n"
);
});
$socket = new React\Socket\SocketServer('127.0.0.1:8080');
$http->listen($socket);
echo "Server running at http://127.0.0.1:8080" . PHP_EOL;
它是一個(gè)底層庫(kù),一般而言,所有PSR的框架都可以基于他運(yùn)行,替換PHP-FPM。所以他也提供了各個(gè)流行框架的接入方案,包括laravel、symfony等,基于ReactPHP,開(kāi)發(fā)了一個(gè)PHP-PM項(xiàng)目。
PHP-PM 是 PHP 應(yīng)用程序的進(jìn)程管理器、增壓器和負(fù)載平衡器。
可以直接通過(guò)命令運(yùn)行:
ppm start --bootstrap=laravel --app-env=prod --debug=0 --logging=0 --workers=20
實(shí)際上ReactPHP是個(gè)很有趣的項(xiàng)目,比如IP電視服務(wù)器、終端shell、Mqtt的server、PHP版的Redis、一個(gè)GUI框架、比特幣P2P網(wǎng)絡(luò)等等,以后有機(jī)會(huì)給大家介紹介紹。
AMPHP系
AMPHP 是 PHP 的高質(zhì)量、事件驅(qū)動(dòng)庫(kù)的集合,在設(shè)計(jì)時(shí)考慮了纖維和并發(fā)性。
基于AMPHP實(shí)現(xiàn)的HTTP服務(wù)框架叫amphp/http-server。使用它也可以快速實(shí)現(xiàn)一個(gè)穩(wěn)定高性能的HTTP服務(wù)。
use Amp\Http\Server\RequestHandler\ClosureRequestHandler;
use Amp\Http\Server\SocketHttpServer;
use Amp\Http\Server\Request;
use Amp\Http\Server\Response;
use Amp\Http\Status;
use Amp\Socket\Server;
use Psr\Log\NullLogger;
// Run this script, then visit http://localhost:1337/ in your browser.
Amp\Loop::run(function () {
$sockets = [
Server::listen("0.0.0.0:1337"),
Server::listen("[::]:1337"),
];
$server = new SocketHttpServer($sockets, new ClosureRequestHandler(function (Request $request) {
return new Response(Status::OK, [
"content-type" => "text/plain; charset=utf-8"
], "Hello, World!");
}), new NullLogger);
yield $server->start();
// Stop the server gracefully when SIGINT is received.
// This is technically optional, but it is best to call Server::stop().
Amp\Loop::onSignal(SIGINT, function (string $watcherId) use ($server) {
Amp\Loop::cancel($watcherId);
yield $server->stop();
});
});
AMPHP也實(shí)現(xiàn)了很多有趣的項(xiàng)目,比如Mysql的客戶端,能夠?qū)崿F(xiàn)連接池等特性。
swow
swow是一個(gè)基于協(xié)程的跨平臺(tái)并發(fā)I/O引擎,關(guān)注并發(fā)IO。
官方給出的HTTP例子代碼行數(shù)比較多,主要是展示了HTTP請(qǐng)求支持的每個(gè)階段的操作方法,代碼也是很簡(jiǎn)潔的。
declare(strict_types=1);
use Swow\Buffer;
use Swow\Coroutine;
use Swow\Http\Parser;
use Swow\Http\ParserException;
use Swow\Socket;
use Swow\SocketException;
$host = getenv('SERVER_HOST') ?: '127.0.0.1';
$port = (int) (getenv('SERVER_PORT') ?: 9764);
$backlog = (int) (getenv('SERVER_BACKLOG') ?: 8192);
$multi = (bool) (getenv('SERVER_MULTI') ?: false);
$bindFlag = Socket::BIND_FLAG_NONE;
$server = new Socket(Socket::TYPE_TCP);
if ($multi) {
$server->setTcpAcceptBalance(true);
$bindFlag |= Socket::BIND_FLAG_REUSEPORT;
}
$server->bind($host, $port, $bindFlag)->listen($backlog);
while (true) {
try {
$connection = $server->accept();
} catch (SocketException $exception) {
break;
}
Coroutine::run(static function () use ($connection): void {
$buffer = new Buffer(Buffer::COMMON_SIZE);
$parser = (new Parser())->setType(Parser::TYPE_REQUEST)->setEvents(Parser::EVENT_BODY);
$parsedOffset = 0;
$body = null;
try {
while (true) {
$length = $connection->recv($buffer, $buffer->getLength());
if ($length === 0) {
break;
}
while (true) {
$parsedOffset += $parser->execute($buffer, $parsedOffset);
if ($parser->getEvent() === $parser::EVENT_NONE) {
$buffer->truncateFrom($parsedOffset);
$parsedOffset = 0;
break; /* goto recv more data */
}
if ($parser->getEvent() === Parser::EVENT_BODY) {
$body ??= new Buffer(Buffer::COMMON_SIZE);
$body->write(0, $buffer, $parser->getDataOffset(), $parser->getDataLength());
}
if ($parser->isCompleted()) {
$response = sprintf(
"HTTP/1.1 200 OK\r\n" .
"Connection: %s\r\n" .
"Content-Length: %d\r\n\r\n" .
'%s',
$parser->shouldKeepAlive() ? 'Keep-Alive' : 'Closed',
$body ? $body->getLength() : 0,
$body ?: ''
);
$connection->send($response);
$body?->clear();
break; /* goto recv more data */
}
}
if (!$parser->shouldKeepAlive()) {
break;
}
}
} catch (SocketException $exception) {
echo "No.{$connection->getFd()} goaway! {$exception->getMessage()}" . PHP_EOL;
} catch (ParserException $exception) {
echo "No.{$connection->getFd()} parse error! {$exception->getMessage()}" . PHP_EOL;
}
$connection->close();
});
}總結(jié)
以上是一些非常流行的PHP框架和項(xiàng)目,但還有其他很多實(shí)現(xiàn)了高性能HTTP服務(wù)的項(xiàng)目。這里不多做介紹了。雖然我們談到PHP的時(shí)候,很少談到網(wǎng)絡(luò)編程,甚至在入門教程中根本就沒(méi)有網(wǎng)絡(luò)編程這節(jié)課。但是使用PHP做網(wǎng)絡(luò)編程的各項(xiàng)應(yīng)用已經(jīng)很火熱了。
在入門其他語(yǔ)言是一定有一節(jié)課程是學(xué)習(xí)網(wǎng)絡(luò)編程的,做PHP教程的也應(yīng)該考慮考慮增加這部分課程了。
到此這篇關(guān)于詳解PHP實(shí)現(xiàn)HTTP服務(wù)器過(guò)程的文章就介紹到這了,更多相關(guān)PHP HTTP服務(wù)器內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
PHP實(shí)現(xiàn)的簡(jiǎn)單AES加密解密算法實(shí)例
這篇文章主要介紹了PHP實(shí)現(xiàn)的簡(jiǎn)單AES加密解密算法,結(jié)合具體實(shí)例形式分析了php基于mcrypt_encrypt、bin2hex、mcrypt_decrypt等方法進(jìn)行字符串加密解密的相關(guān)操作技巧,需要的朋友可以參考下2017-05-05
解析PHP 使用curl提交json格式數(shù)據(jù)
本篇文章是對(duì)PHP中使用curl提交json格式數(shù)據(jù)的實(shí)現(xiàn)方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-06-06
PHP讀取數(shù)據(jù)庫(kù)并按照中文名稱進(jìn)行排序?qū)崿F(xiàn)代碼
有時(shí)候我們讀取數(shù)據(jù)庫(kù)輸出的時(shí)候可能會(huì)需要按照中文用戶名的方式進(jìn)行排序,有些新手朋友對(duì)此事無(wú)從下手,接下來(lái)由小編為您詳細(xì)介紹實(shí)現(xiàn)方法,感興趣的朋友可以了解下啊2013-01-01
PHP郵件群發(fā)機(jī)實(shí)現(xiàn)代碼
這篇文章主要介紹了PHP郵件群發(fā)機(jī)實(shí)現(xiàn)代碼,需要的朋友可以參考下2016-02-02
PHP和Shell實(shí)現(xiàn)檢查SAMBA與NFS Server是否存在
這篇文章主要介紹了PHP和Shell實(shí)現(xiàn)檢查SAMBA與NFS Server是否存在,本文分別給出了PHP檢查腳本和Shell檢查腳本,需要的朋友可以參考下2015-01-01
php inc文件使用的風(fēng)險(xiǎn)和注意事項(xiàng)
本文講的是php中使用.inc文件的風(fēng)險(xiǎn)及解決方法2013-11-11
php簡(jiǎn)單圖像創(chuàng)建入門實(shí)例
這篇文章主要介紹了php簡(jiǎn)單圖像創(chuàng)建方法,實(shí)例分析了php圖像創(chuàng)建的基本技巧,需要的朋友可以參考下2015-06-06
PHP排序算法之快速排序(Quick Sort)及其優(yōu)化算法詳解
這篇文章主要介紹了PHP排序算法之快速排序(Quick Sort)及其優(yōu)化算法,結(jié)合實(shí)例形式分析了php快速排序的原理、實(shí)現(xiàn)方法,并分析了各種優(yōu)化技巧與操作注意事項(xiàng),需要的朋友可以參考下2018-04-04
PHP程序員最常犯的11個(gè)MySQL錯(cuò)誤小結(jié)
對(duì)于大多數(shù)web應(yīng)用來(lái)說(shuō),數(shù)據(jù)庫(kù)都是一個(gè)十分基礎(chǔ)性的部分。如果你在使用PHP,那么你很可能也在使用MySQL—LAMP系列中舉足輕重的一份子。2010-11-11

