web服务器如何处理php请求,想解决的 php 做 web 服务器如果解决并发请求的错误思路笔记,关键字 pcntl_fork...

本文介绍了如何使用PHP实现一个简单的Web服务器,并利用pcntl_fork进行并发处理CGI请求。尽管PHP默认为单线程,但作者尝试通过创建子进程来实现并发。然而,在实际测试中,当后端CGI程序有延迟时,请求仍然按顺序执行。文章还包含了服务器代码的详细注释,以及如何使用ab工具进行并发请求的示例。
摘要由CSDN通过智能技术生成

正好看到一篇用 python 来实现 web 服务器的文章,说到并发处理,所以也想用它里面的那个思路用 php 来实现一遍。http://mengkang.net/491.html

本想通过pcntl_fork派生出子线程,然后再在子线程里去再去处理任务,但是由于 php 单线程的限制,还是顺序执行,但是那篇文章对我收获还是很大,这里做下笔记。

这里只是修改了server.php重点是46行~70行

class server {

private $ip;

private $port;

public function __construct($ip, $port) {

$this->ip = $ip;

$this->port = $port;

$this->await();

}

private function await() {

$sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);

if ($sock < 0) {

echo "Error:" . socket_strerror(socket_last_error()) . "\n";

}

$ret = socket_bind($sock, $this->ip, $this->port);

if (!$ret) {

echo "BIND FAILED:" . socket_strerror(socket_last_error()) . "\n";

exit;

}

echo "OK\n";

$ret = socket_listen($sock);

if ($ret < 0) {

echo "LISTEN FAILED:" . socket_strerror(socket_last_error()) . "\n";

}

do {

$new_sock = null;

try {

$new_sock = socket_accept($sock);

} catch (Exception $e) {

echo $e->getMessage();

echo "ACCEPT FAILED:" . socket_strerror(socket_last_error()) . "\n";

}

$pid = pcntl_fork();

if ($pid == -1) {

echo "could not fork";

} else if ($pid) {

echo "父进程 id:".getmypid()."子进程 id:".$pid."\n";

pcntl_wait($status);

} else {

echo "子进程开始处理请求\n";

try {

$request_string = socket_read($new_sock, 1024);

$response = $this->output($request_string);

socket_write($new_sock, $response);

socket_close($new_sock);

} catch (Exception $e) {

echo $e->getMessage();

echo "READ FAILED:" . socket_strerror(socket_last_error()) . "\n";

}

exit();

}

} while (TRUE);

}

/**

* @param $request_string

* @return string

*/

private function output($request_string){

$request_time = time();

// 静态 GET /1.html HTTP/1.1 ...

// 动态 GET /user.cgi?id=1 HTTP/1.1 ...

$request_array = explode(" ",$request_string);

if(count($request_array) < 2){

return "";

}

$requestUri = $uri = $request_array[1];

//echo "request:".web_config::WEB_ROOT . $uri;

$query_string = null;

if ($uri == "/favicon.ico") {

$this->request_log($request_time,$requestUri);

return "";

}

if (strpos($uri,"?")) {

$uriArr = explode("?", $uri);

$uri = $uriArr[0];

$query_string = isset($uriArr[1]) ? $uriArr[1] : null;

}

$filename = web_config::WEB_ROOT . $uri;

if ($this->cgi_check($filename)) {

$this->set_env($query_string);

$handle = popen($filename, "r");

$read = stream_get_contents($handle);

pclose($handle);

$this->request_log($request_time,$requestUri);

return $this->add_header($read);

}

// 静态文件的处理

if (file_exists($filename)) {

$this->request_log($request_time,$requestUri);

return $this->add_header(file_get_contents($filename));

} else {

return $this->not_found();

}

}

/**

* 设置环境变量 给 cgi 程序使用

* @param $query_string

* @return bool

*/

private function set_env($query_string){

if($query_string == null){

return false;

}

if (strpos($query_string, "=")) {

putenv("QUERY_STRING=".$query_string);

}

}

/**

* 判断请求的 uri 是否是合法的 cgi 资源

* @param $uri

* @return bool

*/

private function cgi_check($uri){

$info = pathinfo($uri);

$extension = isset($info["extension"]) ? $info["extension"] : null;

if( $extension && in_array($extension,explode(",",web_config::CGI_EXTENSION))){

return true;

}

return false;

}

/**

* 404 返回

* @return string

*/

private function not_found(){

$content = "

File Not Found

";

return "HTTP/1.1 404 File Not Found\r\nContent-Type: text/html\r\nContent-Length: ".strlen($content)."\r\n\r\n".$content;

}

/**

* 加上头信息

* @param $string

* @return string

*/

private function add_header($string){

return "HTTP/1.1 200 OK\r\nContent-Length: ".strlen($string)."\r\nServer: mengkang\r\n\r\n".$string;

}

private function request_log($request_time,$uri){

date_default_timezone_set('PRC');

echo date("Y-m-d H:i:s",$request_time)." | ".$uri." | ".date("Y-m-d H:i:s",time())."\n";

}

}

我用 ab 并发请求,后端的 cgi 程序 sleep 4 秒,实际效果还是在队列里等待的。

ab -n3 -c3 http://127.0.01:9003/user.cgi?id=1

571d882504825b01eb66a99b84606afe.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值