<?php

class PHPSocketServer
{
const ERROR = 0;
const LOG = 1;
const DEBUG = 2; private $aConfig = NULL;
private $hSocket = NULL;
private $aClients = array();
private $iRunning = 0;
private $iStartTime = 0;
private $iLastActivity = 0; private static $aDefaults = array
(
'main' => array
(
'address' => 'localhost',
'port' => 15151,
'backlog' => 200,
'select_timeout' => 1,
'pid_file' => 'phpserver.pid'
), 'verbosity' => array
(
'echo_log' => 1,
'echo_debug' => 0,
'echo_errors' => 1,
'log_errors' => 1
)
); public function getPidFile()
{
return $this->aConfig['main']['pid_file'];
} private static function getName( $hSocket )
{
return socket_getpeername( $hSocket, $sAddress, $iPort ) ? "$sAddress:$iPort" : "?????:???";
} private function log( $sMessage, $iType )
{
$sTimeStamp = @strftime( '%c' ); if( $iType == self::ERROR )
{
$aBacktrace = debug_backtrace();
$aBacktrace = $aBacktrace[1];
$sMessage = sprintf( '[%s] [E] %s%s%s [%d] : %s', $sTimeStamp, $aBacktrace['class'], $aBacktrace['type'], $aBacktrace['function'], $aBacktrace['line'], $sMessage ); if( $this->aConfig['verbosity']['echo_errors'] )
printf( "$sMessage\n" ); if( $this->aConfig['verbosity']['log_errors'] )
error_log( $sMessage );
}
else if( $iType == self::DEBUG && $this->aConfig['verbosity']['echo_debug'] )
{
echo sprintf( '[%s] [D] : %s', $sTimeStamp, $sMessage )."\n";
}
else if( $iType == self::LOG && $this->aConfig['verbosity']['echo_log'] )
{
echo sprintf( '[%s] [L] : %s', $sTimeStamp, $sMessage )."\n";
}
} /*
* Handle clients here.
*/
private function handleClientRequest( $hClient, $iClientIndex )
{
/*
* ...
*/ $this->disconnect( $iClientIndex );
} private function disconnect( $i )
{
socket_close( $this->aClients[ $i ] );
$this->aClients[ $i ] = NULL;
} private function loadConfiguration( $sConfigFile )
{
if( !is_file( $sConfigFile ) || !is_readable( $sConfigFile ) )
die( "Could not read $sConfigFile.\n" ); else if( !( $this->aConfig = parse_ini_file( $sConfigFile, TRUE ) ) )
die( "Could not parse $sConfigFile.\n" ); foreach( self::$aDefaults as $sSection => $aDefaultValues )
{
if( !isset( $this->aConfig[ $sSection ] ) )
$this->aConfig[ $sSection ] = array(); foreach( $aDefaultValues as $sName => $sValue )
{
if( !isset( $this->aConfig[ $sSection ][ $sName ] ) )
$this->aConfig[ $sSection ][ $sName ] = $sValue;
}
}
} public function setConfig( $sSectionName, $sConfigName, $mValue )
{
if( !isset( $this->aConfig[ $sSectionName ] ) )
$this->aConfig[ $sSectionName ] = array(); $this->aConfig[ $sSectionName ][ $sConfigName ] = $mValue;
} public function __construct( $sConfigFile )
{
$this->loadConfiguration( $sConfigFile ); if( !( $this->hSocket = socket_create( AF_INET, SOCK_STREAM, SOL_TCP ) ) )
$this->log( 'Could not create main socket ( '.socket_strerror( socket_last_error() ).' ).', self::ERROR ); else if( socket_set_option( $this->hSocket, SOL_SOCKET, SO_REUSEADDR, 1 ) === FALSE )
$this->log( 'Could not set SO_REUSEADDR flag ( '.socket_strerror( socket_last_error() ).' ).', self::ERROR );
} public function start()
{
if( !socket_bind( $this->hSocket, $this->aConfig['main']['address'], $this->aConfig['main']['port'] ) )
$this->log( 'Could not bind on '.$this->aConfig['main']['address'].':'.$this->aConfig['main']['port'].' ( '.socket_strerror( socket_last_error() ).' ).', self::ERROR ); else if( !socket_listen( $this->hSocket, $this->aConfig['main']['backlog'] ) )
$this->log( 'Could not put main socket in listening mode ( '.socket_strerror( socket_last_error() ).' ).', self::ERROR ); else if( !socket_set_nonblock( $this->hSocket ) )
$this->log( 'Could not set main socket in non-blocking mode ( '.socket_strerror( socket_last_error() ).' ).', self::ERROR ); else
{
$this->iStartTime = time(); $this->log( 'Server started on '.$this->aConfig['main']['address'].':'.$this->aConfig['main']['port'].' .', self::LOG ); for(;;)
{
$aRead = array_merge( array( $this->hSocket ), $this->aClients ); if( socket_select( $aRead, $aWrite, $aExcept, $this->aConfig['main']['select_timeout'] ) )
{
if( in_array( $this->hSocket, $aRead ) )
{
if( ( $hClient = @socket_accept( $this->hSocket ) ) )
{
$this->aClients[ microtime(TRUE) ] = $hClient;
$this->iLastActivity = time(); $this->log( 'New incoming connection '.self::getName( $hClient ), self::DEBUG );
}
else
$this->log( 'Could not accept a new connection ( '.socket_strerror( socket_last_error() ).' ).', self::ERROR );
}
} /*
* Search for readable clients.
*/
foreach( $this->aClients as $i => $hClient )
{
if( in_array( $hClient, $aRead ) )
{
$this->handleClientRequest( $hClient, $i );
}
} /*
* Remove closed connections.
*/
$this->aClients = array_filter( $this->aClients );
}
}
} public function __destruct()
{
if( $this->hSocket )
{
$this->log( 'Shutting down ...', self::LOG ); foreach( $this->aClients as $sId => $hClient )
{
if( $hClient )
socket_close( $hClient );
} socket_close( $this->hSocket );
} @unlink( $this->getPidFile() );
}
} ?>

php非阻塞服务器的更多相关文章

  1. 【IBM】Merlin 给 Java 平台带来了非阻塞 I/O

    Merlin 给 Java 平台带来了非阻塞 I/O 新增的功能大幅降低了线程开销 Java 技术平台早就应该提供非阻塞 I/O 机制了.幸运的是,Merlin(JDK 1.4)有一根几乎在各个场合都 ...

  2. Java NIO: Non-blocking Server 非阻塞网络服务器

    本文翻译自 Jakob Jenkov 的 Java NIO: Non-blocking Server ,原文地址:http://tutorials.jenkov.com/java-nio/non-bl ...

  3. Java NIO 非阻塞Socket服务器构建

    推荐阅读IBM developerWorks中NIO的入门教程,尤其是对块I/O和流I/O不太清楚的开发者. 说到socket服务器,第一反应是java.net.Socket这个类.事实上在并发和响应 ...

  4. 利用Python中SocketServer 实现客户端与服务器间非阻塞通信

    利用SocketServer模块来实现网络客户端与服务器并发连接非阻塞通信 版权声明 本文转自:http://blog.csdn.net/cnmilan/article/details/9664823 ...

  5. 非阻塞tcp服务器与阻塞的tcp服务器对比

    一般的tcp服务器(阻塞)是使用的如下 [erlang] gen_tcp传输文件原型 http://www.cnblogs.com/bluefrog/archive/2012/09/10/267904 ...

  6. 简易非阻塞http服务器

    说明         需要理解阻塞和非阻塞的区别,特别要注意非阻塞和异步不是一个概念,这个很容易弄错.云盘里面netty的书会讲这几个方面的区别,nodejs深入浅出关于异步编程章节里面       ...

  7. 【python】网络编程-SocketServer 实现客户端与服务器间非阻塞通信

    利用SocketServer模块来实现网络客户端与服务器并发连接非阻塞通信.首先,先了解下SocketServer模块中可供使用的类:BaseServer:包含服务器的核心功能与混合(mix-in)类 ...

  8. 第15章 高并发服务器编程(1)_非阻塞I/O模型

    1. 高性能I/O (1)通常,recv函数没有数据可用时会阻塞等待.同样,当socket发送缓冲区没有足够多空间来发送消息时,函数send会阻塞. (2)当socket在非阻塞模式下,这些函数不会阻 ...

  9. tornado-简单的服务器非阻塞

    1.服务器 非阻塞 import tornado.ioloop import tornado.web import tornado.httpserver # 非阻塞 import tornado.op ...

随机推荐

  1. 电脑技巧 如何保存网页为PDF

    安装Adobe Acrobat X pro(要安装版本,不要绿色版),完成之后再打印机里面可以看到添加了新的Adobe PDF打印机   对于任意的Office文档,都可以直接打印到PDF得到PDF文 ...

  2. HDU1069(还是dp基础)

    今天不想说太多废话-由于等下要写自己主动提交机. 不知道能不能成功呢? 题目的意思就是,一个猴子,在叠砖头 ...以下的要严格大于上面的.求叠起来最高能到多少- n非常少,n^2算法毫无压力-话说dp ...

  3. Shiro整合springboot,freemaker,redis(含权限系统完整源码)

    区块链技术联盟 2018-02-08 17:06:40 目录 一.导语 二.shiro功能介绍 三.shiro详解 四.shiro实战案例分享 五.系统配置 六.其他 一.导语 今天推荐给大家一个非常 ...

  4. Elasticsearch cluster health: yellow unassigned shards

    查看ES各个分片的状态 $ curl -XGET http://127.0.0.1:9200/_cluster/health?pretty { "cluster_name" : & ...

  5. BIEE Demo(RPD创建 + 分析 +仪表盘 )

    说明:此Demo步骤简略,详细Demo可以参照下面的 天善视频:BIEE 11G Rpd模型设计 天善视频:BIEE 11G 报表开发 Oracle BIEE (Business Intelligen ...

  6. Lucene底层原理和优化经验分享(1)-Lucene简介和索引原理

    Lucene底层原理和优化经验分享(1)-Lucene简介和索引原理 2017年01月04日 08:52:12 阅读数:18366 基于Lucene检索引擎我们开发了自己的全文检索系统,承担起后台PB ...

  7. Android开发之使用HttpURLConnection进行POST请求

    一.前提准备 在开始实际编码之前,我们有必要先了解下将会用的类以及方法,进行一个大体的了解. 1.URL类 这个类主要的功能是定位到要获取资源的网址以及打开连接.比如下面的代码: URL realur ...

  8. appium环境搭建参考

    别人的安装经验,如果再遇到问题可以参考: http://www.cnblogs.com/fnng/p/4540731.html

  9. 合并果子(NOIP2004)

    合并果子(NOIP2004)[问题描述]在一个果园里,多多已经将所有的果子打了下来,而且按果子的不同种类分成了不同的堆.多多决定把所有的果子合成一堆.每一次合并,多多可以把两堆果子合并到一起,消耗的体 ...

  10. [转载]eclipse自动同步插件filesync的使用

    原文地址:eclipse自动同步插件filesync的使用作者:老孙丢了金箍棒    这篇文章和之前我写的<eclipse下自动部署WEB项目>根本目的是一样的,只是达到目的的方式不同. ...