宅男在线永久免费观看网直播,亚洲欧洲日产国码无码久久99,野花社区在线观看视频,亚洲人交乣女bbw,一本一本久久a久久精品综合不卡

全部
常見問題
產(chǎn)品動態(tài)
精選推薦

【輕松掌握】Swoole簡單入門教程,讓你成為PHP高手!

管理 管理 編輯 刪除

Swoole簡單入門示例

Swoole可以讓PHP 開發(fā)人員可以編寫高性能的異步并發(fā) TCP、UDP、Unix Socket、HTTP,WebSocket 服務(wù)。Swoole 可以廣泛應(yīng)用于互聯(lián)網(wǎng)、移動通信、企業(yè)軟件、云計算、網(wǎng)絡(luò)游戲、物聯(lián)網(wǎng)(IOT)、車聯(lián)網(wǎng)、智能家居等領(lǐng)域。

前提

使用Composer構(gòu)建項目,構(gòu)建好項目。

或者利用搜索引擎。

本篇介紹以下幾個示例:

一、??使用Swoole發(fā)送郵件??

二、使用Swoole實現(xiàn)在線聊天

三、使用Systemctl管理Swoole服務(wù)

四、使用Swoole實現(xiàn)毫秒級定時任務(wù)

五、使用Websocket上傳文件

使用composer安裝郵件發(fā)送組件:phpmailer

composer require phpmailer/phpmailer

主程序

在目錄:src/app/下建立Mail.php,用作Swoole服務(wù)端主程序。


namespace Shanhubei\Swoole;

use swoole_server;
use Redis;
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;

class Mail
{
    protected $serv;
    protected $host = '127.0.0.1';
    protected $port = 9502;
    // 進(jìn)程名稱
    protected $taskName = 'swooleMailer';
    // PID路徑
    protected $pidPath = '/run/swooleMail.pid';
    // 設(shè)置運行時參數(shù)
    protected $options = [
        'worker_num' => 4, //worker進(jìn)程數(shù),一般設(shè)置為CPU數(shù)的1-4倍  
        'daemonize' => true, //啟用守護(hù)進(jìn)程
        'log_file' => '/data/logs/swoole.log', //指定swoole錯誤日志文件
        'log_level' => 0, //日志級別 范圍是0-5,0-DEBUG,1-TRACE,2-INFO,3-NOTICE,4-WARNING,5-ERROR
        'dispatch_mode' => 1, //數(shù)據(jù)包分發(fā)策略,1-輪詢模式
        'task_worker_num' => 4, //task進(jìn)程的數(shù)量
        'task_ipc_mode' => 3, //使用消息隊列通信,并設(shè)置為爭搶模式
        //'heartbeat_idle_time' => 600, //一個連接如果600秒內(nèi)未向服務(wù)器發(fā)送任何數(shù)據(jù),此連接將被強制關(guān)閉
        //'heartbeat_check_interval' => 60, //啟用心跳檢測,每隔60s輪循一次
    ];
    // 郵件服務(wù)器配置
    protected $mailConfig = [
        'smtp_server' => 'smtp.163.com',
        'username' => '[email protected]',
        'password' => '密碼/口令',// SMTP 密碼/口令
        'secure' => 'ssl', //Enable TLS encryption, `ssl` also accepted
        'port' => 465, // tcp郵件服務(wù)器端口
    ];
    // 安全密鑰
    protected $safeKey = 'MDDGnQE33ytd2jDFADS39DSEWsdD24sK';


    public function __construct($mailConfig, $options = [])
    {
        // 構(gòu)建Server對象,監(jiān)聽端口
        $this->serv = new swoole_server($this->host, $this->port);

        if (!empty($options)) {
            $this->options = array_merge($this->options, $options);
        }
        $this->serv->set($this->options);

        $this->mailConfig = $mailConfig;

        // 注冊事件
        $this->serv->on('Start', [$this, 'onStart']);
        $this->serv->on('Connect', [$this, 'onConnect']);
        $this->serv->on('Receive', [$this, 'onReceive']);
        $this->serv->on('Task', [$this, 'onTask']);  
        $this->serv->on('Finish', [$this, 'onFinish']);
        $this->serv->on('Close', [$this, 'onClose']);

        // 啟動服務(wù)
        //$this->serv->start();
    }

    protected function init()
    {
        //
    }

    public function start()
    {
        // Run worker
        $this->serv->start();
    }

    public function onStart($serv)
    {
        // 設(shè)置進(jìn)程名
        cli_set_process_title($this->taskName);
        //記錄進(jìn)程id,腳本實現(xiàn)自動重啟
        $pid = "{$serv->master_pid}\n{$serv->manager_pid}";
        file_put_contents($this->pidPath, $pid);
    }

    //監(jiān)聽連接進(jìn)入事件
    public function onConnect($serv, $fd, $from_id)
    {
        $serv->send($fd, "Hello {$fd}!" );
    }

    // 監(jiān)聽數(shù)據(jù)接收事件
    public function onReceive(swoole_server $serv, $fd, $from_id, $data)
    {
        $res['result'] = 'failed';
        $key = $this->safeKey;

        $req = json_decode($data, true);
        $action = $req['action'];
        $token = $req['token'];
        $timestamp = $req['timestamp'];

        if (time() - $timestamp > 180) {
            $res['code'] = '已超時';
            $serv->send($fd, json_encode($res));
            exit;
        }

        $token_get = md5($action.$timestamp.$key);
        if ($token != $token_get) {
            $res['msg'] = '非法提交';
            $serv->send($fd, json_encode($res));
            exit;
        }

        $res['result'] = 'success';
        $serv->send($fd, json_encode($res)); // 同步返回消息給客戶端
        $serv->task($data);  // 執(zhí)行異步任務(wù)

    }

    /**
    * @param $serv swoole_server swoole_server對象
    * @param $task_id int 任務(wù)id
    * @param $from_id int 投遞任務(wù)的worker_id
    * @param $data string 投遞的數(shù)據(jù)
    */
    public function onTask(swoole_server $serv, $task_id, $from_id, $data)
    {
        $res['result'] = 'failed';
        $req = json_decode($data, true);
        $action = $req['action'];
        echo date('Y-m-d H:i:s')." onTask: [".$action."].\n";
        switch ($action) {
            case 'sendMail': //發(fā)送單個郵件
                $mailData = [
                    'emailAddress' => '[email protected]',
                    'subject' => 'swoole demo',
                    'body' => '測試This is the HTML message body <b>in bold!</b>,<br/>歡迎訪問<a 
                ];
                $this->sendMail($mailData);
                break;
            case 'sendMailQueue': // 批量隊列發(fā)送郵件
                $this->sendMailQueue();
                break;
            default:
                break;
        }
    }


    /**
    * @param $serv swoole_server swoole_server對象
    * @param $task_id int 任務(wù)id
    * @param $data string 任務(wù)返回的數(shù)據(jù)
    */
    public function onFinish(swoole_server $serv, $task_id, $data)
    {
        //
    }


    // 監(jiān)聽連接關(guān)閉事件
    public function onClose($serv, $fd, $from_id) {
        echo "Client {$fd} close connection\n";
    }

    public function stop()
    {
        $this->serv->stop();
    }

    private function sendMail($mail_data = [])
    {
        $mail = new PHPMailer(true);
        try {
            $mailConfig = $this->mailConfig;
            //$mail->SMTPDebug = 2;        // 啟用Debug
            $mail->isSMTP();   // Set mailer to use SMTP
            $mail->Host = $mailConfig['smtp_server'];  // SMTP服務(wù)
            $mail->SMTPAuth = true;                  // Enable SMTP authentication
            $mail->Username = $mailConfig['username'];    // SMTP 用戶名
            $mail->Password = $mailConfig['password'];     // SMTP 密碼/口令
            $mail->SMTPSecure = $mailConfig['secure'];     // Enable TLS encryption, `ssl` also accepted
            $mail->Port = $mailConfig['port'];    // TCP 端口

            $mail->CharSet  = "UTF-8"; //字符集
            $mail->Encoding = "base64"; //編碼方式

            //Recipients
            $mail->setFrom($mailConfig['username'], 'Shanhubei'); //發(fā)件人地址,名稱
            $mail->addAddress($mail_data['emailAddress'], '親');     // 收件人地址和名稱
            //$mail->addCC('[email protected]'); // 抄送

            //Attachments
            if (isset($mail_data['attach'])) {
                $mail->addAttachment($mail_data['attach']);         // 添加附件
            }
            
            //$mail->addAttachment('/tmp/image.jpg', 'new.jpg');    // Optional name

            //Content
            $mail->isHTML(true);                                  // Set email format to HTML
            $mail->Subject = $mail_data['subject'];
            $mail->Body    = $mail_data['body'];
            //$mail->AltBody = '這是在不支持HTML郵件客戶端的純文本格式';

            $mail->send();
            return true;
        } catch (\Exception $e) {
            echo 'Message could not be sent. Mailer Error: '. $mail->ErrorInfo;
            return false;
        }
    }
    
    // 郵件發(fā)送隊列
    private function sendMailQueue()
    {
        $redis = new Redis();
        $redis->connect('127.0.0.1', 6379);
       
        //$password = '123';
        //$redis->auth($password);

        swoole_timer_tick(1000, function($timer) use ($redis) { // 啟用定時器,每1秒執(zhí)行一次
            $value = $redis->lpop('mailerlist');
            if($value){
                //echo '獲取redis數(shù)據(jù):' . $value;
                $json = json_decode($value, true);
                $start = microtime(true);
                $rs = $this->sendMail($json);
                $end = microtime(true);
                if ($rs) {
                    echo '發(fā)送成功!'.$value.', 耗時:'. round($end - $start, 3).'秒'.PHP_EOL;
                } else { // 把發(fā)送失敗的加入到失敗隊列中,人工處理
                    $redis->rpush("mailerlist_err", $value);
                }
            }else{
                swoole_timer_clear($timer); // 停止定時器
                echo "Emaillist出隊完成";
            }
        });
    }

    
}

運行服務(wù)端

在public/目錄下建立mailServer.php,代碼如下:


require dirname(__DIR__) . '/vendor/autoload.php';

use Shanhubei\Swoole\Mail;

$config = [
    'smtp_server' => 'smtp.163.com',
    'username' => '[email protected]',
    'password' => 'xxxx',// SMTP 密碼/口令
    'secure' => 'ssl', //Enable TLS encryption, `ssl` also accepted
    'port' => 465, // tcp郵件服務(wù)器端口
];
$server = new Mail($config);
$server->start();

你可以注冊一個163郵箱,然后開通smtp功能。我DEMO中使用的是163郵箱發(fā)郵件發(fā)多了被封號了,所以在線演示demo沒上傳了。配置好郵件服務(wù)器參數(shù)后,運行:

php mailServer.php

此時再使用命令??netstat -lntp??查看進(jìn)程。

運行客戶端

在public/目錄下新建mailClient.php,代碼如下:

class Client
{
    private $client;
    
    public function __construct() {
        $this->client = new swoole_client(SWOOLE_SOCK_TCP);
    }

    public function connect($type) {
        if( !$this->client->connect("127.0.0.1", 9502 , 1) ) {
            echo "Error: {$this->client->errMsg}[{$this->client->errCode}]\n";
        }
        // fwrite(STDOUT, "請輸入消息 Please input msg:");
        // $msg = trim(fgets(STDIN));
        $action = 'sendMail';
        if($type == 'q'){
            $action = 'sendMailQueue';
        }
        $time = time();
        $key = 'MDDGnQE33ytd2jDFADS39DSEWsdD24sK';
        $token = md5($action.$time.$key);
        $data = [
            'action' => $action,
            'token' => $token,
            'timestamp' => $time
        ];
        $msg = json_encode($data);

        $this->client->send( $msg );
        $message = $this->client->recv();
        echo "Get Message From Server:{$message}\n";
    }
}

$type = 'q';  //區(qū)分批量和單個發(fā)送標(biāo)志

if($type == 'q'){
    $redis = new \Redis();
    $redis->connect('127.0.0.1', 6379);

    //$password = '123456x';
    ///$redis->auth($password);

    $arr = [];

    $arr[0] = [
        'subject' => '注冊cloudfog-HA',
        'emailAddress' => '[email protected]',
        'body' => '您好,您的CloudFog使用的用戶名是:123, 密碼是:123。<br/>請不要將此郵件泄漏給他人,并盡快登錄CloudFog更換新密碼。如有疑問請聯(lián)系管理員。'
    ];
    $arr[1] = [
        'subject' => '注冊cloudfog2',
        'emailAddress' => '[email protected]',
        'body' => '<a  target="_blank">網(wǎng)易郵箱</a>'
    ];
          
    foreach ($arr as $k=>$v) {
        $redis->rpush("mailerlist", json_encode($v, JSON_UNESCAPED_UNICODE));
    }   
}

$client = new Client();
$client->connect($type);

運行命令啟動客戶端:

php mailClient.php

此時在命令行窗口會返回如下信息:

[root@localhost public]# php mailClient.php 
Get Message From Server:{"result":"success"}

這樣就已經(jīng)執(zhí)行郵件發(fā)送任務(wù)了,如果出現(xiàn)故障,可以查看日志文件??/data/logs/swoole.log??。

然后你可以去查看對方郵箱是否收到相關(guān)郵件。

本文中使用了redis作為簡單隊列,你也可以使用復(fù)雜點的隊列rabbitmq。你也可以使用Crontab來做定時任務(wù),不過它最小粒度是分鐘級別的。當(dāng)然對于批量發(fā)送郵件,如果你不用php的話,可以用Python或者Java,它們都有相當(dāng)成熟的解決方案。

二、使用Swoole實現(xiàn)在線聊天

建立服務(wù)端主程序

準(zhǔn)備工作就緒后,我們開始來擼代碼。

首先在項目目錄:src/app/ 下建立??Chat.php??,用作Swoole服務(wù)端主程序。

Chat.php文件的主體結(jié)構(gòu)是這樣的:


namespace Shanhubei\Swoole;
use swoole_websocket_server;
class Chat
{
    protected $ws;
    protected $host = '0.0.0.0';
    protected $port = 9504;
    // 進(jìn)程名稱
    protected $taskName = 'swooleChat';
    // PID路徑
    protected $pidFile = '/run/swooleChat.pid';
    // 設(shè)置運行時參數(shù)
    protected $options = [
        'worker_num' => 4, //worker進(jìn)程數(shù),一般設(shè)置為CPU數(shù)的1-4倍  
        'daemonize' => true, //啟用守護(hù)進(jìn)程
        'log_file' => '/data/logs/chatswoole.log', //指定swoole錯誤日志文件
        'log_level' => 3, //日志級別 范圍是0-5,0-DEBUG,1-TRACE,2-INFO,3-NOTICE,4-WARNING,5-ERROR
        'dispatch_mode' => 1, //數(shù)據(jù)包分發(fā)策略,1-輪詢模式
    ];
 

    public function __construct($options = [])
    {
        $this->ws = new swoole_websocket_server($this->host, $this->port);

        if (!empty($options)) {
            $this->options = array_merge($this->options, $options);
        }
        $this->ws->set($this->options);

        $this->ws->on("open", [$this, 'onOpen']);
        $this->ws->on("message", [$this, 'onMessage']);
        $this->ws->on("close", [$this, 'onClose']);
    }

    public function start()
    {
        // Run worker
        $this->ws->start();
    }

    public function onOpen(swoole_websocket_server $ws, $request)
    {
        // 設(shè)置進(jìn)程名
        cli_set_process_title($this->taskName);
        //記錄進(jìn)程id,腳本實現(xiàn)自動重啟
        $pid = "{$ws->master_pid}\n{$ws->manager_pid}";
        file_put_contents($this->pidFile, $pid);

        echo "server: handshake success with fd{$request->fd}\n";
    }

    public function onMessage(swoole_websocket_server $ws, $frame)
    {
        //$ws->push($frame->fd, "server-push:".date("Y-m-d H:i:s"));
        $connets = $ws->connections;
        echo count($connets)."\n";
        echo $frame->data. "\n";
        if ($frame->data == '美女') {
            $mmpic = [
                'http://pic15.photophoto.cn/20100402/0036036889148227_b.jpg',
                'http://pic23.nipic.com/20120814/5914324_155903179106_2.jpg',
                'http://pic40.nipic.com/20140403/8614226_162017444195_2.jpg'
            ];
            $picKey = array_rand($mmpic);
            $ws->push($frame->fd, file_get_contents($mmpic[$picKey]), WEBSOCKET_OPCODE_BINARY);
        } else {
            $ws->push($frame->fd, $this->reply($frame->data));
        }
        
    }

    public function onClose($ws, $fid)
    {
        echo "client {$fid} closed\n";
        foreach ($ws->connections as $fd) {
            $ws->push($fd, $fid. '已離開!');
        }
    }

    private function reply($str) {
        $str = mb_strtolower($str);
        switch ($str) {
            case 'hello':
                $res = 'Hello, Friend.';
                break;

            case 'fuck':
                $res = 'Fuck bitch.';
          
                break;
            case 'ping':
                $res = 'PONG.';
                break;
            case 'time':
                $res = date('H:i:s');
                break;
            
            default:
                $res = $str;
                break;
        }
        return $res;
    }
}

我們需要往??onMessage()??方法里填代碼。在這里,服務(wù)端接收客戶端消息,并作出相應(yīng)動作。Websocket可以向客戶端發(fā)送字符串、二進(jìn)制等形式消息。

public function onMessage(swoole_websocket_server $ws, $frame)
    {
        //$ws->push($frame->fd, "server-push:".date("Y-m-d H:i:s"));
     if ($frame->data == '美女') {
            $mmpic = [
                'http://pic15.photophoto.cn/20100402/0036036889148227_b.jpg',
                'http://pic23.nipic.com/20120814/5914324_155903179106_2.jpg',
                'http://pic40.nipic.com/20140403/8614226_162017444195_2.jpg'
            ];
            $picKey = array_rand($mmpic); //隨機返回一張圖片
            $ws->push($frame->fd, file_get_contents($mmpic[$picKey]), WEBSOCKET_OPCODE_BINARY);
        } else {
            $ws->push($frame->fd, $this->reply($frame->data));
        }
    }

    private function reply($str) {
        $str = mb_strtolower($str);
        switch ($str) {
            case 'hello':
                $res = 'Hello, Friend.';
                break;

            case 'fuck':
                $res = 'Fuck bitch.';
                break;
            case 'ping':
                $res = 'PONG.';
                break;
            case 'time':
                $res = date('H:i:s');
                break;
            
            default:
                $res = $str;
                break;
        }
        return $res;
    }

將上面代碼加入到Chat.php中,用來處理接收消息并響應(yīng)回復(fù)。響應(yīng)回復(fù)的內(nèi)容可以根據(jù)實際情況修改,本代碼只是用來演示。

啟動服務(wù)端

在public/目錄下建立chatServer.php,代碼如下:

require dirname(__DIR__) . '/vendor/autoload.php';

use Shanhubei\Swoole\Chat;

$opt = [
    'daemonize' => true
];
$ws = new Chat($opt);
$ws->start();

然后運行以下代碼啟動服務(wù)端:??php chatServer.php?? 如果一切正常,你可以netstat -lntp看一下,系統(tǒng)會監(jiān)聽進(jìn)程名為swooleChat,端口為9504的服務(wù)。

啟動客戶端

我們使用HTML5的websocket客戶端來連接服務(wù)端,本地建立wsClient.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name=viewport content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
    <title>Client</title>
    <link rel="stylesheet" >
    <link rel="stylesheet" href="css/chat.css">
</head>
<body>
    <div id="chat-wrap">
        <div id="result"></div>
        <ul class="chat-thread">
            <li class="you"><img class="head" src="images/head1.jpg" alt=""><p>Are we meeting today?</p></li>
            <li class="you"><img class="head" src="images/head1.jpg" alt=""><p>yes</p></li>
            <li class="me"><img class="head" src="images/head1.jpg" alt=""><p>一部分保持在行尾,另一部分換到下一行。</p></li>
            <li class="you"><img class="head" src="images/head1.jpg" alt=""><p>yes</p></li>
            <li class="you"><img class="head" src="images/head1.jpg" alt=""><p>yes</p></li>
        </ul>
        
    </div>
    <div class="send">
        <form action="">
          <input type="text" class="form-control" id="m" autocomplete="off" placeholder="請輸入內(nèi)容">
          <button type="submit" class="btn btn-info">發(fā)送</button>
        </form>
    </div>
<!-- <div>
    <div id="result"></div>
    <form class="form-inline" action="">
      <div class="form-group">
        <input type="text" class="form-control" id="m" autocomplete="off" placeholder="請輸入內(nèi)容">
      </div>
      <button type="submit" class="btn btn-info">發(fā)送</button>
    </form>
</div> -->
<script src="https://cdn.bootcss.com/jquery/2.2.4/jquery.min.js"></script>
<script>
if ("WebSocket" in window) {
    var ws = new WebSocket("ws://192.168.3.105:9504");

    var result = document.querySelector('#result');

    var chatthread = document.querySelector('.chat-thread');
    chatthread.scrollTop = chatthread.scrollHeight;

    ws.onopen = function() {
        result.innerHTML = '已連接上!';
        $('#result').show().html('已連接上!').fadeOut(1500);
        console.log('已連接上!');
    }

    document.querySelector('form').onsubmit = function(e) {
        var msg = document.querySelector('#m').value;
        ws.send(msg);
        $('.chat-thread').append('<li class="me"><img class="head" src="images/head1.jpg" alt=""><p>'+msg+'</p></li>');
        chatthread.scrollTop = chatthread.scrollHeight;
        document.querySelector('#m').value = '';
        return false;
    }
    ws.onmessage = function(e) {
        if(e.data instanceof Blob) {
            // var img = document.createElement("img");
            // img.src = window.URL.createObjectURL(e.data);
            // result.appendChild(img);
            // var d = window.URL.createObjectURL(e.data);
            // console.log(d);
            var img = '<img src="'+window.URL.createObjectURL(e.data)+'" width="180"/>';
            $('.chat-thread').append('<li class="you"><img class="head" src="images/head1.jpg" alt=""><p>'+img+'</p></li>');
        }else {
            // var p = document.createElement("p");
            // p.innerHTML = e.data;
            // result.appendChild(p);
            $('.chat-thread').append('<li class="you"><img class="head" src="images/head1.jpg" alt=""><p>'+e.data+'</p></li>');
        }
        chatthread.scrollTop = chatthread.scrollHeight;
    }
    ws.onclose = function() {
        console.log('連接已關(guān)閉!');
    }
} else {
    alert('您的瀏覽器不支持 WebSocket!');
}
</script>
</body>
</html>

然后用瀏覽器打開wsClient.html,你可以看到一個聊天窗口,一開始會提示連接成功,然后你可以在輸入框中輸入你想說的話,如“美女”等等。

三、使用Systemctl管理Swoole服務(wù)

配置Swoole服務(wù)

有了Systemctl,我們可以輕松配置我們的Swoole服務(wù),下面以Swoole聊天服務(wù)為例:

首先在??/usr/lib/systemd/system/??目錄下,新建文件swoolechat.service,并加入以下代碼:

[Unit]
Description=Swoole Chat Server
After=network.target syslog.target

[Service]
Type=forking
LimitNOFILE=65535
ExecStart=/usr/local/php/bin/php /home/web/swoole/public/chatServer.php
ExecReload=/bin/kill -USR1 $MAINPID
Restart=always

[Install]
WantedBy=multi-user.target graphical.target

然后保存好文件,并使用如下命令重新載入所有的[Unit]文件,確保我們添加進(jìn)去的service能被系統(tǒng)加載并生效。

systemctl  daemon-reload

驗證

現(xiàn)在我們來驗證服務(wù),首先啟動swoole服務(wù):

systemctl start swoolechat.service

然后使用以下命令查看swoole服務(wù)是否正常:

systemctl status swoolechat.service

四、使用Swoole實現(xiàn)毫秒級定時任務(wù)

接著服務(wù)端代碼 ??public\taskServer.php?? :


require dirname(__DIR__) . '/vendor/autoload.php';

use Shanhubei\Swoole\Task;

$opt = [
    'daemonize' => false
];
$ser = new Task($opt);
$ser->start();

客戶端代碼 public\taskClient.php :

class Client
{
    private $client;
    
    public function __construct() {
        $this->client = new swoole_client(SWOOLE_SOCK_TCP);
    }

    public function connect() {
        if( !$this->client->connect("127.0.0.1", 9506 , 1) ) {
            echo "Error: {$this->client->errMsg}[{$this->client->errCode}]\n";
        }
        fwrite(STDOUT, "請輸入消息 Please input msg:");
        $msg = trim(fgets(STDIN));
        $this->client->send( $msg );
        $message = $this->client->recv();
        echo "Get Message From Server:{$message}\n";
    }
}

$client = new Client();
$client->connect();

驗證效果

1.啟動服務(wù)端:

php taskServer.php

2.客戶端輸入:

另開命令行窗口,執(zhí)行

[root@localhost public]# php taskClient.php 
請輸入消息 Please input msg:hello
Get Message From Server:{"result":"success"}

五、使用Websocket上傳文件

服務(wù)端

我們繼續(xù)使用Swoole實驗室:1-使用Composer構(gòu)建項目構(gòu)建好的項目,新建文件\src\app\Uploader.php:

namespace Shanhubei\Swoole;
use swoole_websocket_server;

class Uploader
{
    protected $ws;
    protected $host = '0.0.0.0';
    protected $port = 9505;
    // 進(jìn)程名稱
    protected $taskName = 'swooleUploader';
    // PID路徑
    protected $pidFile = '/run/swooleUploader.pid';
    // 設(shè)置運行時參數(shù)
    protected $options = [
        'worker_num' => 4, //worker進(jìn)程數(shù),一般設(shè)置為CPU數(shù)的1-4倍  
        'daemonize' => true, //啟用守護(hù)進(jìn)程
        'log_file' => '/data/logs/uploadswoole.log', //指定swoole錯誤日志文件
        'log_level' => 3, //日志級別 范圍是0-5,0-DEBUG,1-TRACE,2-INFO,3-NOTICE,4-WARNING,5-ERROR
        'dispatch_mode' => 1, //數(shù)據(jù)包分發(fā)策略,1-輪詢模式
    ];
 

    public function __construct($options = [])
    {
        $this->ws = new swoole_websocket_server($this->host, $this->port);

        if (!empty($options)) {
            $this->options = array_merge($this->options, $options);
        }
        $this->ws->set($this->options);

        $this->ws->on("open", [$this, 'onOpen']);
        $this->ws->on("message", [$this, 'onMessage']);
        $this->ws->on("close", [$this, 'onClose']);
    }

    public function start()
    {
        // Run worker
        $this->ws->start();
    }

    public function onOpen(swoole_websocket_server $ws, $request)
    {
        // 設(shè)置進(jìn)程名
        cli_set_process_title($this->taskName);
        //記錄進(jìn)程id,腳本實現(xiàn)自動重啟
        $pid = "{$ws->master_pid}\n{$ws->manager_pid}";
        file_put_contents($this->pidFile, $pid);

        echo "server: handshake success with fd{$request->fd}\n";
        $msg = '{"msg": "connect ok"}';
        $ws->push($request->fd, $msg);
    }

    public function onMessage(swoole_websocket_server $ws, $frame)
    {
        $opcode = $frame->opcode;
        if ($opcode == 0x08) {
            echo "Close frame received: Code {$frame->code} Reason {$frame->reason}\n";
        } else if ($opcode == 0x1) {
            echo "Text string\n";
        } else if ($opcode == 0x2) {
            echo "Binary data\n"; //
        } else {
            echo "Message received: {$frame->data}\n";
        }
        $filename = './files/aaa.jpg';
        file_put_contents($filename, $frame->data);
        echo "file path : {$filename}\n";
        $ws->push($frame->fd, 'upload success');
    }
    public function onClose($ws, $fid)
    {
        echo "client {$fid} closed\n";
        foreach ($ws->connections as $fd) {
            $ws->push($fd, $fid. '已斷開!');
        }
    }
}

$frame->opcode,WebSocket的OpCode類型,可以通過它來判斷傳輸?shù)臄?shù)據(jù)是文本內(nèi)容還是二進(jìn)制數(shù)據(jù)。

新建public/uploadServer.php,用于啟動服務(wù)端腳本:


require dirname(__DIR__) . '/vendor/autoload.php';

use Shanhubei\Swoole\Uploader;

$opt = [
    'daemonize' => false
];
$ws = new Uploader($opt);
$ws->start();

客戶端

在本地站點建立客戶端文件upload.html。只需在頁面中放置一個文件選擇控件和一個用于輸出上傳信息的div#log。

<input type="file" id="myFile">
<div id="log"></div>

當(dāng)選擇好本地文件后,觸發(fā)onchange事件,這個時候客戶端嘗試與服務(wù)端建立websocket連接,然后開始讀取本地文件,讀取完成后將數(shù)據(jù)發(fā)送給服務(wù)端。

$('#myFile').on('change', function(event) {
    var ws = new WebSocket("ws://192.168.3.106:9505");

    ws.onopen = function() {
        log('已連接上!');
    }
    ws.onmessage = function(e) {
        log("收到服務(wù)器消息:" + e.data + "'\n");
        if (e.data == 'connect ok') {
            log('開始上傳文件');
        } 
        if (e.data == 'upload success') {
            log('上傳完成');
            ws.close();
        } else {
            var file = document.getElementById("myFile").files[0];

            var reader = new FileReader();
            reader.readAsArrayBuffer(file);

            reader.onload = function(e) {
                ws.send(e.target.result);
                log('正在上傳數(shù)據(jù)...');
            }
        }
    }
    ws.onclose = function() {
        console.log('連接已關(guān)閉!');
        log('連接已關(guān)閉!');
    }
});
//在消息框中打印內(nèi)容
function log(text) {
    $("#log").append(text+"<br/>");
}

這里講一下HTML5的FileReader 對象,F(xiàn)ileReader允許Web應(yīng)用程序異步讀取存儲在用戶計算機上的文件(或原始數(shù)據(jù)緩沖區(qū))的內(nèi)容,使用 File 或 Blob 對象指定要讀取的文件或數(shù)據(jù)。FileReader提供了幾種讀取文件的方法:

  • ??reader.readAsArrayBuffer(file|blob)??:用于啟動讀取指定的 Blob 或 File 內(nèi)容。讀取文件后,會在內(nèi)存中創(chuàng)建一個ArrayBuffer對象(二進(jìn)制緩沖區(qū)),將二進(jìn)制數(shù)據(jù)存放在其中。當(dāng)讀取操作完成時,readyState 變成 DONE(已完成),并觸發(fā) loadend 事件,同時 result 屬性中將包含一個 ArrayBuffer 對象以表示所讀取文件的數(shù)據(jù)。通過此方式,可以直接在網(wǎng)絡(luò)中傳輸二進(jìn)制內(nèi)容。此外對于大文件我們可以分段讀取二進(jìn)制內(nèi)容上傳。
  • ??reader.readAsDataURL(file|blob)??:該方法會讀取指定的 Blob 或 File 對象。讀取操作完成的時候,readyState 會變成已完成(DONE),并觸發(fā) loadend 事件,同時 result 屬性將包含一個data:URL格式的字符串(base64編碼)以表示所讀取文件的內(nèi)容。
  • ??FileReader.readAsText(file|blob)??:可以將 Blob 或者 File 對象轉(zhuǎn)根據(jù)特殊的編碼格式轉(zhuǎn)化為內(nèi)容(字符串形式)。當(dāng)轉(zhuǎn)化完成后, readyState 這個參數(shù)就會轉(zhuǎn)換 為 done 即完成態(tài), event(“l(fā)oadend”) 掛載的事件會被觸發(fā),并可以通過事件返回的形參得到中的 FileReader.result 屬性得到轉(zhuǎn)化后的結(jié)果。
  • ??FileReader.readAsBinaryString()??:讀取文件內(nèi)容為二進(jìn)制字符串,已廢除,不要用了。

運行服務(wù)端

php uploadServer.php

運行客戶端

在本地站點目錄,打開upload.html

請登錄后查看

CRMEB-慕白寒窗雪 最后編輯于2023-12-15 11:17:08

快捷回復(fù)
回復(fù)
回復(fù)
回復(fù)({{post_count}}) {{!is_user ? '我的回復(fù)' :'全部回復(fù)'}}
排序 默認(rèn)正序 回復(fù)倒序 點贊倒序

{{item.user_info.nickname ? item.user_info.nickname : item.user_name}} LV.{{ item.user_info.bbs_level || item.bbs_level }}

作者 管理員 企業(yè)

{{item.floor}}# 同步到gitee 已同步到gitee {{item.is_suggest == 1? '取消推薦': '推薦'}}
{{item.is_suggest == 1? '取消推薦': '推薦'}}
沙發(fā) 板凳 地板 {{item.floor}}#
{{item.user_info.title || '暫無簡介'}}
附件

{{itemf.name}}

{{item.created_at}}  {{item.ip_address}}
打賞
已打賞¥{{item.reward_price}}
{{item.like_count}}
{{item.showReply ? '取消回復(fù)' : '回復(fù)'}}
刪除
回復(fù)
回復(fù)

{{itemc.user_info.nickname}}

{{itemc.user_name}}

回復(fù) {{itemc.comment_user_info.nickname}}

附件

{{itemf.name}}

{{itemc.created_at}}
打賞
已打賞¥{{itemc.reward_price}}
{{itemc.like_count}}
{{itemc.showReply ? '取消回復(fù)' : '回復(fù)'}}
刪除
回復(fù)
回復(fù)
查看更多
打賞
已打賞¥{{reward_price}}
2192
{{like_count}}
{{collect_count}}
添加回復(fù) ({{post_count}})

相關(guān)推薦

快速安全登錄

使用微信掃碼登錄
{{item.label}} 加精
{{item.label}} {{item.label}} 板塊推薦 常見問題 產(chǎn)品動態(tài) 精選推薦 首頁頭條 首頁動態(tài) 首頁推薦
取 消 確 定
回復(fù)
回復(fù)
問題:
問題自動獲取的帖子內(nèi)容,不準(zhǔn)確時需要手動修改. [獲取答案]
答案:
提交
bug 需求 取 消 確 定
打賞金額
當(dāng)前余額:¥{{rewardUserInfo.reward_price}}
{{item.price}}元
請輸入 0.1-{{reward_max_price}} 范圍內(nèi)的數(shù)值
打賞成功
¥{{price}}
完成 確認(rèn)打賞

微信登錄/注冊

切換手機號登錄

{{ bind_phone ? '綁定手機' : '手機登錄'}}

{{codeText}}
切換微信登錄/注冊
暫不綁定
CRMEB客服

CRMEB咨詢熱線 咨詢熱線

400-8888-794

微信掃碼咨詢

CRMEB開源商城下載 源碼下載 CRMEB幫助文檔 幫助文檔
返回頂部 返回頂部
CRMEB客服