研究了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. 13 SELECT 以外的内容

    Insert 直接路径法 这种方法不去查找已有块中的空间, 它直接从高水位之上开始插入数据. 直接使用的是 nologging模式, 记住默认情况下通过直接路径插入进行加载的表上的索引仍然是会产生un ...

  2. getAttribute()方法的使用小笔记

    今天在某课网上复习js,突然卡在一个小例子上.反复做了几遍就是报错.终于查询w3c才找到错误的源头. 这里记录一下,谨防以后又忘了. 错误码: <body> <p id=" ...

  3. poj3855Blast the Enemy!(多边形重心)

    链接 #include <iostream> #include<cstdio> #include<cstring> #include<algorithm> ...

  4. ORA-00205

    场景 数据库启动时报错.关闭前还是正常运行的,再次启动时,就报了以下错误. Copyright (c) , , Oracle. All rights reserved. Connected to an ...

  5. samba服务器搭建

    为实现windows与linux资源共享,搭建一个samba服务器:这个我也是探索了一段时间. 找到一篇写得比较清楚的博客: http://yangxuejun.blog.51cto.com/6239 ...

  6. SqlServer扩展存储过程

    1. 扩展存储过程xp_cmdshell用法: --1.启用 SP_CONFIGURE RECONFIGURE GO SP_CONFIGURE RECONFIGURE GO --2.用法 master ...

  7. 关于电脑玩MT以及多开的方法

    方法是转的别人的首先感谢原创者!!上四开屏幕截图,因为小伙伴需要8张卡,所以我四个四个一起练.8开我的电脑估计都有压力,五开六开可能没问题,但是为了方便就四开,练完四个再练四个.图接下来说下多开模拟器 ...

  8. 苹果审核Metadata Rejected

    最近提交了 公司的一个 app,收到了appStore拒绝的信息及邮件 拒绝后的状态改为了:metadata rejected 邮件里面有这样一句话 意思大致就是: 你的app先被显示为 Metada ...

  9. java 多线程4(死锁)

    死锁现象: 死锁原因: 1.存在两个或两个以上的线程. 2.存在两个或两个或两个以上的共享资源. 死锁现象解决的方案: 没有方案只能尽量避免.

  10. 委托(C# 编程指南)

    原文地址:https://msdn.microsoft.com/zh-cn/library/ms173171.aspx delegate 是表示对具有特定参数列表和返回类型的方法的引用的类型. 在实例 ...