php利用libevent搭建高效Http服务器

技术文档 - PHP文档 作者: xcheng1986 发布于:2016-07-29 阅读(986) (暂无评论)  

php利用libevent搭建高效Http服务器
<?php

/**
 * httpServer
 *
 * @author lixiaocheng<xcheng1986@126.com>
 * @date 2016-7-29
 */
class httpServer {

	const LIBSERVER = 'tcp://0.0.0.0:8080';

	private $parser = null;

	public function __construct() {
		$GLOBALS['hq_connections'] = array();
		$GLOBALS['hq_buffers'] = array();
		$this->parser = new parseRequest();
	}

	/**
	 * run
	 */
	public function run() {
		$socket = stream_socket_server(self::LIBSERVER, $errno, $errstr);
		if (!$socket)
			die('Http Server Error.');
		stream_set_blocking($socket, 0);
		$base = event_base_new();
		$event = event_new();
		event_set($event, $socket, EV_READ | EV_PERSIST, array($this, 'http_accept'), $base);
		event_base_set($event, $base);
		event_add($event);
		event_base_loop($base);
	}

	/**
	 * http_accept
	 */
	private function http_accept($socket, $flag, $base) {
		static $http_id = 0;

		$connection = stream_socket_accept($socket);
		stream_set_blocking($connection, 0);
		echo "receive new http request [http_id:" . $http_id . "]\r\n";

		//注册缓冲区读
		$buffer = event_buffer_new($connection, array($this, 'http_read'), NULL, array($this, 'http_error'), array($base, $http_id));
		event_buffer_base_set($buffer, $base);
		event_buffer_enable($buffer, EV_READ | EV_PERSIST);

		//保存
		$GLOBALS['hq_connections'][$http_id] = $connection;
		$GLOBALS['hq_buffers'][$http_id] = $buffer;

		$http_id++;
	}

	/**
	 * http_read
	 */
	private function http_read($buffer, $arr) {

		$http_id = $arr[1];

		//用户请求的信息
		$read_str = '';
		while ($read = event_buffer_read($buffer, 1024))
			$read_str .= $read;

		//根据请求的信息做相应的处理并输出结果
		$data = $this->parser->parse($read_str);
		$res = $this->toDoSomething($data);

		$out = "HTTP/1.1 200 OK\r\n" .
			"Content-Type: text/html; charset=utf-8\r\n" .
			"Pragma: no-cache\r\n" .
			"\r\n\r\n" .
			"<html><head><title>httpServer</title></head><body><pre>" . $res . "</pre></body></html>";

		$this->sendUserMsg($http_id, $out);
	}

	/**
	 * http_error
	 */
	private function http_error($buffer, $error, $arr) {

		$http_id = $arr[1];

		//关闭用户连接
		event_buffer_disable($buffer, EV_READ | EV_WRITE);
		event_buffer_free($buffer);
		fclose($GLOBALS['hq_connections'][$http_id]);

		//释放资源
		unset($buffer);
		unset($GLOBALS['hq_connections'][$http_id]);
	}

	/**
	 * 解析请求的字符串
	 * @param type $request_string
	 */
	private function parse($request_string) {
		return print_r($request_string, true);
	}

	/**
	 * to do something
	 */
	private function toDoSomething($request_data) {
		return print_r($request_data, true);
	}

	/**
	 * sendUserMsg
	 */
	private function sendUserMsg($http_id, $string) {
		//Http返回数据给用户
		stream_socket_sendto($GLOBALS['hq_connections'][$http_id], $string);
		//关闭用户连接
		event_buffer_disable($GLOBALS['hq_buffers'][$http_id], EV_READ | EV_WRITE);
		event_buffer_free($GLOBALS['hq_buffers'][$http_id]);
		fclose($GLOBALS['hq_connections'][$http_id]);

		//释放资源
		unset($GLOBALS['hq_buffers'][$http_id]);
		unset($GLOBALS['hq_connections'][$http_id]);
	}

}

/**
 * Http请求解析类
 */
class parseRequest {

	const DEFAULT_ACTION = 'Index';
	const DEFAULT_METHOD = 'index';

	private $header_arr = array();

	public function parse($request_string) {
		$data = explode("\r\n\r\n", $request_string);
		if (empty($data))
			return array();

		$header_arr = explode("\r\n", $data[0]);
		list($method, $url, $stat) = explode(" ", $header_arr[0]);
		$url_info = parse_url($url);
		$this->request_get($url_info['query']);
		$this->request_post($data[1]);
		$this->request_method($method);
		$this->request_path($url_info['path']);

		return $this->header_arr;
	}

	/**
	 * 获取请求的GET数组
	 * @param type $url_info_query
	 */
	private function request_get($url_info_query) {
		parse_str($url_info_query, $this->header_arr['get']);
		if (!$this->header_arr['get'])
			$this->header_arr['get'] = array();
	}

	/**
	 * 获取请求的POST数组
	 * @param type $body
	 */
	private function request_post($body) {
		if ($body)
			parse_str($body, $this->header_arr['post']);
		else
			$this->header_arr['post'] = array();
	}

	/**
	 * 获取请求方法
	 * @param type $method
	 * @return type
	 */
	private function request_method($method) {
		$this->header_arr['method'] = $method;
	}

	/**
	 * 获取请求路由
	 * @param type $url_info_path
	 * @return type
	 */
	private function request_path($url_info_path) {
		if ($url_info_path == '' || $url_info_path == '/' || $url_info_path[0] != '/')
			return $this->header_arr['path'] = array('action' => self::DEFAULT_ACTION, 'method' => self::DEFAULT_METHOD);
		$url_info_path = ltrim($url_info_path, '/');
		$path_arr = explode('/', $url_info_path);
		$this->header_arr['path'] = array(
			'action' => $path_arr[0] ? ucfirst($path_arr[0]) : self::DEFAULT_ACTION,
			'method' => $path_arr[1] ? strtolower($path_arr[1]) : self::DEFAULT_METHOD,
		);
	}

}

$S = new httpServer();
$S->run();