php非阻塞服务器
<?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非阻塞服务器的更多相关文章
- 【IBM】Merlin 给 Java 平台带来了非阻塞 I/O
Merlin 给 Java 平台带来了非阻塞 I/O 新增的功能大幅降低了线程开销 Java 技术平台早就应该提供非阻塞 I/O 机制了.幸运的是,Merlin(JDK 1.4)有一根几乎在各个场合都 ...
- Java NIO: Non-blocking Server 非阻塞网络服务器
本文翻译自 Jakob Jenkov 的 Java NIO: Non-blocking Server ,原文地址:http://tutorials.jenkov.com/java-nio/non-bl ...
- Java NIO 非阻塞Socket服务器构建
推荐阅读IBM developerWorks中NIO的入门教程,尤其是对块I/O和流I/O不太清楚的开发者. 说到socket服务器,第一反应是java.net.Socket这个类.事实上在并发和响应 ...
- 利用Python中SocketServer 实现客户端与服务器间非阻塞通信
利用SocketServer模块来实现网络客户端与服务器并发连接非阻塞通信 版权声明 本文转自:http://blog.csdn.net/cnmilan/article/details/9664823 ...
- 非阻塞tcp服务器与阻塞的tcp服务器对比
一般的tcp服务器(阻塞)是使用的如下 [erlang] gen_tcp传输文件原型 http://www.cnblogs.com/bluefrog/archive/2012/09/10/267904 ...
- 简易非阻塞http服务器
说明 需要理解阻塞和非阻塞的区别,特别要注意非阻塞和异步不是一个概念,这个很容易弄错.云盘里面netty的书会讲这几个方面的区别,nodejs深入浅出关于异步编程章节里面 ...
- 【python】网络编程-SocketServer 实现客户端与服务器间非阻塞通信
利用SocketServer模块来实现网络客户端与服务器并发连接非阻塞通信.首先,先了解下SocketServer模块中可供使用的类:BaseServer:包含服务器的核心功能与混合(mix-in)类 ...
- 第15章 高并发服务器编程(1)_非阻塞I/O模型
1. 高性能I/O (1)通常,recv函数没有数据可用时会阻塞等待.同样,当socket发送缓冲区没有足够多空间来发送消息时,函数send会阻塞. (2)当socket在非阻塞模式下,这些函数不会阻 ...
- tornado-简单的服务器非阻塞
1.服务器 非阻塞 import tornado.ioloop import tornado.web import tornado.httpserver # 非阻塞 import tornado.op ...
随机推荐
- [Functional Programming] Using JS, FP approach with Arrow or State Monad
Using Naive JS: const {modify, get} = require('crocks/State'); const K = require('crocks/combinators ...
- 【mybatis】多次查询缓存的问题
转自:http://cheng-xinwei.iteye.com/blog/2021700?utm_source=tuicool&utm_medium=referral 最近在使用mybati ...
- GitHub没有实时通知怎么办?当然是自己上手写一个啊!
相信各位程序员对github已经不陌生了.不知道各位有没有注意到GitHub没有推送通知这个功能.当有人在我的存储库中创建了一个提取请求/问题时,我可以收到电子邮件通知,但当有人stars/forks ...
- iOS SDK 从配置文件里读SDK。转化成class 可同时加载多个SDK
首先在工程中加入XXX plist 配置文件. 然后在key 输入名字比如allsdk value 里填写.a 文件的名字 NSString *plistPath = [[NSBundle mai ...
- Core Java-多线程-线程的生命周期
0. 在介绍线程前我们先看一下什么是进程? 进程是线程的母亲,如果在大学计算机课程里读过操作系统一定不会陌生. 所谓进程,它是计算机程序关于某数据集上的一次活动,是系统进行资源分配和调度的基本单位,是 ...
- 获取js连接参数js_args
获取js连接参数,如下以链接: <script src="js/jscript.js?skin=green" type="text/javascript" ...
- 微信小程序 - 自定义swiper dots样式(非组件)
自定义须知: :组件内无法使用自定义样式变化,需要自定义 :原理就是利用swiper change事件与下标index匹配,显示不同的样式 swiper组件须知: :一旦swiper用于组件化,就 ...
- 创新大师Steve Blank: 你真的知道什么是真正的精益创业吗?
编者注:本文来自被誉为当代创新大师的Steve Blank的博客. 中文版由天地会珠海分舵编译. 全文从当今非常多人对精益创业的误解作为一个切入点,深入的分析了为什么人们这么easy就对精益创业产生误 ...
- Ant脚本简介与基础知识
转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/6624003.html 一:Ant是什么 Ant相当于Linux环境下的shell脚本,只不过是用xml文档来 ...
- Nginx server之Nginx添加ssl支持
//环境介绍 1.nginx服务器:10.10.54.157 2.配置nginx服务器,当监听到来自客户端www.zijian.com:80请求时,转到10.10.54.150:1500这个web服务 ...