爱妃科技PHP pthreads扩展 真正多线程的使用 | | 爱妃科技
正在加载
请稍等

菜单

红楼飞雪 梦

15526773247

文章

Home web服务器端开发 PHP pthreads扩展 真正多线程的使用
Home web服务器端开发 PHP pthreads扩展 真正多线程的使用

PHP pthreads扩展 真正多线程的使用

web服务器端开发 by

我之前的文章中说过,大多数网站的性能瓶颈不在PHP服务器上,因为它可以简单地通过横向增加服务器或CPU核数来轻松应对(对于各种云主机,增加VPS或CPU核数就更方便了,直接以备份镜像增加VPS,连操作系统、 环境都不用安装配置),而是在于MySQL数据库。如果用 MySQL 数据库,一条联合查询的SQL,也许就可以处理完业务逻辑,但是,遇到大量并发请求,就歇菜了。如果用 NoSQL 数据库,也许需要十次查询,才能处理完同样地业务逻辑,但每次查询都比 MySQL 要快,十次循环NoSQL查询也许比一次MySQL联合查询更快,应对几万次/秒的查询完全没问题。如果加上PHP多线程,通过十个线程同时查询 NoSQL,返回结果汇总输出,速度就要更快了。我们实际的APP产品中,调用一个通过用户喜好实时推荐商品的PHP接口,PHP需要对BigSea NoSQL数据库发起500~1000次查询,来实时算出用户的个性喜好商品数据,PHP多线程的作用非常明显。

PHP扩展下载:https://github.com/krakjoe/pthreads
PHP手册文档:http://php.net/manual/zh/book.pthreads.php

1、扩展的编译安装(Linux),编辑参数 –enable-maintainer-zts 是必选项:

cd /Data/tgz/php-5.5.1
./configure --prefix=/Data/apps/php --with-config-file-path=/Data/apps/php/etc --with-mysql=/Data/apps/mysql --with-mysqli=/Data/apps/mysql/bin/mysql_config --with-iconv-dir --with-freetype-dir=/Data/apps/libs --with-jpeg-dir=/Data/apps/libs --with-png-dir=/Data/apps/libs --with-zlib --with-libxml-dir=/usr --enable-xml --disable-rpath --enable-bcmath --enable-shmop --enable-sysvsem --enable-inline-optimization --with-curl --enable-mbregex --enable-fpm --enable-mbstring --with-mcrypt=/Data/apps/libs --with-gd --enable-gd-native-ttf --with-openssl --with-mhash --enable-pcntl --enable-sockets --with-xmlrpc --enable-zip --enable-soap --enable-opcache --with-pdo-mysql --enable-maintainer-zts
make clean
make
make install        
 
unzip pthreads-master.zip
cd pthreads-master
/Data/apps/php/bin/phpize
./configure --with-php-config=/Data/apps/php/bin/php-config
make
make install

添加:

vi /Data/apps/php/etc/php.ini
extension = "pthreads.so"

 

2.windows下安装php真正的多线程扩展pthreads教程:(上述是linux下的PThread扩展,下面的是windows)

扩展地址:http://docs.php.net/manual/zh/book.pthreads.php

(1)下载pthreads扩展
下载地址:http://windows.php.net/downloads/pecl/releases/pthreads
根据本人环境,我下载的是pthreads-2.0.8-5.3-ts-vc9-x86。
2.0.8代表pthreads的版本。
5.3代表php的版本。
ts表示php要线程安全版本的。
vc9表示php要Visual C++ 2008编译器编译的。
x86则表示32位的

(2)、安装pthreads扩展
复制php_pthreads.dll 到目录 bin\php\ext\ 下面。(本人路径D:\wamp\bin\php\php5.3.10\ext)
复制pthreadVC2.dll 到目录 bin\php\ 下面。(本人路径D:\wamp\bin\php\php5.3.10)
复制pthreadVC2.dll 到目录 C:\windows\system32 下面。
打开php配置文件php.ini。在后面加上extension=php_pthreads.dll
提示!Windows系统需要将 pthreadVC2.dll 所在路径加入到 PATH 环境变量中。我的电脑—>鼠标右键—>属性—>高级—>环境变量—>系统变量—>找到名称 为Path的—>编辑—>在变量值最后面加上pthreadVC2.dll的完整路径(本人的为C:\WINDOWS \system32\pthreadVC2.dll)。

(3)、测试pthreads扩展

class AsyncOperation extends \Thread {
    public function __construct($arg){
        $this->arg = $arg;
    }
    public function run(){
        if($this->arg){
            printf("Hello %s\n", $this->arg);
        }
    }
}
$thread = new AsyncOperation("World");
if($thread->start())
    $thread->join();
?>

 

运行以上代码出现 Hello World,说明pthreads扩展安装成功!

 

 

3、给出一段PHP多线程、与For循环,抓取百度搜索页面的PHP代码示例:

  1. <?php
  2. class test_thread_run extends Thread
  3. {
  4. public $url;
  5. public $data;
  6.  
  7. public function __construct($url)
  8. {
  9. $this->url = $url;
  10. }
  11.  
  12. public function run()
  13. {
  14. if(($url = $this->url))
  15. {
  16. $this->data = model_http_curl_get($url);
  17. }
  18. }
  19. }
  20.  
  21. function model_thread_result_get($urls_array)
  22. {
  23. foreach ($urls_array as $key => $value)
  24. {
  25. $thread_array[$key] = new test_thread_run($value["url"]);
  26. $thread_array[$key]->start();
  27. }
  28.  
  29. foreach ($thread_array as $thread_array_key => $thread_array_value)
  30. {
  31. while($thread_array[$thread_array_key]->isRunning())
  32. {
  33. usleep(10);
  34. }
  35. if($thread_array[$thread_array_key]->join())
  36. {
  37. $variable_data[$thread_array_key] = $thread_array[$thread_array_key]->data;
  38. }
  39. }
  40. return $variable_data;
  41. }
  42.  
  43. function model_http_curl_get($url,$userAgent="")
  44. {
  45. $userAgent = $userAgent ? $userAgent : 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.2)';
  46. $curl = curl_init();
  47. curl_setopt($curl, CURLOPT_URL, $url);
  48. curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
  49. curl_setopt($curl, CURLOPT_TIMEOUT, 5);
  50. curl_setopt($curl, CURLOPT_USERAGENT, $userAgent);
  51. $result = curl_exec($curl);
  52. curl_close($curl);
  53. return $result;
  54. }
  55.  
  56. for ($i=0; $i < 100; $i++)
  57. {
  58. $urls_array[] = array("name" => "baidu", "url" => "http://www.baidu.com/s?wd=".mt_rand(10000,20000));
  59. }
  60.  
  61. $t = microtime(true);
  62. $result = model_thread_result_get($urls_array);
  63. $e = microtime(true);
  64. echo "多线程:".($e-$t)."\n";
  65.  
  66. $t = microtime(true);
  67. foreach ($urls_array as $key => $value)
  68. {
  69. $result_new[$key] = model_http_curl_get($value["url"]);
  70. }
  71. $e = microtime(true);
  72. echo "For循环:".($e-$t)."\n";
  73. ?>

 

再给一个一个Thinkphp3.2.2简单例子

<?php
namespace Home\Controller;
class test extends \Thread {
    public $url;
    public $result;
 
    public function __construct($url) {
        $this->url = $url;
    }
 
    public function run() {
        if ($this->url) {
            $this->result = model_http_curl_get($this->url);
        }
    }
}
function model_http_curl_get($url) {
    $curl = curl_init();  
    curl_setopt($curl, CURLOPT_URL, $url);  
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);  
    curl_setopt($curl, CURLOPT_TIMEOUT, 5);  
    curl_setopt($curl, CURLOPT_USERAGENT, 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.2)');  
    $result = curl_exec($curl);  
    curl_close($curl);  
    return $result;  
}
for ($i = 0; $i < 10; $i++) {
    $urls[] = 'http://www.baidu.com/s?wd='. rand(10000, 20000);
}
/* 多线程速度测试 */
$t = microtime(true);
foreach ($urls as $key=>$url) {
    $workers[$key] = new test($url);
    $workers[$key]->start();
}
foreach ($workers as $key=>$worker) {
    while($workers[$key]->isRunning()) {
        usleep(100);  
    }
    if ($workers[$key]->join()) {
        dump($workers[$key]->result);
    }
}
$e = microtime(true);
echo "多线程耗时:".($e-$t)."秒<br>";  
/* 单线程速度测试 */
$t = microtime(true);
foreach ($urls as $key=>$url) {
    dump(model_http_curl_get($url));
}
$e = microtime(true);
echo "For循环耗时:".($e-$t)."秒<br>";

测试结果如下:
多线程耗时:2.8371710777282714844秒
For循环耗时:10.941586017608642578秒

 

下面的是官方的一些实例:

<?php
/**
* This file serves as a benchmark for pthreads initialization/destruction
* usage: php-zts examples/Benchmark.php [threads] [samples]
*   threads - the number of threads to create, default=100
*   samples - the number of times to run the test, default=5
*/
 
/**
* Nothing
*/
class T extends Thread {
	public function run() {}
}
 
$max = @$argv[1] ? $argv[1] : 100;
$sample = @$argv[2] ? $argv[2] : 5;
 
printf("Start(%d) ...", $max);
$it = 0;
do {
    $s = microtime(true);
    /* begin test */
    $ts = [];
    while (count($ts)<$max) {
        $t = new T();
        $t->start();
        $ts[]=$t;
    }
    $ts = [];
    /* end test */
 
    $ti [] = $max/(microtime(true)-$s);
    printf(".");
} while ($it++ < $sample);
 
printf(" %.3f tps\n", array_sum($ti) / count($ti));
?>

 

<?php
/*
	This isn't built in as it's a pretty simple task to achieve for your self
	I can't really think of any functions that are labourious enough that you
	would want to execute them by themselves in a thread of their own. Maybe
	you have functions within your own code that could be called async without
	refactoring for multi-threading capabilities ...
 
	I personally think you shouldn't try to make chocolate from cheese and you
	would be better of refactoring your code to be multi-threaded ...
 
	But here's an example of how you would achieve such a task:
*/
class Async extends Thread {
	/**
	* Provide a passthrough to call_user_func_array
	**/
	public function __construct($method, $params){
		$this->method = $method;
		$this->params = $params;
		$this->result = null;
		$this->joined = false;
	}
 
	/**
	* The smallest thread in the world
	**/
	public function run(){
		if (($this->result=call_user_func_array($this->method, $this->params))) {
			return true;
		} else return false;
	}
 
	/**
	* Static method to create your threads from functions ...
	**/
	public static function call($method, $params){
		$thread = new Async($method, $params);
		if($thread->start()){
			return $thread;
		} /** else throw Nastyness **/
	}
 
	/**
	* Do whatever, result stored in $this->result, don't try to join twice
	**/
	public function __toString(){
		if(!$this->joined) {
			$this->joined = true;
			$this->join();
		}
 
		return $this->result;
	}
}
 
/* here's us calling file_get_contents in a thread of it's own */
$future = Async::call("file_get_contents", array("http://www.php.net"));
/* here's us counting the bytes out, note, __toString() magic joined so no need to join explicitly */
printf("Got %d bytes from php.net\n", strlen((string)$future));
/* you can reference again as a string because you cached the result, YOU CANNOT JOIN TWICE */
printf("First 16 chars: %s\n", substr((string)$future, 0, 16));
/* if you have no __toString(): */
/* $response = $future->result; */
/* you could also not use a reference to the thread,
	if the threads job was to say, log stats and you do not need to know when or how it returns,
	then you could just Async::call at the beginning of the request and by the end it would be finished */
?>

 

<?php
/*
* Sharing symbols 101
* @NOTE Thread::fetch was never included in a release and was superceeded by object handlers
* 	pthreads allows read access to thread data from any context
	pthreads allows write access to thread data from any context
	carry on reading ...
	work in progress ...
*/
class TestObject {
	public $val;
}
 
class Fetching extends Thread {
	public function run(){
		/*
		* of course ...
		*/
		$this->sym = 10245;
		$this->arr = array(
			"1", "2", "3"
		);
 
		/*
		* objects do work, no preparation needed ...
		* read/write objects isn't finalized ..
		* so do the dance to make it work ...
		*/
		$obj = new TestObject();
		$obj->val = "testval";
		$this->obj = $obj;
 
		/*
		* will always work
		*/
		$this->objs = serialize($this->obj);
 
		/*
		* nooooooo
		*/
		$this->res = fopen("php://stdout", "w");
 
		/*
		* tell the waiting process we have created symbols and fetch will succeed
		*/
		$this->synchronized(function(){
		    $this->notify();
		});
 
		/* wait for the process to be finished with the stream */
		$this->synchronized(function(){
		    $this->wait();
		});
	}
}
 
$thread = new Fetching();
 
$thread->start();
 
$thread->synchronized(function($me){
    $me->wait();
}, $thread);
 
/*
* we just got notified that there are symbols waiting
*/
foreach(array("sym", "arr", "obj", "objs", "res") as $symbol){
	printf("\$thread->%s: ", $symbol);	
	$fetched = $thread->$symbol;
	if ($fetched) {
		switch($symbol){
			/*
			* manual unserialize
			*/
			case "objs":
				var_dump(unserialize($fetched));
			break;
 
			default: var_dump($fetched);
		}
	}
	printf("\n");
}
 
/* notify the thread so it can destroy resource */
$thread->synchronized(function($me){
    $me->notify();
}, $thread);
?>

 

<?php
 
/**
 * This is small example that shows the implementation of a thread based HTTP server
 * supporting Connection: keep-alive and how session handling can be implemented.
 * 
 * To start the server, open the command line and enter:
 * 
 *     $ php -f keep-alive-session.php 8822
 *     
 * where 8822 is an example port to let the server listen to. To run this example you
 * need a thread-safe compiled PHP > 5.3 with pthreads enabled.
 * 
 * @author Tim Wagner <tw@appserver.io>
 * @version 0.1.0
 * @link https://github.com/krakjoe/pthreads
 */
class Test extends Thread
{
 
    /**
     * Socket resource to read/write from/to.
     * 
     * @var resource
     */
    protected $socket;
 
    /**
     * Initializes the thread with the socket resource
     * necessary for reading/writing.
     * 
     * @param resource $socket The socket resource
     * @return void
     */
    public function __construct($socket)
    {
        $this->socket = $socket;
    }
 
    /**
     * Found on php.net {@link http://pa1.php.net/function.http-parse-headers#111226}, thanks
     * to anonymous!
     * 
     * @param string $header The header to parse
     * @return array The headers parsed from the passed string
     * @see http://pa1.php.net/function.http-parse-headers#111226
     */
    public function http_parse_headers($header)
    {
        $retVal = array();
        $fields = explode("\r\n", preg_replace('/\x0D\x0A[\x09\x20]+/', ' ', $header));
        foreach( $fields as $field ) {
            if (preg_match('/([^:]+): (.+)/m', $field, $match)) {
                $match[1] = preg_replace('/(?<=^|[\x09\x20\x2D])./e', 'strtoupper("\0")', strtolower(trim($match[1])));
                if( isset($retVal[$match[1]]) ) {
                    if (!is_array($retVal[$match[1]])) {
                        $retVal[$match[1]] = array($retVal[$match[1]]);
                    }
                    $retVal[$match[1]][] = $match[2];
                } else {
                    $retVal[$match[1]] = trim($match[2]);
                }
            }
        }
        return $retVal;
    }
 
    /**
     * The thread's run() method that runs asynchronously.
     * 
     * @link http://www.php.net/manual/en/thread.run.php
     */
    public function run()
    {
 
        // initialize the local variables and the socket
        $threadId = $this->getThreadId();
 
        $counter = 1;
        $connectionOpen = true;
        $startTime = time();
 
        $timeout = 5;
        $maxRequests = 5;
 
        $client = socket_accept($this->socket);
        socket_set_option($client, SOL_SOCKET, SO_RCVTIMEO, array("sec" => $timeout, "usec" => 0));
 
        do {
 
            // we only read headers here, because it's an example
            $buffer = '';
            while ($buffer .= socket_read($client, 1024)) {
                if (false !== strpos($buffer, "\r\n\r\n")) {
                    break;
                }
            }
 
            // check if the clients stopped sending data
            if ($buffer === '') {
 
                socket_close($client);
                $connectionOpen = false;
 
            } else {
 
                // parse the request headers
                $requestHeaders = $this->http_parse_headers($buffer);
 
                // simulate $_COOKIE array
                $_COOKIE = array();
                if (array_key_exists('Cookie', $requestHeaders)) {
                    $cookies = explode('; ', $requestHeaders['Cookie']);
                    foreach ($cookies as $cookie) {
                        list ($key, $value) = explode('=', $cookie);
                        $_COOKIE[$key] = $value;
                    }
                }
 
                // calculate the number of available requests (after this one)
                $availableRequests = $maxRequests - $counter++;
 
                // prepare response headers
                $headers = array();
                $headers[] = "HTTP/1.1 200 OK";
                $headers[] = "Content-Type: text/html";
 
                // start the session if not already done 
                if (session_status() == PHP_SESSION_NONE) {
                    session_start();
                }
 
                // write data to a REAL PHP session, started with session_start()!
                $_SESSION["thread_$threadId"]['availableRequest'] = $availableRequests;
 
                // add a header to create session cookie
                $headers[] = "Set-Cookie: " . session_name() . "=" . session_id() . "; Path=/";
 
                // prepare HTML body
                $body = '<html><head><title>A Title</title></head><body><p>Generated by thread: ' . $threadId . '</p><p>' . var_export($_SESSION, true) . '</p></body></html>';
 
                // prepare header with content-length
                $contentLength = strlen($body);
                $headers[] = "Content-Length: $contentLength";
 
                // check if this will be the last requests handled by this thread
                if ($availableRequests > 0) {
                    $headers[] = "Connection: keep-alive";
                    $headers[] = "Keep-Alive: max=$availableRequests, timeout=$timeout, thread={$this->getThreadId()}";
                } else {
                    $headers[] = "Connection: close";
                }
 
                // prepare the response head/body
                $response = array(
                    "head" => implode("\r\n", $headers) . "\r\n",
                    "body" => $body
                );
 
                // write the result back to the socket
                socket_write($client, implode("\r\n", $response));
 
                // check if this is the last request
                if ($availableRequests <= 0) {
                    // if yes, close the socket and end the do/while
                    socket_close($client);
                    $connectionOpen = false;
                }
            }
 
        } while ($connectionOpen);
    }        
}
 
// intialize the threads and the socket
$workers = array();
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_bind($socket, '0.0.0.0', $argv[1]);
socket_listen($socket);
 
// we start 5 worker threads here
if ($socket) {
 
    $worker = 0;
 
    while (++ $worker < 5) {
        $workers[$worker] = new Test($socket);
        $workers[$worker]->start(PTHREADS_INHERIT_ALL|PTHREADS_ALLOW_HEADERS);
    }
 
    foreach ($workers as $worker) {
        $worker->join();
    }
}

 

<?php
/* this seems like a pretty good way to show you the difference between threads that are syncrhonized with mutex and those that aren't */
/* will show 50 very neat rows <-.........-> then 50 threads doing the same thing with no mutex */
class MyWorkerThread extends Thread {
	public function __construct($limit, $mutex = null){
		$this->limit = $limit;
		$this->mutex = $mutex;
	}
 
	public function run(){
		if($this->mutex)
			$locked=Mutex::lock($this->mutex);
		printf("%s#%lu:<-", !empty($locked)?"Y":"N", $this->getThreadId());
		$i=0;
		while($i++<$this->limit){
			echo ".";
		}
		printf("->\n");
		if($this->mutex)
			Mutex::unlock($this->mutex);
		return true;
	}
}
 
$timer = microtime(true);
/* create and lock a mutex */
$mutex = Mutex::create(true);
/* create workers */
$workers = array();
for($i=0;$i<50;$i++){
	$workers[$i]=new MyWorkerThread(rand(30, 100), $mutex);
	/* they cannot go anywhere, I have the mutex */
	$workers[$i]->start();
}
printf("Release the (muzzled) hounds ... :\n");
Mutex::unlock($mutex);
foreach($workers as $i=> $worker)
	$workers[$i]->join();
printf("Muzzled: %f seconds\n", microtime(true)-$timer);
/* please remember to destroy mutex and condition variables */
Mutex::destroy($mutex);
 
$timer = microtime(true);
/* same again, no mutex */
printf("Now no mutex ... :\n");
$workers = array();
for($i=0;$i<50;$i++){
	$workers[$i]=new MyWorkerThread(rand(30, 100));
	/* they cannot go anywhere, I have the mutex */
	$workers[$i]->start();
}
foreach($workers as $worker)
	$worker->join();
printf("Dribbling: %f seconds\n", microtime(true)-$timer);
?>

 

<?php
/**
* This example illustrates best practice with regard to using MySQLi in multiple threads
*
* For convenience and simplicity it uses a Pool.
**/
 
class Connect extends Worker {
 
    public function __construct($hostname, $username, $password, $database, $port = 3306) {
        $this->hostname = $hostname;
        $this->username = $username;
        $this->password = $password;
        $this->database = $database;
        $this->port     = $port;
    }
 
    public function getConnection() {
        if (!self::$link) {
            self::$link = new mysqli(
                $this->hostname, 
                $this->username, 
                $this->password, 
                $this->database, 
                $this->port);
        }
 
        /* do some exception/error stuff here maybe */       
 
        return self::$link;
    }
 
    protected $hostname;
    protected $username;
    protected $password;
    protected $database;
    protected $port;
 
    /**
    * Note that the link is stored statically, which for pthreads, means thread local
    **/
    protected static $link;
}
 
class Query extends Threaded {
 
    public function __construct($sql) {
        $this->sql = $sql;
    }
 
    public function run() {
        $mysqli = $this->worker->getConnection();
 
        $result = $mysqli->query($this->sql);
 
        if ($result) {    
            while (($row = $result->fetch_assoc())) {
                $rows[] = $row;
            }
        }
 
        $this->result = $rows;
    }
 
    public function getResult() {
        return $this->result;
    }
 
    protected $sql;
    protected $result;
}
 
$pool = new Pool(4, "Connect", ["localhost", "root", "", "mysql"]);
$pool->submit
    (new Query("SHOW PROCESSLIST;"));
$pool->submit
    (new Query("SHOW PROCESSLIST;"));
$pool->submit
    (new Query("SHOW PROCESSLIST;"));
$pool->submit
    (new Query("SHOW PROCESSLIST;"));
$pool->submit
    (new Query("SHOW PROCESSLIST;"));
$pool->submit
    (new Query("SHOW PROCESSLIST;"));
$pool->shutdown();
 
/* ::collect is used here for shorthand to dump query results */
$pool->collect(function($query){
    var_dump(
        $done = $query->getResult());
 
    return count($done);
});
?>
<?php
/*
* @NOTE
*	RESOURCES ARE BEING TRIED OUT, THIS MAY CRASH OR KILL THE EXECUTOR OF THE SCRIPT: NOT MY FAULT
*
*	It's pretty clear that people want resources to work, and I cannot deny it would be useful.
*	Officially, resources are unsupported, if it doesn't work there is NOTHING I can do about it.
*	I do NOT have the time to make every kind of resource safe, or ensure compatibility.
*	I can apply some cleverness to make sure resources are destroyed by whoever creates them, that is ALL.
*	In the case of sockets, this appears to work, the code below ran all day on pthreads.org without interruption.
*	AGAIN: 	If this does not work, there is NOTHING more I can do. 
			If a particular type of resource wigs out, there is NOTHING I can do.
			If this kills you, horribly, there is NOTHING I can do.
*/
class Client extends Thread {
	public function __construct($socket){
		$this->socket = $socket;
		$this->start();
	}
	public function run(){
		$client = $this->socket;
		if ($client) {
			$header = 0;
			while(($chars = socket_read($client, 1024, PHP_NORMAL_READ))) {
				$head[$header]=trim($chars);
				if ($header>0) {
					if (!$head[$header] && !$head[$header-1])
						break;
				}
				$header++;
			}
			foreach($head as $header) {
				if ($header) {
					$headers[]=$header;	
				}
			}
 
			$response = array(	
				"head" => array(
					"HTTP/1.0 200 OK",
					"Content-Type: text/html"
				), 
				"body" => array()
			);
 
			socket_getpeername($client, $address, $port);
 
			$response["body"][]="<html>";
			$response["body"][]="<head>";
			$response["body"][]="<title>Multithread Sockets PHP ({$address}:{$port})</title>";
			$response["body"][]="</head>";
			$response["body"][]="<body>";
			$response["body"][]="<pre>";
			foreach($headers as $header)
				$response["body"][]="{$header}";
			$response["body"][]="</pre>";
			$response["body"][]="</body>";
			$response["body"][]="</html>";
			$response["body"] = implode("\r\n", $response["body"]);
			$response["head"][] = sprintf("Content-Length: %d", strlen($response["body"]));
			$response["head"] = implode("\r\n", $response["head"]);
 
			socket_write($client, $response["head"]);
			socket_write($client, "\r\n\r\n");
			socket_write($client, $response["body"]);
 
			socket_close($client);
		}
	}
}
/* ladies and gentlemen, the world first multi-threaded socket server in PHP :) */
$server = socket_create_listen(13000);
while(($client = socket_accept($server))){
	$clients[]=new Client($client);
	/* we will serve a few clients and quit, to show that memory is freed and there are no errors on shutdown (hopefully) */
	/* in the real world, do something here to ensure clients not running are destroyed */
	/* the nature of a socket server is an endless loop, 
		if you do not do something to explicitly destroy clients you create this may leak */
}
/* that is all */
?>

 

14 2015-05

 

我要 分享

 

 

本文 作者

 

相关 文章