如何在tomcat7下,使用ajax连接activemq ajax demo

workerman源码分析之启动过程 - 推酷
workerman源码分析之启动过程
PHP一直以来以草根示人,它简单,易学,被大量应用于web开发,非常可惜的是大部分开发都在简单的增删改查,或者加上pdo,redis等客户端甚至分布式,以及规避语言本身的缺陷。然而这实在太委屈PHP了。记得有一次问walker,PHP能做什么?他说:什么都能做啊!当时我就震惊了,这怎么可能。。。直到后来一直看workerman源码,发现PHP原来有很多不为大家所知的诸多用法,包括多进程(还有线程)、信号处理、namespace等等一大堆特点。而workerman正是这些很少被使用特性(或者说扩展)的集大成者,如果非要说它的缺点,那就是PHP的缺点了,当然PHP的优点它全占了~而且PHP7发布在即,workerman必将得到更多的优化,搭配HHVM更是叼的不行。
版本:3.1.8(linux)
模型:GatewayWorker(Worker模型可与之类比)
注:只贴出讲解部分代码,出处以文件名形式给出,大家可自行查看
workerman最初只开发了Linux版本,win是后来增加的,基于
多进程模型
工作进程,Master、Gateway和Worker,Gateway主要用于处理IO事件,保存客户端链接状态,将数据处理请求发送给Worker等工作,Worker则是完全的业务逻辑处理,前者为IO密集型,后者为计算密集型,它们之间通过网络通信,Gateway和Worker两两间注册通信地址,所以非常方便的进行分布式部署,如果业务处理量大可以单纯的增加Worker服务。
它们有一个负责监听的父进程(Master),监听子进程状态,发送 signal 给子进程,接受来自终端的命令、信号等工作。父进程可以说是整个系统启动后的入口。
启动命令解析
既然以命令模式(cli)运行(注意与 fpm 的区别,后者处理来自网页端的请求),就必然有一个启动脚本解析命令,譬如说3.x版本(之前默认为daemon)新增一个 -d 参数,以表示守护进程运行,解析到该参数设置 self::$daemon = true, 随后fork子进程以脱离当前进程组,设置进程组组长等工作。这里有两个非常重要的参数 $argc 和 $argc,前者表示参数个数,后者为一个数组,保存有命令的所有参数,比如:sudo php start.php start -d,$argv就是 array( [0]=&start.php, [1]=&start, [2]=&-d ),而解析主要用到$argv。
启动主要执行下面步骤:
,加载各 Application 下启动文件;
设置&_appInitPath 根目录;
解析,初始化参数,执行相应命令。
下面是具体实现(workerman/worker.php):
public static function parseCommand()
// 检查运行命令的参数
$start_file = $argv[0];
$command = trim($argv[1]);
// 子命令,目前只支持-d
$command2 = isset($argv[2]) ? $argv[2] : '';
// 检查主进程是否在运行
$master_pid = @file_get_contents(self::$pidFile);
$master_is_alive = $master_pid && @posix_kill($master_pid, 0);
if($master_is_alive)
if($command === 'start')
self::log(&Workerman[$start_file] is running&);
elseif($command !== 'start' && $command !== 'restart')
self::log(&Workerman[$start_file] not run&);
// 根据命令做相应处理
switch($command)
// 启动 workerman
case 'start':
if($command2 === '-d')
Worker::$daemonize =
// 显示 workerman 运行状态
case 'status':
// 重启 workerman
case 'restart':
// 停止 workeran
case 'stop':
// 想主进程发送SIGINT信号,主进程会向所有子进程发送SIGINT信号
$master_pid && posix_kill($master_pid, SIGINT);
// 如果 $timeout 秒后主进程没有退出则展示失败界面
$timeout = 5;
$start_time = time();
// 检查主进程是否存活
$master_is_alive = $master_pid && posix_kill($master_pid, 0);
if($master_is_alive)
// 检查是否超过$timeout时间
if(time() - $start_time &= $timeout)
self::log(&Workerman[$start_file] stop fail&);
usleep(10000);
self::log(&Workerman[$start_file] stop success&);
// 是restart命令
if($command === 'stop')
// -d 说明是以守护进程的方式启动
if($command2 === '-d')
Worker::$daemonize =
// 平滑重启 workerman
case 'reload':
walker代码注释已经非常详尽,下面有几点细节处:
检查主进程是否存活:17行的逻辑与操作,如果主进程PID存在情况下,向该进程发送信号0,实际上并没有发送任何信息,只是检测该进程(或进程组)是否存活,同时也检测当前用户是否有权限发送系统信号;
为什么主进程PID会保存?系统启动后脱离当前terminal运行,如果要执行关闭或者其他命令,此时是以另外的一个进程执行该命令,如果我们连进程PID都不知道,那该向谁发信号呢?!所以主进程PID必须保存起来,而且主进程负责监听其他子进程,所以它是我们继续操作的入口。
Worker::runAll()
php的socket编程其实和C差不多,后者对socket进行了再包裹,并提供接口给php,在php下网络编程步骤大大减少。譬如:
直接创建了server/client socke(php有两套socket操作函数)。wm则大量使用了前者,启动过程如下(注释已经非常详尽):
public static function runAll()
// 初始化环境变量
self::init();
// 解析命令
self::parseCommand();
// 尝试以守护进程模式运行
self::daemonize();
// 初始化所有worker实例,主要是监听端口
self::initWorkers();
初始化所有信号处理函数
self::installSignal();
// 保存主进程pid
self::saveMasterPid();
// 创建子进程(worker进程)并运行
self::forkWorkers();
// 展示启动界面
self::displayUI();
// 尝试重定向标准输入输出
self::resetStd();
// 监控所有子进程(worker进程)
self::monitorWorkers();
下面还是只说该过程的关键点:
初始化环境变量,例如设置主进程名称、日志路径,初始化定时器等等;
解析命令行参数,主要用到 $argc 和 $argc 用法同C语言;
生成守护进程,以脱离当前终端(两年前大部分认为PHP无法做daemon,其实这是个误区!其实PHP在linux的进程模型很稳定,现在wm在商业的应用已经非常成熟,国内某公司每天处理几亿的连接,用于订单、支付调用,大家可以打消顾虑了);
初始化所有worker实例(注意,这里是在主进程做的,只是生成了一堆 server 并没有设置监听,多进程模型是在子进程做的监听,即IO复用);
为主进程注册信号处理函数;
保存主进程PID,当系统运行后,我们在终端查看系统状态或者执行关闭、重启命令,是通过主进程进行通信,所以需要知道主进程PID,我们知道在终端下敲入一个可执行命令,实则是在当前终端下新建一个子进程来执行,所以我们需要得知主进程PID,以向WM主进程发送SIGNAL,这时信号处理函数捕获该信号,并通过回调方式执行。
创建子进程,设置当前进程用户(root)。在多进程模型中,两给子进程,分别监听不同的server地址,我们在主进程只是创建server并没有设置监听,也没有生成指定数目的server,原因在于,我们在一个进程多次创建同一个 socket, woker数目其实就是 socket 数量,也就是该 socket 的子进程数目,否则会报错;
在子进程中,将 server socket 注册监听事件,用到一个扩展
,可以实现IO复用,并注册数据读取回调,同时也可注册socket连接事件回调;
输入输出重定向;
主进程监听子进程状态,在一个无限循环中调用 pcntl_signal_dispatch() 函数,用于捕获子进程退出状态,该函数会一直阻塞,直到有子进程退出时才触发;
至此,一个完整的启动过程大致处理完成,然后 server 会一直运行,一直等待 socket 连接事件,等待数据可读可写事件,通过事先注册的处理函数,就能完整的处理整个网络过程。
其实网络编程过程大致都差不多,这些都有标准答案,每个语言实现的大致过程基本相同,当然类似 golang 的 goroutine 另说。。。需要了解应用层协议(如果可能,需要手动解包和封包),网络模型,TCP/UDP,进程间通信,IO复用等等,当然最重要的是会 debug。。。自己动手尝试写一个简单的 server 就会遇到很多无法遇见的坑,所以纸上得来终觉浅,绝知此事要躬行。
已发表评论数()
请填写推刊名
描述不能大于100个字符!
权限设置: 公开
仅自己可见
正文不准确
标题不准确
排版有问题
主题不准确
没有分页内容
图片无法显示
视频无法显示
与原文不一致输入关键字进行搜索
个人比较菜还望多多指教。目前我们开发了一套微信的应用程序,由于原有程序是放到windows2012的服务器上,所以考虑就把workerman放到了另一台linux服务器上。有几个疑问望大神们帮忙下。例如我使用WebSocket协议对外提供服务,在原有程序上开发的聊天室远程连接workerman的服务器,在微信应用的程序我会判定是否是这个聊天室的成员,包括是否为管理还是普通用户,我在想一个问题,就是微信应用的服务器发送到聊天服务器上是用json进行数据传输的,如果进行全体禁言时候微信应用的服务器会判断是否为管理是否为当前房间的用户,如果按照简单的开发实例在谷歌浏览器里输入:
// 假设服务端ip为127.0.0.1
ws = new WebSocket(&ws://127.0.0.1:2346&);
ws.onopen = function() {
alert(&连接成功&);
ws.send('tom');
alert(&给服务端发送一个字符串:tom&);
ws.onmessage = function(e) {
alert(&收到服务端的消息:& + e.data);
有用户使用恶意行为进行json数据进行更改的话,那么装有workerman的服务器应该如何判断恶意更改的用户是否为管理是否是这个聊天室的成员?
还有就是如果用户知道json数据格式后,这些随意更改房间号接收其他房间的信息或者进行其他踢人的功能,如何避免恶意使用?
我的想法是用户发送信息到workerman服务器后,在微信应用的服务器接收数据时候进行判断是否有相关的权限但是感觉还是有些行不通。还望大神不吝赐教。
建议用GatewayWorker框架,业务实现不在GatewayWorker中做,仅仅把GatewayWorker当作一个单向的推送通道(通过GatewayClient向客户端推送)。这样GatewayWorker与现有项目能很好的解耦,权限控制及其它业务逻辑还是按照项目原有的方法做,仅当需要向客户端主动推送数据时才调用GatewayClient推送数据。
多谢大神 ! 看了你发的这个链接如大梦初醒一般。太方便了!多谢!!!
刚接触了两天看完了workerman
GatewayWorker框架还没看。
大神再请教一个问题
如果把GatewayWorker当做一个单向的推送通道,那如何实现语音实时传输呢?
客户端需要什么格式直接传就行了
大神求指教,GatewayClient和GatewayWorker不是在同一台服务器上,GatewayClient接收数据怎么写?
能否给个例子?
GatewayClient只能发,不能收。单向的
大神求指教,我把GatewayWorker当做一个单向的推送通道,在客户端连接上之后在服务器上的Event.php 写的直接获取客户端的client_id
public static function onConnect($client_id)
// 向当前client_id发送数据
$data = array(
'type' => 'login',
'client_id'=>$client_id
Gateway::sendToClient($client_id,json_encode($data));
然后发送给客户端,客户端接收到信息后发送到应用后端GatewayClient 进行分组 绑定UID 发送登录信息。
由于所建立的是单向的推送通道
服务器上的event.php只写了用户连接上之后发送的业务逻辑其他的业务逻辑都是在另一个应用上写的。但是又碰到难点了,
Gateway::getClientInfoByGroup($roomid);
foreach($clients_list as $tmp_client_id=>$item)
$clients_list[$tmp_client_id] = $item['client_name'];
Object {781ade1d0ba: null, 781ade1d0b: null}
client_id对应的clientname都是为null,如果在服务器上可以session用户名,这作为单项通道如何session存储用户名呢?迷茫了求助
GatewayClient有个Gateway:: updateSession($client_id, $session); 方法,可以后台更改某个client_id的session
要回复问题请先或
关注: 2 人
Powered by输入关键字进行搜索
目前的web项目中要实现服务端向客户端app做主动推送,是用workerman还是gatewayWorker?
app推送gateworker方便些,支持分布式部署,支持多端口多协议,支持在任意项目中推送
协议可以用workerman自带的text协议,一个简单的文本协议,格式就是 文本字符串+换行符 。可以传json + 换行符。
text协议说明
也可以去github上找个websocket库,使用websocket协议
或者自己定义个协议
github上找个websocket库就支持了
要回复问题请先或
关注: 2 人
Powered by

我要回帖

更多关于 activemq tomcat 整合 的文章

 

随机推荐