Организация демона с применением libevent

EvgenyPrudnikov

Новичок
Организация демона с применением libevent

Доброго времени суток.

Т.к. второй день копаюсь в примерах и мануалах, но не могу решить проблему, рискну попросить помощи у гуру.
Поиск по базе Клуба ничего не дал.

Задача такая, необходимо написать простой скрипт-демон, который слушает некий tcp порт, приходящие запросы обрабатываются при помощи libevent.

Как решал задачу:
1. открываю неблокирующий сокет
2. передаю его в качестве декскриптора событию, запускаю event_loop
3. В колбек-процедуре делаю акцепт сокета и пытаюсь через event_bufer прочитать-записать данные

Что происходит:
Цикл запускается, сокет открывается, коллбэк вызывается нормально, но не получается прочитать данные из буфера, записать в него тоже не могу ничего. Читать напрямую из рез-та $conn = stream_socket_accept($stream,0,$addr); получилось просто fread, но записать опять - же не смог.
Запрос делаю по http на некий урл, далее nginx пробразывает его на нужный порт.

Собственно вопросов у меня два и оба не оригинальны:
1. Для чего в либэвенте используется буфер (документации крайне мало, буквально пара скупых слов, как речь на могиле налогового инспектора)
2. Что я делаю неправильно и что нужднго сделать, что бы решить мою задачу? :)
Вариант отказаться от использования libevent... не катит, если нет возможности точно понять "почему" :)

Заранее спасибо :)

Реврайт nginx-а:
PHP:
		location ^~ /newtest {
			access_log off;
			#fastcgi_pass unix:/tmp/phpfastcgid.sock;
			fastcgi_pass localhost:8004;
			include fastcgi_params;
			fastcgi_param DONT_USE_SENDFILE 1;
			fastcgi_param APPNAME Chat;
			fastcgi_param  QUERY_STRING     	$query_string;                     
			fastcgi_param  REQUEST_METHOD	$request_method;
			fastcgi_param  CONTENT_TYPE	$content_type;
		}
Собственно сам код:
PHP:
<?php

error_reporting(E_ALL);
ini_set('display_errors', 1);

function onAcceptEvent($stream, $events)
{
    global $base;
    $initialLowMark = 0;
    $initialHighMark = 0xFFFFFF;
    
    $conn = stream_socket_accept($stream,0,$addr);
    stream_set_blocking($conn,0);
    
    
  $buf = event_buffer_new($conn, 'onReadEvent', 'onWriteEvent', 'onFailureEvent', array(1, 1));
  event_buffer_base_set($buf, $base);
  event_buffer_priority_set($buf,10);
  event_buffer_watermark_set($buf,EV_READ,$initialLowMark,$initialHighMark);
  event_buffer_enable($buf,EV_READ | EV_WRITE | EV_PERSIST);
  stream_set_blocking($buf, 0);
    $read = event_buffer_read($buf, 2048);
    var_dump($read);
    
    $str = 'sdfsd fsd fs dfs df';
    $res = event_buffer_write($buf, $str);
    var_dump($res);
    $read = event_buffer_read($buf, strlen($str));
    var_dump($read);
    
    event_buffer_free($buf);
}

 function onReadEvent($stream,$arg)
 {
     global $base, $buf;
 }
 
 function onWriteEvent($stream,$arg)
 {
     global $base, $buf;
 }
 
 function onFailureEvent($stream,$arg)
 {
     global $base, $buf;
 }
 
 
if (ini_get('mbstring.func_overload') >= 2)
{
 function binarySubstr($s,$p,$l = 0xFFFFFFF)
 {
  return substr($s,$p,$l,'ASCII');
 }
}
else
{
 function binarySubstr($s,$p,$l = NULL)
 {
  if ($l === NULL) {$ret = substr($s,$p);}
  else {$ret = substr($s,$p,$l);}
  if ($ret === FALSE) {$ret = '';}
  return $ret;
 }
}
 
 
$base = event_base_new();
$event = event_new();

$sock = stream_socket_server('127.0.0.1:8004', $errno,$errstr, STREAM_SERVER_BIND | STREAM_SERVER_LISTEN);
stream_set_blocking($sock,0);

event_set($event, $sock, EV_READ, 'onAcceptEvent', array($event,$base));
event_base_set($event, $base);

while (TRUE) {
//event_base_loop($base, EVLOOP_NONBLOCK);
event_add($event);
event_base_loop($base, EVLOOP_NONBLOCK);
}

/*
$base = event_base_new();
$event = event_new();

$socket = stream_socket_server('tcp://127.0.0.1:8004', $errno, $errstr);

event_set($event, $socket, EV_READ | EV_PERSIST, "callback_func", array($event, $base));
event_base_set($event, $base);

event_add($event);
event_base_loop($base);
*/
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
>Запрос делаю по http на некий урл, далее nginx пробразывает его на нужный порт.

ты пишешь fcgi-демон на PHP ?
 

EvgenyPrudnikov

Новичок
Если честно не особо в курсе про данный проект, и при попытке познакомится напрягает уже то, что страница проекта устойчиво http://php-fpm.anight.org/ "недоступна" :)

Главная задача - быстро принимать и обрабатывать демоном запросы из сокета.
Если fpm может помочь в её реализации, подскажите, пожалуйста каким образом.
Я понимаю, что может найтись немало интересных технологий и готовых фреймворков, но хотелось бы всё таки самому разобраться как работает библиотека либэвент и как правильно заюзать её под пхп.
 

DYPA

Настоящая dypa (c)
http://code.google.com/p/phpdaemon/source/browse/#svn/trunk в помощь ;)
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
это стабильный продукт, сделан для hi-load проектов типа мамбы
либивент в него включен

каким образом - прочитать доки, собрать, подумать
 

Alexandre

PHPПенсионер
FCGI сервер на рнр http://code.google.com/p/phpdaemon/
вроде как работает быстро, сам не проверял.

php-fpm более надежное решение с точки зрения продакшен,
уже себя зарекомендовало в нагрузочных проектах.
 

dr-sm

Новичок
php-fpm это очень удобная и полезная надстройка для запуска PHP скриптов с помощью FastCGI'шного SAPI.
концептуально ничем не отличается от mod_php Apachе.
только соединение с фронэндом будед не по HTTP протоколу, а по FastCGI.

и он не для этого:
разобраться как работает библиотека либэвент и как правильно заюзать её под пхп.
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
dr-sm
в PHP нет надстроек, это патч и extension
не для запуска, а для управления,
не с помощью, а по интерфейсу
концептуально он похож на mod_php как ты на китайца
разобраться очень даже можно, почитав код :)

Alexandre, Wicked
я че-то не нашел где его скачать на гугле ... подскажите!
 

Макс

Старожил PHPClub
grigori
только через svn
svn checkout http://phpdaemon.googlecode.com/svn/trunk/ phpdaemon-read-only
 

dr-sm

Новичок
Автор оригинала: grigori
dr-sm
в PHP нет надстроек, это патч и extension
не для запуска, а для управления,
не с помощью, а по интерфейсу
концептуально он похож на mod_php как ты на китайца
разобраться очень даже можно, почитав код :)
с помощью SAPI (Server Application Programming Interface)
и в чем же концептуальные отличия модпхп от фпм состоят?

я собственно только хотел сказать, что по исходникам фпм,
можно научится использовать libevent в Си, но никак не в пхп.
ито это не самый простой пример будед. :)
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
ты тоже весьма похож на китайца, но есть некоторая разница, существенная для окружающих тебя людей

-~{}~ 18.10.09 22:18:

Макс, спасибо

-~{}~ 18.10.09 22:50:

а доков по нему так мало, что страшно его брать
 

Alexandre

PHPПенсионер
а доков по нему так мало, что страшно его брать
что фпм или даемон?
фпм - хорошо себя зарекомендовал себя в высоконагруженных проектах, лично знаю автора.
я собственно только хотел сказать, что по исходникам фпм,
можно научится использовать libevent в Си, но никак не в пхп
для изучения использования libevent в Си можно найти более простые примеры в интернете...
чтоб использовать libevent в пхп - наверняка есть примеры тоже, но не думаю что это хор идея.
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
Alexandre ну конечно я про phpdaemon
FPM я уже год юзаю, hi-load читаю и аффтора тоже знаю :)

расширение libevent для PHP еще 0.2 Beta, теоретически можно ждать проблемы
 

440hz

php.ru
Собственно после недолгого изучения libevent получилось вот такое. немного подрихтовали...

версия
Код:
hosting(root):/home/440hz/event/http#>uname -a
FreeBSD hosting.440hz.ru 6.3-RELEASE-p2 FreeBSD 6.3-RELEASE-p2 #0: Mon Jun  9 00:18:18 MSD 2008     
[email][email protected][/email]:/usr/obj/usr/src/sys/INDIGO  i386

hosting(root):/home/440hz/event/http#>php -v
PHP 5.2.9 with Suhosin-Patch 0.9.7 (cli) (built: Apr  7 2009 16:31:03)
Copyright (c) 1997-2009 The PHP Group
Zend Engine v2.2.0, Copyright (c) 1998-2009 Zend Technologies
    with eAccelerator v0.9.5.3, Copyright (c) 2004-2006 eAccelerator, by eAccelerator

hosting(root):/home/440hz/event/http#>pkg_info | grep libevent
libevent-1.4.9      Provides an API to execute callback functions on certain ev
вызов
Код:
hosting(root):/home/440hz/event/http#>ab -n 10000 -c 1000 [url]http://localhost:81/[/url]
загрузка проца и и памяти
Код:
68018 root        1 111    0 22320K  2332K RUN    0   0:05 25.97% php
68884 root        1 109    0 14548K  8164K RUN    0   0:02 23.52% ab
ответ от бенчмарка
Код:
Server Software:        HTTPDaemon/1.0
Server Hostname:        localhost
Server Port:            81

Document Path:          /
Document Length:        124 bytes

Concurrency Level:      1000
Time taken for tests:   8.526055 seconds
Complete requests:      10000
Failed requests:        0
Write errors:           0
Total transferred:      2541778 bytes
HTML transferred:       1240868 bytes
Requests per second:    1172.88 [#/sec] (mean)
Time per request:       852.606 [ms] (mean)
Time per request:       0.853 [ms] (mean, across all concurrent requests)
Transfer rate:          291.11 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0  156 811.4      0    6306
Processing:     2  144 257.4     11     951
Waiting:        0   73 155.5      9     780
Total:          2  301 842.6     11    6562

Percentage of the requests served within a certain time (ms)
  50%     11
  66%     21
  75%    344
  80%    420
  90%    777
  95%    935
  98%   3044
  99%   6255
 100%   6562 (longest request)
на этой же тачке отдает nginx + FastCGI (www.php.ru первая страница)

Код:
hosting(root):/home/440hz/event/http#>ab -n 10000 -c 1000 [url]http://www.php.ru:80/[/url]

...

Server Software:        nginx/0.5.33
Server Hostname:        [url]www.php.ru[/url]
Server Port:            80

Document Path:          /
Document Length:        6397 bytes

Concurrency Level:      1000
Time taken for tests:   15.290741 seconds
Complete requests:      10000
Failed requests:        9819
   (Connect: 0, Length: 9819, Exceptions: 0)
Write errors:           0
Non-2xx responses:      9825
Total transferred:      4563879 bytes
HTML transferred:       2966331 bytes
Requests per second:    653.99 [#/sec] (mean)
Time per request:       1529.074 [ms] (mean)
Time per request:       1.529 [ms] (mean, across all concurrent requests)
Transfer rate:          291.42 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0  317 1099.2      0    8119
Processing:     4  831 1299.4    298   14579
Waiting:        0  551 1223.4    185   14540
Total:          4 1149 1600.6    299   14579

Percentage of the requests served within a certain time (ms)
  50%    299
  66%    989
  75%   1399
  80%   2036
  90%   3399
  95%   3988
  98%   4599
  99%   8432
 100%  14579 (longest request)

asyncserver.php
PHP:
<?php

/**
 * Асинхронный демон TCP для обработки HTTP запросов
 * 
 * @version: $Id:$
 */

define ( 'EVBUFFER_READ', 0x01 );
define ( 'EVBUFFER_WRITE', 0x02 );
define ( 'EVBUFFER_EOF', 0x10 );
define ( 'EVBUFFER_ERROR', 0x20 );
define ( 'EVBUFFER_TIMEOUT', 0x40 );

define ( 'POOL_READ', 0x01 );
define ( 'POOL_WRITE', 0x02 );
define ( 'POOL_DONE', 0x04 );

/**
 * 
 */
class AsyncServer {
	
	public static $log;
	
	var $rBaseEvent;
	
	// номер открывемого сокета
	var $iSockets;
	// массви открытых сокетов
	var $aSockets;
	// массив событий связанных с сокетом
	var $aSocketsEvents;
	
	// номер открываемого соединения
	var $iConnections;
	// массив текущих коннектов
	var $aConnections;
	// массив событий для текущий коннектов
	var $aConnectionEvents;
	
	// массив буферов, связанных с текущими коннектами
	var $aBuffers;

	// таймауты на коннекты, что б левых отрубать
	var $iTimeOutRead = 5;
	var $iTimeOutWrite = 5;
	
	// длина буфера чтения
	var $iBufferReadLenght = 2048;
	
	// состояния коннекта ЧТЕНИЕ/ЗАПИСЬ
	var $aState;
	// массив пулов для чтения данных из коннекта
	var $aReadPool;
	// массив пулов для записи данных в коннект
	var $aWritePool;
	
	function __construct() {
		
		$this->iSockets = 0;
		$this->iConnections = 0;
		
		// создадим основную базу событий
		$this->rBaseEvent = event_base_new ();
		
		if ($this->rBaseEvent === false) {
			AsyncServer::say ( "Can't create event base." );
			exit ();
		}
		// логируем?
		AsyncServer::$log = false;
	
	}
	
	// выдача лога
	static function say($msg, $who = 'DAEMON') {
		if (AsyncServer::$log)
			print ("{$who}: {$msg}\n") ;
	}
	
	// добавить массив сокетов
	function AddSockets($aIP, $iPort = 81) {
		
		foreach ( $aIP as $IP ) {
			$this->AddSocket ( 'tcp://' . $IP . ':' . $iPort );
		}
	
	}
	
	// добавить сокет
	function AddSocket($sAddr) {
		
		// номер сокета
		$i = $this->iSockets ++;
		
		// открываем слушающий сокет
		$rSocket = stream_socket_server ( $sAddr, $errno, $errstr, STREAM_SERVER_BIND | STREAM_SERVER_LISTEN );
		
		if ($rSocket === false) {
			AsyncServer::say ( "Can't create socket [$sAddr]. {$errno}:{$error}" );
			exit ();
		} else {
			AsyncServer::say ( "Create socket [{$i}] [$sAddr]." );
		}
		
		// запомним сокет
		$this->aSockets [$i] = $rSocket;
		
		// новое событие для сокета
		$event = event_new ();
		AsyncServer::say ( "Create new event." );
		
		// ловим на чтение и после операции чтения возвращаем событие в базу
		$bRc = event_set ( $event, $rSocket, EV_READ | EV_PERSIST, array (
				$this, 
				'onAcceptEvent' ), array (
				$i ) );
		
		if ($bRc === false) {
			AsyncServer::say ( "Can't event set." );
			exit ();
		}
		AsyncServer::say ( "Set event READ to socket [{$i}]." );
		
		AsyncServer::say ( "Save socket and event [{$i}] into Daemon." );
		// запомним событие
		$this->aSocketsEvents [$i] = $event;
	
	}
	
	// установим события в базе
	function EnableSocketEvents() {
		
		reset ( $this->aSocketsEvents );
		foreach ( $this->aSocketsEvents as $i => $event ) {
			$bRc = event_base_set ( $event, $this->rBaseEvent );
			if ($bRc === false) {
				AsyncServer::say ( "Can't set [{$i}] event base." );
				exit ();
			} else {
				AsyncServer::say ( "Set [{$i}] event base." );
			}
		}
	
	}
	
	// добавим события в базу для мониторинга
	function AddSocketEvents() {
		
		reset ( $this->aSocketsEvents );
		foreach ( $this->aSocketsEvents as $i => $event ) {
			$bRc = event_add ( $event );
			if ($bRc === false) {
				AsyncServer::say ( "Can't event [{$i}] add." );
				exit ();
			} else {
				AsyncServer::say ( "Event [{$i}] add." );
			}
		}
	
	}
	
	// кто-то приконнектился. обработаем
	function onAcceptEvent($rSocket, $rEvent, $args) {
		
		// номер сокета от которго пришел коннект
		$i = $args [0];
		AsyncServer::say ( "AcceptEvent [{$i}]." );
		
		// примем коннект
		$rConnection = stream_socket_accept ( $rSocket, 0, $addr );
		AsyncServer::say ( "Connection form [{$addr}]." );
		// сдалем его не блокирующим, что б позволить еще принимать коннекты
		stream_set_blocking ( $rSocket, 0 );
		
		// номер коннекта
		$c = $this->iConnections ++;
		// запомним коннект
		$this->aConnections [$c] = $rConnection;
		
		// пул на чтение данных
		$this->aState [$c] = POOL_READ;
		$this->aReadPool [$c] = '';
		$this->aWritePool [$c] = '';
		
		// создадим события на коннекте
		$buf = event_buffer_new ( $this->aConnections [$c], array (
				$this, 
				'onReadEvent' ), array (
				$this, 
				'onWriteEvent' ), array (
				$this, 
				'onFailureEvent' ), array (
				$c ) );
		AsyncServer::say ( "New buffer created." );
		
		// буфер в базовую наблюдалку
		event_buffer_base_set ( $buf, $this->rBaseEvent );
		AsyncServer::say ( "Set buffer to base." );
		// таймауты что б рубить задержки
		event_buffer_timeout_set ( $buf, $this->iTimeOutRead, $this->iTimeOutWrite );
		AsyncServer::say ( "Set timeout(s)." );
		// включаем буфер на события и возвращаем события назад после выполнения
		event_buffer_enable ( $buf, EV_READ | EV_WRITE | EV_PERSIST );
		AsyncServer::say ( "Buffer enable." );
		
		// сохраним буффер
		$this->aBuffers [$c] = $buf;
	
	}
	
	// простенький обработчик запросов
	function Request($c) {
		
		AsyncServer::say ( "Processing [{$c}]...", 'REQUEST' );
		
		// получим данные
		$sData = $this->aReadPool [$c];
		
		// извратимся что б ыбло видно что где
		$sData = str_replace ( "\n", '<NL>', $sData );
		$sData = str_replace ( "\r", '<CR>', $sData );
		
		$sData = '[' . strlen ( $sData ) . ']' . "\n" . $sData . "\n";
		
		// выдадим заголовки. мож кто броузером считает
		$headers = array ();
		$headers [] = 'HTTP/1.1 200 OK';
		$headers [] = 'Server: Daemon 1.0';
		$headers [] = 'Content-Type: text/html';
		$headers [] = 'Content-Length: ' . strlen ( $sData );
		$headers [] = 'Connection: close';
		$headers [] = 'Accept-Ranges: bytes';
		
		$sHeaders = '';
		foreach ( $headers as $header ) {
			$sHeaders .= $header . "\r\n";
		}
		
		// писнем запросившему ответ
		event_buffer_write ( $this->aBuffers [$c], $sHeaders . "\r\n" . $sData );
	
	}
	
	// читаем данные
	function onReadEvent($rSocket, $args) {
		
		$c = $args [0];
		
		// если читаем после получения данных, т.е. косяк в данных
		// /r/n/r/n пришло, а клиент передает дальше
		// ну и нах такого
		if ($this->aState [$c] != POOL_READ) {
			AsyncServer::say ( "Pool state [{$c}] not READ", 'READ' );
			$this->CloseConnection ( $c );
			return;
		}
		
		// читаем, пока не пришло \r\n\r\n в конце
		do {
			$tmp = event_buffer_read ( $this->aBuffers [$c], $this->iBufferReadLenght );
			// не все клиент передал. обычно по telnet так. кусками плюет.
			if ($tmp == '' or $tmp == null)
				break;
			$this->aReadPool [$c] .= $tmp;
			AsyncServer::say ( "Reading from [{$c}] [" . strlen ( $this->aReadPool [$c] ) . "]/[" . strlen ( $tmp ) . "] ...", 'READ' );
		} while ( ! $this->CheckRequest ( $c ) );
	
	}
	
	// проверить, что пришел конец запроса
	// \r\n\r\n
	function CheckRequest($c) {
		
		// так очень медленно, аж пипец. даже не думайте.
		//if (preg_match ( "/\r\n\r\n$/", $this->aReadPool [$c] )) {
		// проверяем
		if (strpos ( $this->aReadPool [$c], "\r\n\r\n" )) {
			
			AsyncServer::say ( "Ok.", 'CHECKREQUEST' );
			
			// пул теперь только на запись
			$this->aState [$c] = POOL_WRITE;
			// разберем запрос и товетим
			$this->Request ( $c );
			
			return true;
			
		} else {
			
			AsyncServer::say ( "Waiting data...", 'CHECKREQUEST' );
			return false;
			
		}
	
	}
	
	// пишем клиенту
	function onWriteEvent($rSocket, $args) {
		
		$c = $args [0];
		AsyncServer::say ( "Write [{$c}].", 'WRITE' );
		// записали и закрыли коннект.
		if ($this->aState [$c] == POOL_WRITE) {
			$this->CloseConnection ( $c );
		}
	
	}
	
	// обработка ошшибок. бывают же. например по таймауту отвалить надо.
	function onFailureEvent($rSocket, $iError, $args) {
		
		$c = $args [0];
		
		if ($iError & EVBUFFER_READ)
			AsyncServer::say ( "Error READ on [{$c}]...", 'FAILURE' );
		
		if ($iError & EVBUFFER_WRITE)
			AsyncServer::say ( "Error WRITE on [{$c}]...", 'FAILURE' );
		
		if ($iError & EVBUFFER_EOF)
			AsyncServer::say ( "EOF", 'FAILURE' );
		if ($iError & EVBUFFER_ERROR)
			AsyncServer::say ( "ERROR", 'FAILURE' );
		if ($iError & EVBUFFER_TIMEOUT)
			AsyncServer::say ( "TIMEOUT", 'FAILURE' );
		
		// закроем коннект
		$this->CloseConnection ( $c );
	
	}
	
	// закрыть коннект
	function CloseConnection($c) {
		
		// отрубим буфер
		event_buffer_disable ( $this->aBuffers [$c], EV_READ | EV_WRITE );
		AsyncServer::say ( "Buffer disable [{$c}]" );
		// освободим.
		event_buffer_free ( $this->aBuffers [$c] );
		AsyncServer::say ( "Buffer free [{$c}]" );
		unset ( $this->aBuffers [$c] );
		
		// закроем коннект
		fclose ( $this->aConnections [$c] );
		AsyncServer::say ( "Close connection [{$c}]" );
		
		// освободим
		unset ( $this->aConnections [$c] );
		unset ( $this->aState [$c] );
		unset ( $this->aReadPool [$c] );
		unset ( $this->aWritePool [$c] );
		
		AsyncServer::say ( "Free resource [{$c}]" );
	
	}
	
	function Run() {
		
		// включаем евенты на сокеты
		$this->EnableSocketEvents ();
		$this->AddSocketEvents ();
		// слушаем что пришло
		AsyncServer::say ( "Is anybody here?" );
		// ждем-с
		// циклить НЕ надо, т.к. события возвращаются после выполнения
		event_base_loop ( $this->rBaseEvent );
			
	}

}
http.php
PHP:
<?php

require_once 'asyncserver.php';

class HTTPServer extends AsyncServer {
	
}
daemon.php
PHP:
<?php

require_once 'http.php';

$HTTP = new HTTPServer ( );
$HTTP->AddSockets ( array (
		'0.0.0.0' ), 81 );

$HTTP->Run ();
логи выглядят так:

1 консоль.

Код:
hosting(root):/home/440hz/event/http#>telnet localhost 81
Trying 127.0.0.1...
Connected to localhost.440hz.ru.
Escape character is '^]'.
hello

HTTP/1.1 200 OK
Server: HTTPDaemon/1.0
Content-Type: text/html
Content-Length: 27
Connection: close
Accept-Ranges: bytes

[21]
hello<CR><NL><CR><NL>
Connection closed by foreign host.
hosting(root):/home/440hz/event/http#>telnet localhost 81
Trying 127.0.0.1...
Connected to localhost.440hz.ru.
Escape character is '^]'.
Connection closed by foreign host.
2 консоль

Код:
hosting(root):/usr/home#>curl -v "http://localhost:81"
* About to connect() to localhost port 81 (#0)
*   Trying 127.0.0.1... connected
* Connected to localhost (127.0.0.1) port 81 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.16.3 (i386-portbld-freebsd6.3) libcurl/7.16.3 OpenSSL/0.9.7e zlib/1.2.3
> Host: localhost:81
> Accept: */*
>
< HTTP/1.1 200 OK
< Server: HTTPDaemon/1.0
< Content-Type: text/html
< Content-Length: 180
< Connection: close
< Accept-Ranges: bytes
<
[173]
GET / HTTP/1.1<CR><NL>User-Agent: curl/7.16.3 (i386-portbld-freebsd6.3) libcurl/7.16.3 OpenSSL/0.9.7e zlib/1.2.3<CR><NL>
Host: localhost:81<CR><NL>Accept: */*<CR><NL><CR><NL>
* Closing connection #0
лог

Код:
hosting(root):/usr/home/440hz/event/http#>php daemon.php
DAEMON: Create socket [0] [tcp://0.0.0.0:81].
DAEMON: Create new event.
DAEMON: Set event READ to socket [0].
DAEMON: Save socket and event [0] into Daemon.
DAEMON: Set [0] event base.
DAEMON: Event [0] add.
DAEMON: Is anybody here?
DAEMON: AcceptEvent [0].
DAEMON: Connection form [127.0.0.1:54641].
DAEMON: New buffer created.
DAEMON: Set buffer to base.
DAEMON: Set timeout(s).
DAEMON: Buffer enable.
WRITE: Write [0].
READ: Reading from [0] [143]/[143] ...
CHECKREQUEST: Ok.
REQUEST: Processing [0]...
WRITE: Write [0].
DAEMON: Buffer disable [0]
DAEMON: Buffer free [0]
DAEMON: Close connection [0]
DAEMON: Free resource [0]
DAEMON: AcceptEvent [0].
DAEMON: Connection form [127.0.0.1:54591].
DAEMON: New buffer created.
DAEMON: Set buffer to base.
DAEMON: Set timeout(s).
DAEMON: Buffer enable.
WRITE: Write [1].
READ: Reading from [1] [7]/[7] ...
CHECKREQUEST: Waiting data...
READ: Reading from [1] [9]/[2] ...
CHECKREQUEST: Ok.
REQUEST: Processing [1]...
WRITE: Write [1].
DAEMON: Buffer disable [1]
DAEMON: Buffer free [1]
DAEMON: Close connection [1]
DAEMON: Free resource [1]
DAEMON: AcceptEvent [0].
DAEMON: Connection form [127.0.0.1:59182].
DAEMON: New buffer created.
DAEMON: Set buffer to base.
DAEMON: Set timeout(s).
DAEMON: Buffer enable.
WRITE: Write [2].
FAILURE: Error READ on [2]...
FAILURE: TIMEOUT
DAEMON: Buffer disable [2]
DAEMON: Buffer free [2]
DAEMON: Close connection [2]
DAEMON: Free resource [2]
 

Wicked

Новичок
440hz
лично я не очень понял, что ты этим хотел сказать :) просто выложил результаты эксперимента и код для остальных, чтобы тоже могли поиграться?
 
Сверху