剖析下聊天室

由来

环境:PHP7、Swoole、linux

对聊天室有点感兴趣,对于网络协议有一点一知半解,所以决定借助swoole实现个简单的聊天室,来简单剖析下原理,知道原理以后就可以考虑用其他语言或者自己造轮子写个,当然这是后话。

源码我放置github( https://github.com/WalkingSun/SwooleServer ),有兴趣可以借鉴借鉴。

系统设计

即时通讯的网络通信基于长连接,通信方式有TCP、UDP、socket、websocket等,本次实现是websocket,系统建立常驻内存的websocket服务,客户端即浏览器两者建立连接通信。通信过程如下:

image

关于客户端连接websocket服务,本文不做细述,websocket服务的建立借助swoole,需要在服务端的open、recieve、send、close建立回调处理,为了方便我将连接的客户端信息放入swoole_table(一个基于共享内存和锁实现的超高性能,并发数据结构)。

代码仅供参考:

websocket 服务类:

<?php
/**
 * Created by PhpStorm.
 * User: WalkingSun
 * Date: 2018/10/28
 * Time: 15:54
 */

class WsServer
{
    const host = '0.0.0.0';
    const port = '9501';

    public $swoole;

    public $config = ['gcSessionInterval' => 60000];

    public $openCallback;       //open回调

    public $messageCallback;    //message回调

    public $runApp;    //request回调

    public $workStartCallback;       //work回调

    public $finishCallback;     //finish回调

    public $closeCallback;       //close回调

    public $taskCallback;       //task回调

    public function __construct( $host, $port, $mode, $socketType, $swooleConfig=[], $config=[])
    {
        $host = $host?:self::host;
        $port = $port?:self::port;
        $this->swoole = new Swoole_websocket_server($host,$port,$mode,$socketType);
        $this->webRoot = $swooleConfig['document_root'];
        if( !empty($this->config) ) $this->config = array_merge($this->config, $config);
        $this->swoole->set($swooleConfig);

        $this->swoole->on('open',[$this,'onOpen']);
        $this->swoole->on('message',[$this,'onMessage']);
        $this->swoole->on('request',[$this,'onRequest']);
        $this->swoole->on('WorkerStart',[$this,'onWorkerStart']);            //增加work进程
        $this->swoole->on('task',[$this,'onTask']);            //增加task任务进程
        $this->swoole->on('finish',[$this,'onFinish']);
        $this->swoole->on('close',[$this,'onClose']);
    }

    public function run(){
        $this->swoole->start();
    }

    /**
     * 当WebSocket客户端与服务器建立连接并完成握手后会回调此函数
     * @param $serv swoole_websocket_server 服务对象
     * @param $request swoole_http_server 服务对象
     */
    public function onOpen( swoole_websocket_server $serv,  $request){
        call_user_func_array( $this->openCallback, [ $serv, $request ] );

        //定时器(异步执行)
//        if($request->fd == 1){
//            swoole_timer_tick(2000,function($timer_id){
//                echo time().PHP_EOL;
//            });
//        }
    }

    /**
     *当服务器收到来自客户端的数据帧时会回调此函数。
     * @param $server  swoole_websocket_server 服务对象
     * @param $frame  swoole_websocket_frame对象,包含了客户端发来的数据帧信息
     * $frame->fd,客户端的socket id,使用$server->push推送数据时需要用到
    $frame->data,数据内容,可以是文本内容也可以是二进制数据,可以通过opcode的值来判断
    $frame->opcode,WebSocket的OpCode类型,可以参考WebSocket协议标准文档
    $frame->finish, 表示数据帧是否完整,一个WebSocket请求可能会分成多个数据帧进行发送(底层已经实现了自动合并数据帧,现在不用担心接收到的数据帧不完整)
     */
    public function onMessage(swoole_websocket_server $serv, swoole_websocket_frame $frame ){

        call_user_func_array( $this->messageCallback, [ $serv, $frame ]);

    }

    /**
     * @param $serv  swoole_websocket_server 服务对象
     * @param $fd  连接的文件描述符
     * @param $reactorId  来自那个reactor线程
     * onClose回调函数如果发生了致命错误,会导致连接泄漏。通过netstat命令会看到大量CLOSE_WAIT状态的TCP连接
     * 当服务器主动关闭连接时,底层会设置此参数为-1,可以通过判断$reactorId < 0来分辨关闭是由服务器端还是客户端发起的。
     */
    public function onClose( swoole_websocket_server $serv , $fd , $reactorId ){

        call_user_func_array( $this->closeCallback ,[ $serv , $fd , $reactorId ]);

    }

    /**
     * 在task_worker进程内被调用。worker进程可以使用swoole_server_task函数向task_worker进程投递新的任务。当前的Task进程在调用onTask回调函数时会将进程状态切换为忙碌,这时将不再接收新的Task,当onTask函数返回时会将进程状态切换为空闲然后继续接收新的Task。
     * @param $serv  swoole_websocket_server 服务对象
     * @param $task_id int 任务id,由swoole扩展内自动生成,用于区分不同的任务。$task_id和$src_worker_id组合起来才是全局唯一的,不同的worker进程投递的任务ID可能会有相同
     * @param $src_worker_id int 来自于哪个worker进程
     * @param $data mixed 任务的内容
     */
    public function onTask(swoole_server $serv,  $task_id,  $src_worker_id,  $data){

        call_user_func_array( $this->taskCallback , [ $serv, $task_id, $src_worker_id, $data ]);

//        sleep(10);
//        onTask函数中 return字符串,表示将此内容返回给worker进程。worker进程中会触发onFinish函数,表示投递的task已完成。
//        return "task {$src_worker_id}-{$task_id} success";
    }

    /**
     * 当worker进程投递的任务在task_worker中完成时,task进程会通过swoole_server->finish()方法将任务处理的结果发送给worker进程。
     * @param $serv  swoole_websocket_server 服务对象
     * @param $task_id int  任务id
     * @param $data string  task任务处理的结果内容
     * task进程的onTask事件中没有调用finish方法或者return结果,worker进程不会触发onFinish
    执行onFinish逻辑的worker进程与下发task任务的worker进程是同一个进程
     */
    public function onFinish(swoole_server $serv,  $task_id,  $data){

        call_user_func_array( $this->finishCallback ,[ $serv,$task_id,$data]);
//        echo $data;
//        return $data;
    }

    public function onRequest( $request, $response ){
        call_user_func_array( $this->runApp, [ $request, $response ]);
    }

    public function onWorkerStart( $server,  $worker_id ){
        call_user_func_array( $this->workStartCallback , [$server,  $worker_id]);
    }
}
起服务和回调设置:

   class SwooleController extends BasicController{

       public $host;

       public $port;

       public  $swoole_config=[];

       public static $table;


       public function actionStart(){

           $config = include __DIR__ . '/../config/console.php';

           if( isset($config['swoole']['log_file']) ) $this->swoole_config['log_file'] = $config['swoole']['log_file'];

           if( isset($config['swoole']['pid_file']) ) $this->swoole_config['pid_file'] = $config['swoole']['pid_file'];

           $this->swoole_config = array_merge(
               [
                   'document_root' => $config['swoole']['document_root'],
                   'enable_static_handler'     => true,
   //                'daemonize'=>1,
                   'worker_num'=>4,
                   'max_request'=>2000,
   //            'task_worker_num'=>100,
                   //检查死链接  使用操作系统提供的keepalive机制来踢掉死链接
                   'open_tcp_keepalive'=>1,
                   'tcp_keepidle'=> 1*60,     //连接在n秒内没有数据请求,将开始对此连接进行探测
                   'tcp_keepcount' => 3,       //探测的次数,超过次数后将close此连接
                   'tcp_keepinterval' => 0.5*60,     //探测的间隔时间,单位秒

                   //swoole实现的心跳机制,只要客户端超过一定时间没发送数据,不管这个连接是不是死链接,都会关闭这个连接
   //            'heartbeat_check_interval' => 10*60,        //每m秒侦测一次心跳
   //            'heartbeat_idle_time' => 30*60,            //一个TCP连接如果在n秒内未向服务器端发送数据,将会被切断
               ],$this->swoole_config
           );

           $this->host = $config['swoole']['host'];
           $this->port = $config['swoole']['port'];
           $swooleServer = new WsServer(  $this->host,$this->port,$config['swoole']['mode'],$config['swoole']['socketType'],$this->swoole_config,$config);

           //连接信息保存到swoole_table
           self::$table = new \swoole_table(10);
           self::$table->column('username',\Swoole\Table::TYPE_STRING, 10);
           self::$table->column('avatar',\Swoole\Table::TYPE_STRING, 255);
           self::$table->column('msg',\Swoole\Table::TYPE_STRING, 255);
           self::$table->column('fd',\Swoole\Table::TYPE_INT, 6);
           self::$table->create();

           $swooleServer->openCallback = function( $server , $request ){
               echo "server handshake with fd={$request->fd}\n";
           };

           $swooleServer->runApp = function( $request , $response ) use($config,$swooleServer){

               //全局变量设置及app.log
               $this->globalParam( $request );
               $_SERVER['SERVER_SWOOLE'] = $swooleServer;

               //记录日志
               $apiData = $_SERVER;
               unset($apiData['SERVER_SWOOLE']);
               Common::addLog( $config['log'] , ($apiData) );

               //解析路由
               $r = $_GET['r'];
               $r = $r?:( isset($config['defaultRoute'])?$config['defaultRoute']:'index/index');
               $params = explode('/',$r);
               $controller = __DIR__.'/../controllers/'.ucfirst($params[0]).'Controller.php';

               $result = '';
               if( file_exists( $controller ) ){
                   require_once $controller;
                   $class = new ReflectionClass(ucfirst($params[0]).'Controller');
                   if( $class->hasMethod( 'action'.ucfirst($params[1]) ) ){
                       $instance  = $class->newInstanceArgs();
                       $method = $class->getmethod('action'.ucfirst($params[1])); // 获取类中方法
                       ob_start();
                       $method->invoke($instance);    // 执行方法
                       $result = ob_get_contents();
                       ob_clean();
                   }else{
                       $result = 'NOT FOUND!';
                   }
               }else{
                   $result = "$controller not exist!";
               }

               $response->end( $result );
           };

           $swooleServer->workStartCallback = function( $server,  $worker_id ){

           };

           $swooleServer->taskCallback = function( $server , $request ){
               //发送通知或者短信、邮件等

           };

           $swooleServer->finishCallback = function( $serv,  $task_id,  $data ){

   //            return $data;
           };

           $swooleServer->messageCallback = function( $server,  $iframe  ){
               //记录客户端信息
               echo "Client connection fd {$iframe->fd} ".PHP_EOL;

               $data = json_decode( $iframe->data ,1 );

               if( !empty($data['token']) ){
                   if( $data['token']== 'simplechat_open' ){
                       if( !self::$table->exist($iframe->fd) ){
                           $user = array_merge($data,['fd'=>$iframe->fd]);
                           self::$table->set($iframe->fd,$user);

                           //发送连接用户信息
                           foreach (self::$table as $v){
                               if($v['fd']!=$iframe->fd){
                                   $pushData = array_merge($user,['action'=>'connect']);
                                   $server->push($v['fd'],json_encode($pushData));
                               }
                           }
                       }

                   }

                   if( $data['token']=='simplechat' ){
                       //查询所有连接用户,分发消息

                       foreach (self::$table as $v){
                           if($v['fd']!=$iframe->fd){
                               $pushData = ['username'=>$data['username'],'avatar'=>$data['avatar'],'time'=>date('H:i'),'data'=>$data['data'],'action'=>'send'];
                               $server->push($v['fd'],json_encode($pushData));
                           }
                       }
                   }
               }

               //接受消息,对消息进行解析,发送给组内人其他人

           };

           $swooleServer->closeCallback = function(  $server,  $fd,  $reactorId ){

               if(  self::$table->exist($fd) ){
                   //退出房间处理
                   self::$table->del($fd);
                   foreach (self::$table as $v){
                       $pushData = ['fd'=>$fd,'username'=>'','avatar'=>'','time'=>date('H:i'),'data'=>'','action'=>'remove'];
                       $server->push($v['fd'],json_encode($pushData));
                   }
               }

               echo  "Client close fd {$fd}".PHP_EOL;
           };

           $this->stdout("server is running, listening {$this->host}:{$this->port}" . PHP_EOL);
           $swooleServer->run();
       }


       public function actionStop(){
           $r = $this->sendSignal( SIGTERM );
           if( $r ){
               $this->stdout("server is stopped, stop listening {$this->host}:{$this->port}" . PHP_EOL);
           }
       }

       public function actionRestart(){
           $this->sendSignal(SIGTERM);     //向主进程发送SIGTERM实现关闭服务器
           $this->actionStart();
       }

       public function actionReload(){
           $this->sendSignal(SIGUSR1);   //向主进程/管理进程发送SIGUSR1信号,将平稳地restart所有Worker进程
       }

   }

 

起了服务,客户端就可以连接通信了。

心跳检测

起了半天后服务常会断掉,查看监听端口进程状态,服务器输入:

$ netstat -anp |grep 9501

发现大量CLOSE_WAIT状态,常用状态有 ESTABLISHED 表示正在通信,TIME_WAIT 表示主动关闭,CLOSE_WAIT 表示被动关闭。

TIME_WAIT和CLOSE_WAIT两种状态如果一直被保持,意味着对应数目的通道就一直被占用,且“占着茅坑不使劲”,一旦句柄数达到上限,新的请求就无法处理。而且因为swoole是master-worker模式,
基本上http、tcp通信都是在worker进程,CLOSE_WAIT一直在,子进程将一直无法释放,随着时间的推移CLOSE_WAIT状态的进程越来越多,阻碍新的连接进来,websocket服务不可用。

主动关闭 和 被动关闭
TCP关闭 四次挥手过程如下:

image

挥手流程:

1、 客户端是调用函数close(),这时,客户端会发送一个FIN给服务器。

2、 服务器收到FIN,关闭套接字读通道,并将自己状态设置为CLOSE_WAIT(表示被动关闭),
并返回一个ACK给客户端。

3、 客户端收到ACK,关闭套接字写通道
接下来,服务器会调用close():

1、 服务器close(),发送一个FIN到客户端。

2、 客户端收到FIN,关闭读通道,并将自己状态设置成TIME_WAIT,发送一个ACK给服务器。

3、 服务器收到ACK,关闭写通道,并将自己状态设置为CLOSE。

4、 客户端等待两个最大数据传输时间,然后将自己状态设置成CLOSED。

由此我们看到CLOSE-WAIT 状态,TIME-WAIT 状态 产生的过程,产生的原因是复杂的,比如说网络通信中断、用户手机网络切换wifi网络、网络通信丢包等,故此tcp挥手过程会出现中断,继而
产生这些关闭状态。

为了解决这些占用连接数的异常连接,需要检测连接是否是活动的,对于死连接我们需要释放关闭它。

TIME_WAIT 主动关闭

主动关闭的一方在发送最后一个ACK包后,无论对方是否收到都会进入状态,等待2MSL(Maximum Segment Lifetime数据包的最大生命周期,是一个数据包能在互联网上生存的最长时间,若超过这个时间则该数据包将会消失在网络中)
的时间,才会释放网络资源。

TIME_WAIT状态的存在主要有两个原因:

1)可靠地实现TCP全双工连接的终止。在关TCP闭连接时,最后的ACK包是由主动关闭方发出的,如果这个ACK包丢失,则被动关闭方将重发FIN包,因此主动方必须维护状态信息,以允许它重发这个
ACK包。如果不维持这个状态信息,那么主动方将回到CLOSED状态,并对被动方重发的FIN包响应RST包,而被动关闭方将此包解释成一个错误。因而,要实现TCP全双工连接的正常终止,必须能够处
理四次握手协议中任意一个包丢失的情况,主动关闭方必须维持状态信息进入TIME_WAIT状态。

2)确保迷路重复数据包在网络中消失,防止上一次连接中的包迷路后重新出现,影响新连接。TCP数据包可能由于路由器异常而迷路,在迷路期间,数据包发送方可能因超时而重发这个包,迷路的
数据包在路由器恢复后也会被送到目的地,这个迷路的数据包就称为Lost Duplicate。在关闭一个TCP连接后,如果马上使用相同的IP地址和端口建立新的TCP连接,那么有可能出现前一个连接的迷
路重复数据包在前一个连接关闭后再次出现,影响新建立的连接。为了避免这一情况,TCP协议不允许使用处于TIME_WAIT状态的连接的IP和端口启动一个新连接,只有经过2MSL的时间,确保上一次
连接中所有的迷路重复数据包都已消失在网络中,才能安全地建立新连接。

如果Server主动关闭连接,同样会有大量的连接在关闭后处于TIME_WAIT状态,等待2MSL的时间后才能释放网络资源。对于并发连接,出现大量等待连接,新的连接进不来,会降低系统性能。

time_wait问题可以通过调整内核参数和适当的设置web服务器的keep-Alive值来解决。因为time_wait是自己可控的,要么就是对方连接的异常,要么就是自己没有快速的回收资源,总之不是由于自己程序错误引起的。

解决方式:

  • 试图让Client主动关闭连接,由于每个Client的并发量都比较低,因而不会产生性能瓶颈
  • 优化Server的系统TCP参数,使其网络资源的最大值、消耗速度和恢复速度达到平衡;

    修改/etc/sysctl.conf

    net.ipv4.tcp_tw_recycle = 1       #启用TIME-WAIT状态sockets的快速回收
    
    net.ipv4.tcp_tw_reuse = 1         #允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0,表示关闭
    
    #缓存每个连接最新的时间戳,后续请求中如果时间戳小于缓存的时间戳,即视为无效,相应的数据包会被丢弃,启用这种行为取决于tcp_timestamps和tcp_tw_recycle
    net.ipv4.tcp_timestamps = 1

CLOSE_WAIT 被动关闭

对方发送一个FIN后,程序自己这边没有进一步发送ACK以确认。换句话说就是在对方关闭连接后,程序里没有检测到,或者程序里本身就已经忘了这个时候需要关闭连接,于是这个资源就一直被程序占用着。

解决办法:

  • 释放关闭掉异常的连接;
  • 修复程序的bug,重新发布;

Keep-Alive

TCP中有一个Keep-Alive的机制可以检测死连接,LINUX内核包含对keepalive的支持,其中使用了三个参数:tcp_keepalive_time(开启keepalive的闲置时长)tcp_keepalive_intvl(keepalive探测包的发送
间隔)和tcp_keepalive_probes(如果对方不予应答,探测包的发送次数);如此服务端会隔断时间发送个探测包给客户端,可以是多次,如果在超出设置闲置时长,内核会关闭这个连接。

客户端主动发心跳

通过程序设置最大连接时长,如果客户端在这段时间内没有发送过数据,则关闭释放这个连接。

解决关闭问题

TIME_WAIT 倒是没有出现过, CLOSE_WAIT状态总会出现。

就看看文档,swoole有这些设置,当前使用的是TCP的keep-alive检测,只需改配置即可:

   ...
    //检查死链接  使用操作系统提供的keepalive机制来踢掉死链接
                'open_tcp_keepalive'=>1,
                'tcp_keepidle'=> 1*60,     //连接在n秒内没有数据请求,将开始对此连接进行探测
                'tcp_keepcount' => 3,       //探测的次数,超过次数后将close此连接
                'tcp_keepinterval' => 0.5*60,     //探测的间隔时间,单位秒
   ...

我设置的周期比较短,方便测试。

设置了这些看似稳定了,却还是会出现CLOSE_WAIT,后来查了日志,发生错误中断了,大概意思,代码中出现exit、die,显然常驻内存的swoole不支持这些,会立马中断程序。所以改些这些代码,
刚开始借助YII2.0写的,框架源码的问题,所以swoole这块服务需要单独出来,嗯。。。所以索性直接自己撸个。现在看来,服务跑起来稳定多了,一直没挂呢。

贴下临时地址:http://47.99.189.105:91/

系统监控及优化

系统很简单,但是作为研究,应该更透彻点。

我们的系统如何监控?如果说系统崩溃怎么办?能支撑多大并发?高并发下如何保持系统稳定。。。 一个高性能的即时通讯是如何架构的?

额,留待以后再研究下补充。

参考资料:

https://juejin.im/post/5c3b21e4e51d455231347349



如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!欢迎各位转载,但是未经作者本人同意,转载文章之后必须在文章页面明显位置给出作者和原文连接,否则保留追究法律责任的权利。

原文地址:https://www.cnblogs.com/applelife/p/10448377.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


1.SW的HttpServerHttpServer的本质仍然是swoole_server,其协议加些部分固定使用Http协议解析,支持同步和异步2种模式完整的HTTP协议请求会被封装在swoole_http_request对象内,所有HTTP响应都会通过swoole_http_response对象进行封装和发送无论是同步模式还是异步模式,HttpServer都可
1、Swoole依赖安装hiredissudowgethttps://github.comedis/hiredis/archive/v0.14.0.tar.gzsudotarxfv0.14.0.tar.gzcdhiredis-0.14.0/sudomakesudomakeinstallsudoldconfig需要在编译时增加--enable-async-redis来开启此功能nghttp2sudowgethttps://gith
直接安装会提示找不到openssl/ssl.h文件即便通过Brew安装了OpenSSLbrewinstallopenssl他自己找不到我们手动让他找到就行了呗…当然OpenSSL一定是要安装的,命令就在上方…然后brewinfoopenssl可以看到:Forcompilerstofindopensslyoumayneedtoset:
1.安装依赖yum install -y php php-pear php-devel httpd gcc gcc-c++2.编译安装swoole上传并解压swoole 源码包至服务器 swoole-src-4.3.1.tar.gzcd  /usr/local/swoole-src-4.3.1输入  phpize执行 ./configure执行 make && make install3.配置PHP支持该
下载swoole地址:https://pan.baidu.com/s/1_N3RiFtT3iHLA5xt6oElqA下载后解压tar-zxvf......执行phpize(去php的安装目录执行这个)如果报以下错误:Cannotfindconfig.m4.Makesurethatyourun'/srv/php/bin/phpize'inthetoplevelsourcedirectoryofthem
昨晚我躺在床上,百无聊赖地翻阅 阿兰·德波顿《身份的焦虑》这本书,看到这么一段话,让我想起网络上做墙头草的键盘侠,他们喜欢贴标签,然后去简单粗暴地批评或讨好一类人,那么可以说公众的眼睛是雪亮的吗?我一直不喜欢太绝对太肯定的观点,对此我也保留怀疑,包括那些道听途说来的道理。  
本着开源为原则,为这个世界更美好作出一份共享,我就给大家做个指路人,如果实用,记得给提供开源的朋友一些鼓励。简单介绍一下实现思路,使用swoole扩展接管php运行,由于swoole只能在类UNIX上运行,所以win朋友需要安装cygwin运行的类UNIX模拟环境。为了照顾大多数用户,这里就以win为例:首先
1.文件锁子进程回复制父进程的IO句柄,但是不能让所有的子进程同时对同一个文件进行操作,所以需要文件锁。2.进程间的通讯方式--管道管道是一组(2个)特殊的描述符管道需要在fork函数调用前创建如果某一段主动关闭管道,另一端读取操作会直接返回0,之后会关闭管道在父进程中创建管道的时候
环境:gccyuminstallgcc第一步:下载swoole包wgethttp://pecl.php.net/package/swoole第二步:解压,并进入执行:/usr/local/php/bin/phpize可能会报错Cannotfindautoconf.Pleasecheckyourautoconfinstallationandthe?$PHP_AUTOCONF?environmentvariableissetcorrectly
1、安装swoolewgethttps://github.com/swoole/swoole-src/archive/v1.9.1-stable.tar.gztarzxvfv1.9.1-stable.tar.gzcdswoole-src-1.9.1-stable/usr/local/php/bin/phpize./configure--with-php-config=/usr/local/php/bin/php-configmakemakeinstall2、配置php支持swoolevi
由来环境:PHP7、Swoole、linux对聊天室有点感兴趣,对于网络协议有一点一知半解,所以决定借助swoole实现个简单的聊天室,来简单剖析下原理,知道原理以后就可以考虑用其他语言或者自己造轮子写个,当然这是后话。源码我放置github(https://github.com/WalkingSun/SwooleServer),有兴趣可
检查环境是否满足Swoole的环境依赖#查看linux内核uname-a#查看gcc版本gcc--versiong++--version升级gcc到4.8以上cd/usr/local/srcwgetwgethttp://ftp.gnu.org/gnu/gcc/gcc-4.8.5/gcc-4.8.5.tar.bz2tar-jxvfgcc-4.8.5.tar.bz2cdgcc-4.8.5/usr/local/sr
卸载现有phpapt-getautoremovephp7*find/etc-name"*php*"|xargsrm-rfaptpurge`dpkg-l|grepphp|awk'{print$2}'|tr"\n"""`编译安装phpaptinstallgccmakelibxml2libxml2-devwgethttp://cn2.php.net/distrib
目录概述代码小结扩展参考文档概述Swoole异步Task,主要实现调用异步任务的执行。常用的场景:异步支付处理、异步订单处理、异步日志处理、异步发送邮件/短信等。Swoole的实现方式是worker进程处理数据请求,分配给task进程执行。官方介绍:task底层使用UnixSoc
上一篇写到了如何在windows系统上面利用docker快速搭建swoole开发环境,接下来体验下swoole的使用使用swoole实现tcp服务<?php$serv=newSwoole\Server("0.0.0.0",9501);$serv->on('connect',function($serv,$fd){echo"客户端".$fd."连接成功\n";});$serv-&
一、同步与异步的区别:1、同步模式:后一个任务等待前一个任务结束,然后再执行,程序的执行顺序与任务的排列顺序是一致的、同步的.2、异步模式:则完全不同,每一个任务有一个或多个回调函数(callback),前一个任务结束后,不是执行后一个任务,而是执行回调函数,后一个任务则是不等前一个
1.什么是RPCRPC是一种进程间的通讯方式,全称是“远程调用过程”。当客户端向服务器发出请求时,并不是至直接发送给目标服务器,而是发送给RPCServer,由RPCServer进行调度。RPC提供与调用本地方法无差别的远程调用方法。2.Hprose简介Hprose是一个轻量级的高性能跨语言RPC服务框架;提供
swoole中,接受数据流处理时,需要将数据流切分成小包才能进行功能的实现,以下为常见的几个协议1.EOF协议EOF协议是用一组固定的,不会出现在数据内的字符作为数据分割的标记,简称EOF协议EOF协议的格式如下:DATA|EOF|DATA|EOF|......2.固定包头协议在数
环境依赖:swoole-1.x需要php-5.3.10或更高版本,swoole-2.x需要php-7.0.0或更高版本。安装步骤:[root@dev~]#cd/usr/local/src[root@devsrc]#wgethttp://pecl.php.net//get/swoole-4.3.5.tgz[root@devsrc]#tar-zxvfswoole-4.3.5.tgz[root@devsrc]#cdsw
Swoole:面向生产环境的PHP异步网络通信引擎    使PHP开发人员可以编写高性能的异步并发TCP、UDP、UnixSocket、HTTP,WebSocket服务。Swoole可以广泛应用于互联网、移动通信、企业软件、云计算、网络游戏、物联网(IOT)、车联网、智能家居等领域。使用PHP+Swoole作