<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
<channel>
<title><![CDATA[向东博客 专注WEB应用 构架之美 --- 构架之美，在于尽态极妍 | 应用之美，在于药到病除]]></title> 
<link>https://jackxiang.com/index.php</link> 
<description><![CDATA[赢在IT，Playin' with IT,Focus on Killer Application,Marketing Meets Technology.]]></description> 
<language>zh-cn</language> 
<copyright><![CDATA[向东博客 专注WEB应用 构架之美 --- 构架之美，在于尽态极妍 | 应用之美，在于药到病除]]></copyright>
<item>
<link>https://jackxiang.com/post//</link>
<title><![CDATA[ 基于SWOOLE的分布式SOCKET消息服务器架构]]></title> 
<author>jack &lt;xdy108@126.com&gt;</author>
<category><![CDATA[Swoole专题研究]]></category>
<pubDate>Sun, 23 Oct 2016 12:43:46 +0000</pubDate> 
<guid>https://jackxiang.com/post//</guid> 
<description>
<![CDATA[ 
	基于SWOOLE的分布式SOCKET消息服务器架构<br/><br/>作者: hope 时间: October 30, 2014 分类: php<br/>消息服务器使用socket，为避免服务器过载，单台只允许500个socket连接，当一台不够的时候，扩充消息服务器是必然，问题来了，如何让链接在不同消息服务器上的用户可以实现消息发送呢？<br/><br/>要实现消息互通就必须要让这些消息服务器本身能互通，想了两个方式，一种是消息服务器之间交叉链接，另一种是增加一个特殊的消息服务器，这个消息服务器不对外开放，只负责消息转发和推送。<br/><br/>下列测试不考虑防火墙等。仅测试可行性和效率。<br/><br/>测试环境<br/><br/>消息服务器<br/><br/>192.168.0.201 9501 <br/>192.168.0.202 9501<br/>转发服务器<br/><br/>192.168.0.203 9501<br/>公共缓存<br/><br/>Redis 192.168.0.231 6379<br/>软件环境<br/><br/>centos 6.5 mini swoole php<br/>流程图<br/><br/>整个流程图如下：<br/><br/>enter image description here<br/><br/>流程图说明：<br/>client1可向client2或者其他client发送消息，并接收其他client发送的消息.<br/><br/>Redis中保存client连接的信息，给每个用户分配唯一的key,包括链接的哪台服务器,转发服务器定时检测消息服务器，如消息服务器挂掉，由转发服务器清理掉Redis已经挂掉的所有链接。<br/><br/>完整的流程：<br/><br/>1.Client1给Client2发送一条消息<br/><br/>2.Socket1接收到消息，根据key从Redis取出Client2的连接信息，连接在本机，直接推送给Client2，流程结束。<br/><br/>3.如果连接不在本机，把消息推送到转发服务器,由转发服务器把该消息推送给连接所在消息服务器，消息服务器接收消息，推送给Client2。<br/><br/>4.消息发送结束。<br/><br/>编码实现<br/><br/>Socket<br/>在socket1上创建一个server.php,内容如下：<br/><br/>&nbsp;&nbsp;&lt;?php //服务端 <br/>&nbsp;&nbsp; $serv = new swoole_server(&quot;0.0.0.0&quot;, 9501);<br/><br/>&nbsp;&nbsp;//redis<br/>&nbsp;&nbsp;$redis = new &#92;Redis();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br/>&nbsp;&nbsp;$redis-&gt;connect(&quot;192.168.0.231&quot;, 6379);<br/>&nbsp;&nbsp;<br/>&nbsp;&nbsp;//client<br/>&nbsp;&nbsp;$proxy = new swoole_client(SWOOLE_TCP &#124; SWOOLE_KEEP);<br/>&nbsp;&nbsp;$proxy-&gt;connect(&quot;192.168.0.203&quot;, 9501);<br/>&nbsp;&nbsp;<br/>&nbsp;&nbsp;$serv-&gt;on(&#039;start&#039;, function($serv) &#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;echo &quot;Service:Start...&quot;;<br/>&nbsp;&nbsp;&#125;);<br/>&nbsp;&nbsp;$serv-&gt;on(&#039;connect&#039;, function ($serv, $fd) &#123;<br/>&nbsp;&nbsp;<br/>&nbsp;&nbsp;&#125;);<br/>&nbsp;&nbsp;$serv-&gt;on(&#039;receive&#039;, function ($serv, $fd, $from_id, $data) &#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;global $redis;<br/>&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$data = (array) json_decode($data);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$cmd = $data[&#039;cmd&#039;];<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp; switch ($cmd) &#123;<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case &quot;login&quot;://登陆<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//保存连接信息<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$save = array(<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#039;fd&#039; =&gt; $fd,<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#039;socket_ip&#039; =&gt; &quot;192.168.0.201&quot;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$redis-&gt;set($data[&#039;name&#039;], serialize($save));<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case &quot;chat&quot;:<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$recv = unserialize($redis-&gt;get($data[&#039;recv&#039;]));<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if ($recv[&#039;socket_ip&#039;] != &quot;192.168.0.201&quot;) &#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//需要转发<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$data[&#039;cmd&#039;] = &#039;forward&#039;;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$data[&#039;recv_ip&#039;] = $recv[&#039;socket_ip&#039;];<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$serv-&gt;task(json_encode($data));<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125; else &#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//直接发送<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$serv-&gt;send($recv[&#039;fd&#039;], &quot;&#123;$data[&#039;send&#039;]&#125;给您发了消息：&#123;$data[&#039;content&#039;]&#125;&quot;);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case &quot;forward&quot;://接收转发消息<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$recv = unserialize($redis-&gt;get($data[&#039;recv&#039;]));<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$serv-&gt;send($recv[&#039;fd&#039;], &quot;&#123;$data[&#039;send&#039;]&#125;给您发了消息：&#123;$data[&#039;content&#039;]&#125;&quot;);<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&#125;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//$serv-&gt;send($fd, &#039;Swoole: &#039; . $data);<br/>&nbsp;&nbsp;&#125;);<br/>&nbsp;&nbsp;$serv-&gt;on(&#039;task&#039;, function ($serv, $task_id, $from_id, $data) &#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;global $proxy;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$proxy-&gt;send($data);<br/>&nbsp;&nbsp;&#125;);<br/><br/>&nbsp;&nbsp;$serv-&gt;on(&#039;finish&#039;, function ($serv, $task_id, $data) &#123;<br/><br/>&nbsp;&nbsp;&#125;);<br/>&nbsp;&nbsp;$serv-&gt;on(&#039;close&#039;, function ($serv, $fd) &#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;echo &quot;Client: Close.&#92;n&quot;;<br/>&nbsp;&nbsp;&#125;);<br/><br/>&nbsp;&nbsp;$serv-&gt;set(array(&#039;task_worker_num&#039; =&gt; 4));<br/><br/>&nbsp;&nbsp;$serv-&gt;start();<br/>在socket2上只需把ip变更一下即可。192.168.0.201变更为192.168.0.202.<br/><br/>Proxy<br/>在转发服务器上建立脚本proxy.php，内容如下：<br/><br/> $serv = new swoole_server(&quot;0.0.0.0&quot;, 9501); //服务端<br/> $serv-&gt;on(&#039;start&#039;, function($serv) &#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp; echo &quot;Service:Start...&quot;;<br/> &#125;);<br/> $serv-&gt;on(&#039;connect&#039;, function ($serv, $fd) &#123;<br/><br/> &#125;);<br/> $serv-&gt;on(&#039;receive&#039;, function ($serv, $fd, $from_id, $data) &#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp; global $redis;<br/>&nbsp;&nbsp;&nbsp;&nbsp; $serv-&gt;task($data);<br/> &#125;);<br/> $serv-&gt;on(&#039;task&#039;, function ($serv, $task_id, $from_id, $data) &#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp; $forward = (array) json_decode($data);<br/>&nbsp;&nbsp;&nbsp;&nbsp; $client = new swoole_client(SWOOLE_SOCK_TCP, SWOOLE_SOCK_SYNC);<br/><br/>&nbsp;&nbsp;&nbsp;&nbsp; $client-&gt;connect($forward[&#039;recv_ip&#039;], 9501);<br/>&nbsp;&nbsp;&nbsp;&nbsp; unset($forward[&#039;recv_ip&#039;]);<br/>&nbsp;&nbsp;&nbsp;&nbsp; $client-&gt;send(json_encode($forward));<br/>&nbsp;&nbsp;&nbsp;&nbsp; $client-&gt;close();<br/> &#125;);<br/><br/> $serv-&gt;on(&#039;finish&#039;, function ($serv, $task_id, $data) &#123;<br/><br/> &#125;);<br/> $serv-&gt;on(&#039;close&#039;, function ($serv, $fd) &#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp; echo &quot;Client: Close.&#92;n&quot;;<br/> &#125;);<br/> <br/> $serv-&gt;set(array(&#039;task_worker_num&#039; =&gt; 4));<br/><br/> $serv-&gt;start();<br/>测试<br/><br/>注意开启顺序<br/><br/>1.开启转发服务器php proxy.php<br/><br/>2.分别开启socket服务器php server.php<br/><br/>enter image description here<br/><br/>可以在转发服务器上看到两个消息服务器已经连接<br/>3.开始测试，分别打开两个telnet,连接两个消息服务器，发送消息测试：<br/>登陆<br/><br/>enter image description here<br/><br/>发送消息测试<br/><br/>enter image description here<br/><br/>消息成功接收。<br/><br/>基于强大的swoole扩展，让php高效的实现这些成为可能，目前消息服务器到转发服务器是长连接，转发服务器到消息服务器是短连接，存在性能瓶颈，也浪费了连接资源。下一步改造成长连接，消息服务器的client使用异步。<br/><br/>来自：http://blog.molibei.com/archives/105
]]>
</description>
</item><item>
<link>https://jackxiang.com/post//#blogcomment</link>
<title><![CDATA[[评论]  基于SWOOLE的分布式SOCKET消息服务器架构]]></title> 
<author> &lt;user@domain.com&gt;</author>
<category><![CDATA[评论]]></category>
<pubDate>Thu, 01 Jan 1970 00:00:00 +0000</pubDate> 
<guid>https://jackxiang.com/post//#blogcomment</guid> 
<description>
<![CDATA[ 
	
]]>
</description>
</item>
</channel>
</rss>