研究了3周吧,本来打算用pthreads+event扩展的,结果event扩展太原始了,太多函数了,实在不知道怎么在外部随时发送数据给客户端,所以改用libevent,

改用libevent之后花了2个小时就运行起来了。

当然并不敢说稳定,而且有个地方用了一个“适应”bug的地方,避免bug

两个扩展都从pecl.php.net下载就可以了,

安装,不想写了,16:25了还没吃早饭 午饭

上代码,欢迎讨论:

我的QQ群:

PHPer&Webgame&移动开发,群号:95303036

<?php
class statWorker extends Worker {
public function __construct() { }
public function run(){
while(!$this->isShutdown()){
sleep(3);
}
}
}
class sendAllWorker extends Worker {
public function __construct(&$_logicWorker) {
$this->logicWorker = $_logicWorker;
}
public function run(){ }
}
class data extends Stackable{
public function __construct() {
echo __FILE__.'-'.__LINE__.'<br/>'.chr(10);
}
public function run(){
echo __FILE__.'-'.__LINE__.'<br/>'.chr(10);
}
}
class logicWorker extends Worker{
public $data;
public function __construct(&$_data) {
echo __FILE__.'-'.__LINE__.'<br/>'.chr(10);
$this->data = $_data;
}
public function run(){
$data = $this->data;
$count=0;
while(1){
if($arr =(array) $this->shift()){
echo __FILE__.'-'.__LINE__.'<br/>'.chr(10);
if(!$arr) continue;
if(isset($arr[0])){
echo $arr[0].' from '.$arr[1].chr(10);
//$data[] = array('You say:'.$arr[0], $arr[1]%2==0?0:$arr[1]);
$data[] = array('You say:'.$arr[0], 0);
} if((++$count)%1000==0){
printf("Work Mermory used %.3fMB RAM, time: %3f===> %d \n",
memory_get_peak_usage(true)/1048576, (microtime(true) - $stime), $count);
$stime = microtime(true);
}
}else usleep(100000);
}
}
}
class listenerWorkerRunner extends Worker {
public function __construct(&$_listener){
$this->listener = $_listener;
} public function run(){
$this->listener->dispatch();
}
}
class senderWorker extends Worker {
public function __construct(&$_data, &$clients) {
$this->data = $_data;
$this->clients = $clients;
}
public function run(){
echo __FILE__.'-'.__LINE__.'<br/>'.chr(10);
$data = $this->data;
$clients = $this->clients;
while(1)
{
$arr= $data->shift();
if($arr){
$id = $arr[1];
$msg = $arr[0];
echo '===================================senderWorker GOT: '.trim($msg).' from '.$id.chr(10);
//var_dump($clients);
if(is_array($id))
foreach($id as $i)
fwrite($clients[$i], $msg);
else if($id===0){
//必须这样,否则会报错,$clients的最后一个成员会变成 resource(2) of type (unknown)
$_clients = (array) $clients;
var_dump($_clients);
foreach($_clients as $i=>$c)
fwrite($clients[$i], $msg);
}else
if($clients[$id]) fwrite($clients[$id], $msg);
}else{
//echo 'senderWorker IS RUNNING...'.chr(10);
usleep(100000);
}
}
}
} class epoll{
private static $socket;
public static $connections;
private static $buffers;
private static $worker;
private static $clients;
function epoll($port, &$worker, &$clients){
self::$clients = $clients;
self::$worker = $worker;
if($port<1024) die("Port must be a number which bigger than 1024\n");
self::$socket = stream_socket_server ('tcp://0.0.0.0:'.$port, $errno, $errstr);
stream_set_blocking(self::$socket, 0);
$base = event_base_new();
$event = event_new();
event_set($event, self::$socket , EV_READ | EV_PERSIST, 'epoll::ev_accept', $base);
event_base_set($event, $base);
event_add($event);
event_base_loop($base); self::$connections = array();
self::$buffers = array();
}
public static function ev_accept($socket, $flag, $base) {
static $id = 0; $connection = stream_socket_accept($socket);
stream_set_blocking($connection, 0); $id += 1; $buffer = event_buffer_new($connection, 'epoll::ev_read', NULL, 'epoll::ev_error', $id);
event_buffer_base_set($buffer, $base);
event_buffer_timeout_set($buffer, 30, 30);
event_buffer_watermark_set($buffer, EV_READ, 0, 0xffffff);
event_buffer_priority_set($buffer, 60);//超时自动断开时间
event_buffer_enable($buffer, EV_READ | EV_PERSIST); // we need to save both buffer and connection outside
self::$connections[$id] = $connection;
self::$clients[$id] = $connection;
self::$buffers[$id] = $buffer; echo 'In-> $id='.$id.',$connection='.$connection."\n";
}
public static function ev_error($buffer, $error, $id) {
event_buffer_disable(self::$buffers[$id], EV_READ | EV_WRITE);
event_buffer_free(self::$buffers[$id]);
echo 'Ot-> $id='.$id."\n";
fclose(self::$connections[$id]);
unset(self::$buffers[$id], self::$connections[$id], self::$clients[$id]);
}
public static function ev_read($buffer, $id) {
static $ct=0;
while ($read = event_buffer_read($buffer, 256))
{
$ct+=strlen($read);
if(strpos($read,'ct')!==false) echo 'Ct=>'.count(self::$connections).'\n';
self::$worker[] = array($read, $id);
}
}
//--------------------------------------------
//will not work!!
public static function sendMsg($msg, $id){
if(is_array($id))
foreach($id as $i)
fwrite(self::$clients[$i], $msg);
else if($id===0)
foreach($id as $i)
fwrite(self::$clients[$i], $msg);
else
fwrite(self::$clients[$id], $msg);
}
} //暂未使用,计划用于统计在线之类的
$_statWorker = new statWorker();
$_statWorker->start(); /*
$_logicWorker 处理数据后通过$data传给$_senderWorker下发
因为worker stackable 似乎都不能共享变量(他们接收到的参数——通过worker[]=...,stackable=[],worker->stack几个方式收到的数据都是复制的,并且资源复制不成功,是null,通过public方法设定的参数同样是复制的,只有construct构造函数接收的参数才可以以引用的)
我了解到的是要给worker共享数据,只能通过给其构造函数传递一个stackable(传worker)类型的变量
*/
$data = new data(); //保存连接的客户端,epoll::sendMsg不会正常工作,在里面获取不到self::$clients,也只能通过向构造函数传递stackable变量的方法实现;是为什么我不知道,可能我的用法不对。
$clients = new data(); /*
处理接收上来的数据,比如查看背包,收取邮件,或者战斗 ,行走,但里面不要进行任何io操作——读写数据库甚至是memcache都不可以
logicWorker只做计算型工作,并且是主要的工作线程
那么你可能要问,用户的数据从哪里来?如何保存?
——答案是用别的线程,至少还需要2个线程:登陆线程,从数据库读数据;存档线程,把数据存放到数据。
这样工作按线程分开了,能够有一定并发数, 是多少,不知道,我目前的java程序就是这个方式,单服3000+在线,负载不到1,cpu 20%左右。
php可能要差一点儿 当然这个pthreads应该可以用很不稳定来形容,很容易coredump……,不过怎么都算是个进步吧,因为真的实现了多线程。
*/
$_logicWorker = new logicWorker($data);
/*
负责下发数据,其实,可以由$_logicWorker来执行,我这里主要是想测试数据共享,
*/
$_senderWorker = new senderWorker($data, $clients); //启动线程和监听
$_logicWorker->start();
$_senderWorker->start();
new epoll(9808, $_logicWorker, $clients); echo 'Running ... ---------->
';

我的QQ群:

PHPer&Webgame&移动开发,群号:95303036

加群除了提问之外,请记得帮助别人,谢谢。

一个高在线(可以超过1024)多线程的socket echo server(pthreads 和 libevent扩展)的更多相关文章

  1. day36——死锁、递归锁、信号量、GIL、多线程实现socket通信、线程池和进程池

    day36 死锁现象与递归锁 死锁现象 是指两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去.此时称系统处于死锁状态或系统产生了死锁,这 ...

  2. 《Unity 3D游戏客户端基础框架》多线程异步 Socket 框架构建

    引言: 之前写过一个 demo 案例大致讲解了 Socket 通信的过程,并和自建的服务器完成连接和简单的数据通信,详细的内容可以查看 Unity3D -- Socket通信(C#).但是在实际项目应 ...

  3. SpringCloud学习系列之一 ----- 搭建一个高可用的注册中心(Eureka)

    前言 本篇主要介绍的是SpringCloud相关知识.微服务架构以及搭建一个高可用的服务注册与发现的服务模块(Eureka). SpringCloud介绍 Spring Cloud是在Spring B ...

  4. 打造一个高逼格的android开源项目——小白全攻略 (转)

    转自:打造一个高逼格的android开源项目 小引子 在平时的开发过程中,我们经常会查阅很多的资料,最常参考的是 github 的开源项目.通常在项目的主页面能看到项目的简介和基本使用,并且时不时能看 ...

  5. PHP如何打造一个高可用高性能的网站呢?

    https://blog.csdn.net/jwq101666/article/details/80162245 1. 说到高可用的话要提一下redis,用过的都知道redis是一个具备数据库特征的n ...

  6. 如何快速开发出一个高质量的APP——创业谈

    [起] 今早,一个技术群里有人想快速做出一个app,然后询问技术方案,大概是这样, 拿到了200w投资,期望花20w两个月先做出一个app,包括iOS,Android, 先,呵呵,一下, 大概预估了一 ...

  7. 【转】一个高端.NET技术人才的2014年度总结

    [转]一个高端.NET技术人才的2014年度总结  本人在一家公司做技术负责人.主要从事的是.net方面的开发与管理,偏重开发. 弹指一挥间,时间飘然而过,转眼又是一年. 回顾2014年,是我人生中最 ...

  8. 【创业积累】如何快速开发出一个高质量的APP

    [起] 今早,一个技术群里有人想快速做出一个app,然后询问技术方案,大概是这样, 拿到了200w投资,期望花20w两个月先做出一个app,包括ios,android, 先,呵呵,一下, 大概预估了一 ...

  9. VopSdk一个高逼格微信公众号开发SDK(源码下载)

    看之前回复很多说明大家很有热情&文章被误删掉了,不想让有的朋友错失这个高逼格的东西,现在重新发布,这次就直接放出源码,文章最末下载地址. 看之前回复很多说明大家很有热情&文章被误删掉了 ...

随机推荐

  1. android电池管理系统从上层的java到底层驱动的调用(转载)

    1.概述 随着移动智能设备的快速发屏,电池的续航能力在很大情况下诱导了大众消费者的购买选择,android系统对电源管理的合理与否直接影响到电池的续航能力,而电池系统作为其中的一部分,主要用于对电池状 ...

  2. poj1265Area(pick定理)

    链接  Pick定理是说,在一个平面直角坐标系内,如果一个多边形的顶点全都在格点上,那么这个图形的面积恰好就等于边界上经过的格点数的一半加上内部所含格点数再减一. pick定理的一些应用 题意不好懂, ...

  3. 了解OpenStack

    OpenStack是一个由NASA(美国国家航空航天局)和Rackspace合作研发并发起的,以Apache许可证授权的自由软件和开放源代码项目. OpenStack支持几乎所有类型的云环境,项目目标 ...

  4. WDS 的两种实现方式

    转自:http://blog.chinaunix.net/uid-26527046-id-3627627.html WDS 的两种实现方式 WDS(Wireless Distribution Syst ...

  5. 5.2 i++

    答案:第一段21,第二段12 PS:注意运算符的优先级. 答案:A

  6. B树索引

    在SQL Server中,索引是一种增强式的存在,这意味着,即使没有索引,SQL Server仍然可以实现应有的功能.但索引可以在大多数情况下大大提升查询性能高.在OLAP中尤其明显,要完全理解索引的 ...

  7. [css] 认识margin

    原文链接http://www.zhangxinxu.com/wordpress/2009/08/css-margin%E7%9A%84%E7%9B%B8%E5%85%B3%E5%B1%9E%E6%80 ...

  8. C#_DataTable导出Execl为自定义标题

    public bool ExportExcel(DataTable tb, string path, string tbName) { //excel 2003格式 string connString ...

  9. 向java全台推送数据等

    (1)http://www.cnblogs.com/xdp-gacl/p/3789624.html (2)VenusWebHelper  等等 public void test(){ String f ...

  10. easyui dialog

    <!--弹出“创建”窗口 --> <div id="dialog" class="easyui-dialog" title="创建机 ...