• swoole快速上手


    第一 安装

    第二 配置

    第三 快速使用

    1. 创建tcp服务器

    swoole_server是异步服务器,所以是通过监听事件的方式来编写程序的。当对应的事件发生时底层会主动回调指定的PHP函数。如当有新的TCP连接进入时会执行onConnect事件回调,当某个连接向服务器发送数据时会回调onReceive函数。

    • 服务器可以同时被成千上万个客户端连接,$fd就是客户端连接的唯一标识符
    • 调用 $server->send() 方法向客户端连接发送数据,参数就是$fd客户端标识符
    • 调用 $server->close() 方法可以强制关闭某个客户端连接
    • 客户端可能会主动断开连接,此时会触发onClose事件回调
    /*
     * $host domain
     * $port listener port
     * $mode : swoole_process 多进程方式
     * $socket_type: swoole_socket_tcp
     */
    $serv = new swoole_server('0.0.0.0', 9501);
    
    $serv->set([
    	'worker_num' => 4, //worker 进程数 cpu的1-4倍,可以采用 ps -aft|grep php 来查看
    	'max_request' => 10000,
    ]);
    
    $serv->manager_pid;  //管理进程的PID,通过向管理进程发送SIGUSR1信号可实现柔性重启
    $serv->master_pid;  //主进程的PID,通过向主进程发送SIGTERM信号可安全关闭服务器
    $serv->connections; //当前服务器的客户端连接,可使用foreach遍历所有连接
    /*
     * $event;
     * connect: 当建立连接时候 $serv $fd
     * receive:当连接收到数据时候
     * close: 关闭连接
     */
    $serv->on("connect", function($serv, $fd){
        echo "建立连接
    ";
    //    var_dump($serv);
    //    var_dump($fd);
    });
     
    $serv->on("receive", function($serv, $fd, $from_id, $data){
        echo "接收到数据
    ";
        var_dump($data);
    });
    
    $serv->on("close", function($serv, $fd){
        echo "连接关闭";
    });
    
    $serv->start();
    

    在这里插入图片描述

    2. 创建udp服务器

    UDP服务器与TCP服务器不同,UDP没有连接的概念。启动Server后,客户端无需Connect,直接可以向Server监听的9502端口发送数据包。对应的事件为onPacket

    $swoole_type = SWOOLE_PROCESS;//多进程模式
    $swoole_udp = SWOOLE_SOCK_UDP;
    $serv = new swoole_server("0.0.0.0", 9502, $swoole_type, $swoole_udp);
    /*
     * $server
     * $data 接收到的数据
     * $fd:客户端信息
     */
    $serv->on("packet", function($serv, $data,$fd){
        //发送数据到相应的客户端,反馈信息
        $data = "server: $data";
        $server_socket = -1;
        $serv->sendto($fd["address"], $fd["port"], $data, $server_socket);
        var_dump($fd);
    });
    $serv->start();
    ```![在这里插入图片描述](https://img-blog.csdnimg.cn/20190505014828844.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzI5Njc3ODY3,size_16,color_FFFFFF,t_70)
    

    3. 创建web服务器

    Http服务器只需要关注请求响应即可,所以只需要监听一个onRequest事件

    $host = "http://127.0.0.1";
    $serv = new swoole_http_server($host, 9501);
    /*
     * $request: 请求信息
     * $response: 返回信息
     */
    $serv -> on("request", function($request, $response){
        var_dump($request);
        $response->header("Conteny-Type", "text/html; charset=utf-8");//设置响应头
        $response->end("hello world".rand(100,999)); //发送信息
    });
    $serv->start();
    

    在这里插入图片描述

    4. 创建WebSocket服务器

    4.1 什么是WebSocket?

    WebSocket协议是基于TCP的一种新的网络协议。它实现了浏览器与服务器全双工(full-duplex)通信一允许服务器主动发送信息给客户端。缺陷:HTTP的通信只能由客户端发起

    4.2 WebSocket特点:

    • 建立在TCP协议之上
    • 性能开销小通信高效
    • 客户端可以与任意服务器通信
    • 协议标识符ws wss
    • 持久化网络通信协议

    4.3 WebSocket 工作流程

    WebSocket服务器是建立在Http服务之上的长连接服务,客户端首先会发送一个Http的请求与服务器进行握手。握手成功后会触发onOpen事件,表示连接已就绪,onOpen函数中可以得到$request对象,包含了Http握手的相关信息,如GET参数、Cookie、Http头信息等。建立连接后客户端与服务器端就可以双向通信了。

    • 客户端向服务器端发送信息时,服务器端触发onMessage事件回调
    • 服务器端可以调用$server->push()向某个客户端(使用$fd标识符)发送消息
    • 服务器端可以设置onHandShake事件回调来手工处理WebSocket握手
    • swoole_http_server是swoole_server的子类,内置了Http的支持
    • swoole_websocket_server是swoole_http_server的子类, 内置了WebSocket的支持
    //创建 websocket服务器
    $ws = new swoole_websocket_server("0.0.0.0", 9501);
    //open 建立连接 $ws 服务器,$request:客户信息
    $ws->on("open", function($ws, $request){
        var_dump($request);
        $ws->push($request->fd,"welcome 
    ");
    });
    //message 接收信息
    $ws->on("message", function($ws, $request){
       echo "receive from {$request->fd} : {$request->data}, opcode:{$request->opcode},fin:{$request->finish}
    ";
        $ws->push($request->fd, "get it message");
    });
    $ws->on("close", function($ws, $fd){
        echo "client {$fd} closed
    ";
    });
    $ws->start();
    
    <html lang="en">
    <head>
        <title>Title</title>
    </head>
    <script>
        var webServer = "ws://127.0.0.1:9501";
        var webSocket = new WebSocket(webServer);
        webSocket.onopen = function(evt){
            console.log("连接成功!")
        }
        webSocket.onclose = function (evt) {
            console.log("关闭!")
        }
        webSocket.onmessage = function (evt) {
            console.log(evt.data);
        }
        webSocket.onerror = function (evt, e) {
            console.log("error")
        }
    </script>
    </html>
    
    • 不能直接使用swoole_client与websocket服务器通信,swoole_client是TCP客户端
    • 必须实现WebSocket协议才能和WebSocket服务器通信,可以使用swoole/framework提供的PHP WebSocket客户端
    • WebSocket服务器除了提供WebSocket功能之外,实际上也可以处理Http长连接。只需要增加onRequest事件监听即可实现Comet方案Http长轮询。

    4.4 长连接的关闭

    Swoole内置了心跳检测功能,能自动close掉长时间没有数据来往的连接。而开启心跳检测功能,只需要设置heartbeat_check_interval和heartbeat_idle_time即可。如下:

    $this->serv->set(
        array(
            'heartbeat_check_interval' => 60,
            'heartbeat_idle_time' => 600,
        )
    );
    

    Swoole 异步操作

    5. 定时器

    swoole提供了类似JavaScript的setInterval/setTimeout异步高精度定时器,粒度为毫秒级

    //循环触发
    $tickId = swoole_timer_tick(2000, function($timer_id){
        echo "执行 $timer_id 
    ";
    });
    //n秒后触发
    $afterId = swoole_timer_after(3000, function(){
        echo "3000 后执行
    ";
    });
    //清除定时器
    swoole_timer_clear($afterId);
    

    在这里插入图片描述

    6. 异步tcp服务器

    在Server程序中如果需要执行很耗时的操作,比如一个聊天服务器发送广播,Web服务器中发送邮件。如果直接去执行这些函数就会阻塞当前进程,导致服务器响应变慢。Swoole提供了异步任务处理的功能,可以投递一个异步任务到TaskWorker进程池中执行,不影响当前请求的处理速度。

    //创建tcp服务器
    $serv = new swoole_server("0.0.0.0", 9501);
    //设置异步 进程工作数量
    $serv->set(array("task_worker_num"=>4));
    //投递异步任务
    $serv->on("receive", function($serv, $fd, $from_id, $data){
       $task_id = $serv->task($data);
       echo "异步ID:$task_id
    ";
    });
    //处理异步任务
    $serv->on("task", function($serv, $task_id, $from_id, $data){
       echo "执行 异步ID: $task_id";
       $serv->finish("$data ->OK");
    });
    //处理结果
    $serv->on("finish", function ($serv, $task_id, $data){
       echo "执行完成";
    });
    $serv->start();
    

    在这里插入图片描述

    7. 创建同步TCP客户端

    这个客户端是同步阻塞的,connect/send/recv 会等待IO完成后再返回。同步阻塞操作并不消耗CPU资源,IO操作未完成当前进程会自动转入sleep模式,当IO完成后操作系统会唤醒当前进程,继续向下执行代码。

    • TCP需要进行3次握手,所以connect至少需要3次网络传输过程
    • 在发送少量数据时$client->send都是可以立即返回的。发送大量数据时,socket缓存区可能会塞满,send操作会阻塞。
    • recv操作会阻塞等待服务器返回数据,recv耗时等于服务器处理时间+网络传输耗时之和。
    $client = new swoole_client(SWOOLE_SOCK_TCP);
    //连接到服务器
    if (!$client->connect('127.0.0.1', 9501, 0.5)){
        die("connect failed.");
    }
    //php常量
    fwrite(STDOUT, '请输入消息:')
    $msg = trim(fgets(STDIN));
    
    //向服务器发送数据
    if (!$client->send($msg)){
        die("send failed.");
    }
    //从服务器接收数据
    $data = $client->recv();
    if (!$data){
        die("recv failed.");
    }
    echo $data;
    //关闭连接
    $client->close();
    

    TCP通信过程
    Tcp通信过程

    8. 创建异步TCP客户端

    //创建异步tcp客户端
    $client = new swoole_client(SWOOLE_SOCK_TCP, SWOOLE_SOCK_ASYNC);
    //注册连接成功的回调
    $client->on("connect", function($cli){
        $cli->send("hello world 
    ");
    });
    //注册数据接收回调$cli,服务端信息$data 数据
    $client->on("receive", function($cli, $data){
        echo "data: $data";
    });
    //注册连接失败回调
    $client->on("error", function ($cli){
        echo "faild 
    ";
    });
    //注册关闭函数回调
    $client->on("close", function ($cli){
       echo "close 
    ";
    });
    //发起连接
    $client->connect("127.0.0.1", 8080, 10);
    
    

    异步客户端与上一个同步TCP客户端不同,异步客户端是非阻塞的。可以用于编写高并发的程序。swoole官方提供的redis-asyncmysql-async都是基于异步swoole_client实现的。

    异步客户端需要设置回调函数,有4个事件回调必须设置onConnectonErroronReceiveonClose。分别在客户端连接成功、连接失败、收到数据、连接关闭时触发。

    $client->connect() 发起连接的操作会立即返回,不存在任何等待。当对应的IO事件完成后,swoole底层会自动调用设置好的回调函数。

    9 网络通信协议设计

    1. TCP协议在底层机制上解决了UDP协议的顺序和丢包重传问题。但相比UDP又带来了新的问题,TCP协议是流式的,数据包没有边界。应用程序使用TCP通信就会面临这些难题。因为TCP通信是流式的,在接收1个大数据包时,可能会被拆分成多个数据包发送。多次Send底层也可能会合并成一次进行发送。这里就需要2个操作来解决:分包(Server收到了多个数据包,需要拆分数据包);合包(Server收到的数据只是包的一部分,需要缓存数据,合并成完整的包)。所以TCP网络通信时需要设定通信协议。常见的TCP网络通信协有HTTP/HTTPS/FTP/SMTP/POP3/IMAP/SSH/Redis/Memcache/MySQL 。如果要设计一个通用协议的Server,那么就要按照通用协议的标准去处理网络数据。除了通用协议外还可以自定义协议

    2. EOF结束符协议:EOF协议处理的原理是每个数据包结尾加一串特殊字符表示包已结束。如memcacheftpstmp都使用 作为结束符。发送数据时只需要在包末尾增加 即可。使用EOF协议处理,一定要确保数据包中间不会出现EOF,否则会造成分包错误。

      //在`swoole_server`和`swoole_client`的代码中只需要设置2个参数就可以使用EOF协议处理。
      $server->set(array(
          'open_eof_split' => true,
          'package_eof' => "
      ",
      ));
      $client->set(array(
          'open_eof_split' => true,
          'package_eof' => "
      ",
      ));
      
      
    3. 固定包头+包体协议:这种协议的特点是一个数据包总是由包头+包体2部分组成。包头由一个字段指定了包体或整个包的长度,长度一般是使用2字节/4字节整数来表示。服务器收到包头后,可以根据长度值来精确控制需要再接收多少数据就是完整的数据包

      //Swoole的Server和异步Client都是在onReceive回调函数中处理数据包,当设置了协议处理后,只有收到一个完整数据包时才会触发onReceive事件。同步客户端在设置了协议处理后,调用 $client->recv() 不再需要传入长度,recv函数在收到完整数据包或发生错误后返回。
      $server->set(array(
          'open_length_check' => true,
          'package_max_length' => 81920,
          'package_length_type' => 'n', //see php pack()
          'package_length_offset' => 0,
          'package_body_offset' => 2,
      ));
      

    10. 使用异步客户端

    PHP提供的MySQLCURLRedis 等客户端是同步的,会导致服务器程序发生阻塞。Swoole提供了常用的异步客户端组件,来解决此问题。编写纯异步服务器程序时,可以使用这些异步客户端。

    异步客户端可以配合使用SplQueue实现连接池,以达到长连接复用的目的。在实际项目中可以使用PHP提供的Yield/Generator语法实现半协程的异步框架。也可以基于Promises简化异步程序的编写。

    1. mysql

      $db = new SwooleMySQL;
      $server = array(
          'host' => '127.0.0.1',
          'user' => 'test',
          'password' => 'test',
          'database' => 'test',
      );
      $db->connect($server, function ($db, $result) {
          $db->query("show tables", function (SwooleMySQL $db, $result) {
              var_dump($result);
              $db->close();
          });
      });
      

      mysqliPDO等客户端不同,SwooleMySQL是异步非阻塞的,连接服务器、执行SQL时,需要传入一个回调数。connect的结果不在返回值中,而是在回调函数中。query的结果也需要在回调函数中进行处理。

    2. Redis

      $redis = new SwooleRedis;
      $redis->connect('127.0.0.1', 6379, function ($redis, $result) {
          $redis->set('test_key', 'value', function ($redis, $result) {
              $redis->get('test_key', function ($redis, $result) {
                  var_dump($result);
              });
          });
      });
      
      

      SwooleRedis需要Swoole编译安装hiredis,详细文档参见异步Redis客户端

    3. Http

      $cli = new SwooleHttpClient('127.0.0.1', 80);
      $cli->setHeaders(array('User-Agent' => 'swoole-http-client'));
      $cli->setCookies(array('test' => 'value'));
      
      $cli->post('/dump.php', array("test" => 'abc'), function ($cli) {
          var_dump($cli->body);
          $cli->get('/index.php', function ($cli) {
              var_dump($cli->cookies);
              var_dump($cli->headers);
          });
      });
      

      SwooleHttpClient的作用与CURL完全一致,它完整实现了Http客户端的相关功能。具体请参考 HttpClient文档

    4. 其他客户端
      Swoole底层目前只提供了最常用的MySQLRedisHttp异步客户端,如果你的应用程序中需要实现其他协议客户端,如KafkaAMQP等协议,可以基于SwooleClient异步TCP客户端,开发相关协议解析代码,来自行实现。

    11. 多进程共享数据

    由于PHP语言不支持多线程,因此Swoole使用多进程模式。在多进程模式下存在进程内存隔离,在工作进程内修改global全局变量和超全局变量时,在其他进程是无效的。设置worker_num=1时,不存在进程隔离,可以使用全局变量保存数据

    1. 进程隔离进程隔离

      $fds = array();
      $server->on('connect', function ($server, $fd){
          echo "connection open: {$fd}
      ";
          global $fds;
          $fds[] = $fd;
          var_dump($fds);
      });
      

      $fds 虽然是全局变量,但只在当前的进程内有效。Swoole服务器底层会创建多个Worker进程,在var_dump($fds)打印出来的值,只有部分连接的fd

      对应的解决方案就是使用外部存储服务:数据库,如:MySQLMongoDB;缓存服务器,如:RedisMemcache;磁盘文件,多进程并发读写时需要加锁

      普通的数据库和磁盘文件操作,存在较多IO等待时间。因此推荐使用:Redis 内存数据库,读写速度非常快;/dev/shm内存文件系统,读写操作全部在内存中完成,无IO`消耗,性能极高

    2. 共享内存
      PHP提供了多套共享内存的扩展,但实际上真正在实际项目中可用的并不多。

      • shm扩展(不推荐),提供了shm_put_var/shm_get_var共享内存读写方法。但其底层实现使用链表结构,在保存大量数值时时间复杂度为O(N),性能非常差。并且读写数据没有加锁,存在数据同步问题,需要使用者自行加锁。
      • shmop扩展(不推荐),提供了shmop_read/shmop_write共享内存读写方法。仅提供了基础的共享内存操作指令,并未提供数据结构和封装。不适合普通开发者使用。
      • apcu扩展,提供了apc_fetch/apc_store可以使用Key-Value方式访问。APC扩展总体上是可以用于实际项目的,缺点是锁的粒度较粗,在大量并发读写操作时锁的碰撞较为密集。(yac扩展,不适合用于保存数据,其设计原理导致存在一定的数据miss率,仅作为缓存,不可作为存储)
      • swoole/table扩展,Swoole官方提供的共享内存读写工具,提供了Key-Value操作方式,使用非常简单。底层使用自旋锁实现,在大量并发读写操作时性能依然非常强劲。推荐使用。Table仍然存在两个缺点(提前申请内存,Table在使用前就需要分配好内存,可能会占用较多内存;无法动态扩容,Table内存管理是静态的,不支持动态申请新内存,因此一个Table在设置好行数并创建之后,使用时不能超过限制),使用时需要根据实际情况来选择。

    12. 使用协程客户端(version>=4.2.5, 协程编程须知)

    在最新的4.x版本中,协程取代了异步回调,作为我们推荐使用的编程方式。协程解决了异步回调编程困难的问题。使用协程可以以传统同步编程的方法编写代码,底层自动切换为异步IO,既保证了编程的简单性,又可借助异步IO,提升系统的并发能力。

    1. 协程实例

      $http = new swoole_http_server("0.0.0.0", 9501);
      $http->on('request', function ($request, $response) {
          $db = new SwooleCoroutineMySQL();
          $db->connect([
              'host' => '127.0.0.1',
              'port' => 3306,
              'user' => 'user',
              'password' => 'pass',
              'database' => 'test',
          ]);
          $data = $db->query('select * from test_table');
          $response->end(json_encode($data));
      });
      $http->start();
      
      

      上面的代码编写与同步阻塞模式的程序完全一致的。但是底层自动进行了协程切换处理,变为异步IO。因此:服务器可以应对大量并发,每个请求都会创建一个新的协程,执行对应的代码;某些请求处理较慢时,只会引起这一个请求被挂起,不影响其他请求的处理

    2. 其他协程组件
      Swoole4扩展提供了丰富的协程组件,如RedisTCP/UDP/Unix客户端、Http/WebSocket/Http2`客户端,使用这些组件可以很方便地实现高性能的并发编程。使用协程时请认真阅读 协程编程须知,避免发生错误。

    3. 适用场景

      • 高并发服务,如秒杀系统、高性能API接口、RPC服务器,使用协程模式,服务的容错率会大大增加,某些接口出现故障时,不会导致整个服务崩溃
      • 爬虫,可实现非常巨大的并发能力,即使是非常慢速的网络环境,也可以高效地利用带宽
      • 即时通信服务,如IM聊天、游戏服务器、物联网、消息服务器等等,可以确保消息通信完全无阻塞,每个消息包均可即时地被处理

    13. 进程创建

    //创建进程对应的执行函数
    function doProcess(swoole_process $worker){
        echo "PID".$worker->pid."
    ";
        sleep(10);
    }
    /*
     * 创建一个进程
     * $function 子进程创建成功后执行的函数
     * $redirect_stdin_stdout 重定向子进程的标准输入输出
     * $create_pipe 是否创建管道。启用
     * $redirect_stdin_stdout 将忽略用户的参数
     */
    $process = new swoole_process("doProcess");
    $pid = $process->start();
    //创建多个进程,继续new swoole_process();
    $process = new swoole_process("doProcess");
    $pid = $process->start();
    //等待结束,避免出现僵尸进程
    swoole_process::wait();
    

    14. 进程事件

    <?php
    $workers = [];//进程池
    //创建 启动进程
    for($i=0; $i<3; $i++){
        $process = new swoole_process("doProcess");//创建单独进程
        $pid = $process->start();//启动进程,并获取进程pid
        $workers[$pid] = $process;//存入 进程池
    }
    // 创建进程执行函数
    function doProcess(swoole_process $process){
        $process->write("pid:$process->pid");//子进程写入信息,写入到管道里
        echo "写入信息: $process->pid $process->callback";
    }
    //添加进程事件,向每个子进程添加需要执行的动作
    foreach($workers as $process){
        swoole_event_add($process->pipe, function($pipe) use($process){
           $data = $process->read();//读取管道中的数据
            echo "接收到: $data 
    ";
        });
    }
    

    在这里插入图片描述

    15. 进程队列通信

    $workers = [];
    $worker_num = 2;
    //批量创建进程
    for($i=0;$i<$worker_num;$i++){
        //利用管道通信
        $process = new swoole_process("doProcess", false, false);
        $process->useQueue();//开启队列(类似开辟了新的内存)
        $pid = $process->start();
        $workers[$pid] = $process;
    }
    // 进程执行函数
    function doProcess(swoole_process $process){
        $recv = $process->pop();//默认8192个长度
        echo "从主进程获取到的数据:$recv 
    ";
        sleep(5);
        $process->exit(0);
    }
    // 主进程 向子进程添加数据
    foreach ($workers as $pid=>$process){
        $process->push("Hell 子进程 $pid 
    ");
    }
    // 等待子进程结束,回收资源
    for($i=0;$i<$worker_num;$i++){
        $ret = swoole_process::wait();//等待执行完成
        $pid = $ret['pid'];
        unset($workers[$pid]);
        echo "子进程退出 $pid 
    ";
    }
    

    在这里插入图片描述

    16. 信号触发

    //触发函数
    swoole_process::signal(SIGALRM, function (){
        static $i = 0;
        echo "$i 
    ";
        $i++;
        if($i>10){
            swoole_process::alarm(-1);//清除定时器
        }
    });
    //定时信号
    swoole_process::alarm(100*1000);
    

    在这里插入图片描述

    17. 锁机制

    //锁包含:文件锁/读写锁/信号量/互斥锁/自旋锁
    //创建锁对象
    $lock = new swoole_lock(SWOOLE_MUTEX);//互斥锁
    echo "创建互斥锁 
    ";
    $lock->lock();//开始锁定 主进程
    if(pcntl_fork() > 0){
        sleep(1);
        $lock->unlock();//解锁
    } else{
        echo "子进程 等待锁 
    ";
        $lock->lock();//子进程上锁
        echo "子进程获取锁
    ";
        $lock->unlock();//释放锁
        exit("子进程退出");
    }
    echo "主进程 释放锁";
    unset($lock);
    sleep(1);
    echo "子进程退出";
    

    在这里插入图片描述

    18. DNS查询

    //dns 查询
    //执行dns查询
    swoole_async_dns_lookup("www.baidu.com",function ($host,$ip){
        echo "$host $ip";
    });
    

    19. 异步文件的读取

    swoole_async_readfile(__DIR__."a.txt", function ($filename, $content){
        echo "$filename $content";
    });
    

    20. 异步文件的写入

    $content = "hello world";
    swoole_async_writefile("2.txt", $content, function ($filename){
        echo $filename;
    });
    

    21. 异步事件

    $fp = stream_socket_client("tcp://www.qq.com:80", $errorno, $errstr, 30);
    fwrite($fp, "GET / HTTP/1.1
    Host:www.qq.com
    
    ");
    //添加我们的异步事件
    swoole_event_add($fp, function($fp){
        $resp = fread($fp, 8192);
        var_dump($resp);
        swoole_event_del($fp);
        fclose($fp);
    });
    echo "这个先执行完成
    ";
    

    在这里插入图片描述

    22. 异步mysql

    $db = new swoole_mySQL();
    $config = [
      'host' => '127.0.0.1',
        'user' => 'root',
        'password' => 'root',
        'database' => 'mysql',
        'charset' => 'utf8',
    ];
    $db->connect($config, function ($db, $r){
        if($r == false){
            var_dump($db->connect_errno, $db->connect_errno);
            die('失败');
        }
        $sql = ' show tables';
        $db->query($sql, function(swoole_mySQL $db, $r){
            if($r == false){
                var_dump($db->error);
                die("操作失败");
            } elseif($r == true) {
                var_dump($db->affected_rows, $db->insert_id);
            }
            var_dump($r);
            $db->close();
        });
    });
    

    22. http/server 静态资源处理

    $server = new swoole_server("0.0.0.0", 9501);
    $server -> set([
    	'enable_static_handler' = true,
    	'document_root' = '/data/',
    ]);
    
  • 相关阅读:
    C++虚继承内存布局
    编译OpenJDK记录
    Node.js + Express 调研
    软件工程开发工具
    Servlets & JSP & JavaBean 参考资料
    Eclipse AST 相关资料
    Git & github 最常用操作笔记
    Java入门学习资料整理
    从变量的类型转换看C语言的思维模式
    数学地图(1)
  • 原文地址:https://www.cnblogs.com/daozhangblog/p/12446468.html
Copyright © 2020-2023  润新知