php利用socket扩展写一个简单的多进程并发http服务3

接着上文说

上一篇文章只是实现了其并发功能,前一个请求的处理不会阻碍下一个请求的处理,但是是每次请求的时候产生一个新的进程,也不是很好,并且并发的效果并不好,因为只有一个进程在工作。

这次的改进是,将生成多个工作进程,提高并发性能。

贴代码:

#!/usr/local/php5.3/bin/php
<?php

//多进程--预先生成固定进程的数量来处理请求。
error_reporting(0);

set_time_limit(0);
ob_implicit_flush();
date_default_timezone_set("Asia/Shanghai"); 


$debug = false;

$user='';
$worker_processes=0;
$listen_ip = "127.0.0.1";
$listen_port  = 80;
$vhosti = array();

//解析配置文件
function pare_conf_file(){
	global $user,$worker_processes,$listen_ip,$listen_port,$vhost;
	$ini_array = parse_ini_file("./http.ini", true);
	$user=$ini_array['user'];
	$worker_processes=$ini_array['worker_processes'];
	$listen_ip = $ini_array['listen_ip'];
	$listen_port = $ini_array['listen_port'];
	$vhost = $ini_array['vhost'];
}

pare_conf_file();

//不存在的http方法响应
function response_method_404(){
	$result = "";
	$result .="HTTP/1.1 404\r\n";
	$result .="Content-Length: 14\r\n";
	$result .= "Content-Type: text/html\r\n";
	$result .="\r\nserver is not \r\n";
	return $result;
}

//不存在的文件响应
function response_file_404(){
	$result = "";
	$result .="HTTP/1.1 404\r\n";
	$result .="Content-Length:0\r\n";
	$result .= "Content-Type: text/html\r\n";
	$result .="\r\n\r\n";
	return $result;
}

//不支持文件的类型响应
function response_file_type_404(){
	$result = "";
	$result .="HTTP/1.1 404\r\n";
	$result .="Content-Length:11\r\n";
	$result .= "Content-Type: text/html\r\n";
	$result .="\r\ntype is not\r\n";
	return $result;
}

//图片类型响应
function response_file_img($fileurl){
	$type = mime_content_type($fileurl);
	$body = file_get_contents($fileurl);
	$len = strlen($body);
	$result="";
	$result .="HTTP/1.1 200\r\n";
	$result .="Content-Length:$len\r\n";
	$result .= "Content-Type: {$type}\r\n";
	$result .="\r\n$body\r\n";
	return $result;
}

//JS类型响应
function response_file_js($fileurl){
	global $request;
	$body = file_get_contents($fileurl);
	$len = strlen($body);
	$date = date('D, d M Y G:i:s ').'GMT';
	clearstatcache();
	$last_modified = date('D, d M Y G:i:s ',filemtime($fileurl)).'GMT';
	$result="";

	$result .="HTTP/1.1 200\r\n";
	$result .="Cache-Control: public\r\n";
	$result .="Date:$date\r\n";
	$result .="Last-Modified:$last_modified\r\n";
	$result .="Expires:Fri, 24 Jan 2016 10:06:05 GMT\r\n";
	$result .="Content-Length:$len\r\n";
	$result .= "Content-Type: application/x-javascript\r\n";
	$result .="\r\n$body\r\n";

	return $result;
}

//HTML类型响应
function response_file_html($fileurl){
	$body = file_get_contents($fileurl);
	$len = strlen($body);
	$result = "";
	$result .="HTTP/1.1 200\r\n";
	$result .="Content-Length:$len\r\n";
	$result .= "Content-Type: text/html;charset=utf-8\r\n";
	$result .="\r\n$body\r\n";
	return $result;
}

//解析http请求
function pare_request($str){
	clearstatcache();
	global $web_root,$request;
	$arr = explode("\r\n",$str);
	foreach( $arr as $r){
		$pos = stripos($r,":");
		if ( $pos ){
			$key = trim(substr($r,0,$pos));
			$val = trim(substr($r,$pos+1));
			$request[$key] = $val;
		}

	}
	writelog(var_export($request,true));	
	$line0 = explode(" ",$arr[0]);
	if ( $line0[0] == "GET" ){
		$fileurl = $web_root.$line0[1];
		if ( file_exists($fileurl) ){
			$pathinfo = pathinfo($fileurl);
			if ( $pathinfo['extension'] == "js" ){
				$result = response_file_js($fileurl);
			}else if ( $pathinfo['extension'] == "png" || $pathinfo['extension'] == "jpg" || $pathinfo['extension'] == "gif" ){
				$result = response_file_img($fileurl);
			}else if ( $pathinfo['extension'] == "html" ){
				$result = response_file_html($fileurl);
			}else{
				$result = response_file_type_404();
			}
		}else{
			$result = response_file_404();
		}
	}else{
		$result = response_method_404();
	}
	return $result;
}

//信号处理
function sig_handler($signo) 
{

	switch ($signo) {
		case SIGTERM:// 处理中断信号
			echo "SIGTERM\r\n";
			exit;
			break;
		case SIGHUP:
			// 处理重启信号
			echo "SIGHUP\r\n";
			exit;
			break;
		default:
			echo $signo."DEFAULT\r\n";
			exit;
			// 处理所有其他信号
	}

}

//安装信号处理器
function register_sig_handler(){
	pcntl_signal(SIGTERM, "sig_handler");
	pcntl_signal(SIGHUP, "sig_handler");
	pcntl_signal(IGCHLD, "sig_handler" );
}

//日志
function writelog($msg){
	global $debug;
	if ( $debug ){
		echo $msg;
	}else{
		file_put_contents('./log.txt',$msg,FILE_APPEND | LOCK_EX);
	}
}

//切换用户
if ( $user ){
	$user_info = posix_getpwnam($user);
	$uid = $user_info['uid'];
}else{
	$uid = posix_getuid();
}
posix_setuid($uid);

//调试模式判断
if ( !$debug ){
	//产生子进程分支
	$pid = pcntl_fork();
	if ($pid == -1) {
		writelog("could not fork\r\n");
		die("could not fork"); //pcntl_fork返回-1标明创建子进程失败
	} else if ($pid) {
		exit(); //父进程中pcntl_fork返回创建的子进程进程号
	} else {
		// 子进程pcntl_fork返回的时0
	}

	// 从当前终端分离
	if (posix_setsid() == -1) {
		writelog("could not detach form terminal \r\n");
		die("could not detach from terminal");
	}

	register_sig_handler();

}


$address = '127.0.0.1';
$port = 1215;
$web_root = "/home/xtgxiso/phpsource/socket";
$request = array();
$sock = false;

//创建监听socket
function listen_server_socket(){
	global $sock,$address,$port;
	if (($sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) === false) {
		writelog("socket_create() failed: reason: " . socket_strerror(socket_last_error()) . "\n");
		exit;
	}

	socket_set_nonblock($sock);


	if (socket_bind($sock, $address, $port) === false) {
		writelog("socket_bind() failed: reason: " . socket_strerror(socket_last_error($sock)) . "\n");
		exit;
	}else{
		writelog('Socket ' . $address . ':' . $port . " has been opened\n");
	}

	if (socket_listen($sock, 5) === false) {
		writelog("socket_listen() failed: reason: " . socket_strerror(socket_last_error($sock)) . "\n");
		exit;
	}else{
		writelog("Listening for new clients..\n");
	}
}


listen_server_socket();

//创建工作进程
function start_work_process(){
	global $sock,$client_id;
	$pid = pcntl_fork();
	if ( $pid == 0 ){
		do{
			if ( ($msgsock = socket_accept($sock)) === false ) {
				writelog("socket_accept() failed: reason: " . socket_strerror(socket_last_error($sock)) . "\n");
				usleep(5000);
				continue;
			} else {
				$client_id += 1;
				writelog(date('Y-m-d G:i:s')."--Client #" .$client_id .": Connect\n");
			}
			socket_close($sock);
			$cur_buf = '';
			do {
				if (false === ($buf = socket_read($msgsock, 2048))) {
					writelog("socket_read() failed: reason: " . socket_strerror(socket_last_error($msgsock)) . "\n");
					break;
				}
				writelog("read start:\r\n");
				writelog($buf);
				writelog("read end:\r\n\r\n");
				$talkback = pare_request($buf);
				writelog("\r\nwrite start:\r\n");
				socket_write($msgsock, $talkback, strlen($talkback));
				//writelog($talkback);
				writelog("write end:\r\n\r\n\r\n");
				break;
			} while (true);
			socket_close($msgsock);
		}while(true);
	}else if ( $pid > 0 ){
		socket_close($sock);
	}

}


//创建工作进程并处理信号
$client_id = 0;

for( $i = 1; $i <= $worker_processes;$i++){
	start_work_process();
}

while(1){
	sleep(1);
}

writelog("socket_close \r\n");
socket_close($sock);

这样就可以提前生成比如:10个进程。一下子能力提高了10倍 。这个程序并没有将工作进程中的每个请求创建新的进程来处理(性能不太好),要是能够用线程来解决就好了。

The point of the bill is so that by 2020
christina aguilera weight loss Top 7 Formulas for Writing Articles That Get Read

negative aspects at dress for youths
miranda lambert weight lossAdvice on What to Wear at a 70s Party
gay porn
此条目发表在 好文推荐, 网站开发, 网站架构 分类目录,贴了 , 标签。将固定链接加入收藏夹。

评论功能已关闭。