Swoole筆記(三)

WebSocket

使用Swoole能夠很簡單的搭建異步非阻塞多進程的WebSocket服務器。php

WebSocket服務器

<?php
$server = new swoole_websocket_server("0.0.0.0", 9501);

$server->set(array(
    'daemonize' => false,
    'worker_num' => 2,
));

$server->on('Start', function (swoole_websocket_server $server) {
    echo "Server Start... \n";
    swoole_set_process_name("swoole_websocket_server");
});

$server->on('ManagerStart', function (swoole_websocket_server $server) {
    echo "ManagerStart\n";
});

$server->on('WorkerStart', function (swoole_websocket_server $server, $worker_id) {
    echo "WorkerStart \n";
    if ($server->worker_id == 0){
        swoole_timer_tick(10000,function($id) use ($server) {
            echo "test timer\n";
        });
    }
});

$server->on('Open', function (swoole_websocket_server $server, $request) {
    echo "server: handshake success with fd{$request->fd}\n";
});

$server->on('Message', function (swoole_websocket_server $server, $frame) {
    echo "receive from {$frame->fd}:{$frame->data},opcode:{$frame->opcode},fin:{$frame->finish}\n";
    $server->push($frame->fd, "this is server");
});

$server->on('Close', function ($ser, $fd) {
    echo "client {$fd} closed\n";
});

$server->start();

shell裏直接運行php swoole_ws_server.php啓動便可。若是設置了後臺運行,能夠使用下列命令強殺進程:html

kill -9 $(ps aux|grep swoole|grep -v grep|awk '{print $2}')

或者從新啓動worker進程:nginx

kill -10 $(ps aux|grep swoole_websocket_server|grep -v grep|awk '{print $2}')

輸出:git

[2017-06-01 22:06:21 $2479.0]    NOTICE    Server is reloading now.
WorkerStart 
WorkerStart

注意:github

  • onMessage回調函數爲必選,當服務器收到來自客戶端的數據幀時會回調此函數。
/**
* @param $server
* @param $frame 包含了客戶端發來的數據幀信息;使用$frame->fd獲取fd;$frame->data獲取數據內容
*/
function onMessage(swoole_server $server, swoole_websocket_frame $frame)
  • 使用$server->push()向客戶端發送消息。長度最大不得超過2M。發送成功返回true,發送失敗返回false。
function swoole_websocket_server->push(int $fd, string $data, int $opcode = 1, bool $finish = true);

WebSocket客戶端

最簡單的是使用JS編寫:web

socket = new WebSocket('ws://192.168.1.107:9501/'); 
socket.onopen = function(evt) { 
    // 發送一個初始化消息
    socket.send('I am the client and I\'m listening!'); 
}; 

// 監聽消息
socket.onmessage = function(event) { 
    console.log('Client received a message', event); 
}; 

// 監聽Socket的關閉
socket.onclose = function(event) { 
    console.log('Client notified socket has closed',event); 
}; 

socket.onerror = function(evt) { 
    console.log('Client onerror',event); 
};

Swoole裏沒有直接提供swoole_websocket客戶端,不過經過引入WebSocketClient.php文件能夠實現:redis

<?php

require_once __DIR__ . '/WebSocketClient.php';

$client = new WebSocketClient('192.168.1.107', 9501);

if (!$client->connect())
{
    echo "connect failed \n";
    return false;
}

$send_data = "I am client.\n";
if (!$client->send($send_data))
{
    echo $send_data. " send failed \n";
    return false;
}

echo "send succ \n";
return true;

上面代碼實現的是一個同步的swoole_websocket客戶端。發送完消息會自動關閉,能夠用來與php-fpm應用協做:將耗時任務使用客戶端發送到swoole_websocket_server。shell

如何建立一個聊天室

實際項目裏,咱們能夠將用戶uid和fd進行雙向綁定(暫不考慮多臺服務器分佈式部署狀況),例如使用Redis保存:在onMessage進行用戶信息驗證後:瀏覽器

$this->redis->set($fd, $uid);
$this->redis->set($uid, $fd);

後續須要指定給某人發消息,只須要根據uid/fd發送便可。在onClose事件裏進行解綁操做。羣發的話只須要遍歷一遍$server->connections便可。服務器

示例(該項目只實現羣發):
moell-peng/webim: PHP + Swoole 實現的簡單聊天室
https://github.com/moell-peng...

HttpServer

swoole內置Http服務器的支持。swoole版的http server相對於php-fpm,最大優點在於高性能:代碼一次載入內存,後續無需再解釋執行。缺點是調試沒有nginx+php-fpm方便。

使用swoole,經過幾行代碼便可寫出一個異步非阻塞多進程的Http服務器:

<?php
$serv = new swoole_http_server("0.0.0.0", 9502);

$serv->on('Start', function() {
    echo 'Start';
});

$serv->on('Request', function($request, $response) {
    var_dump($request->get);
    var_dump($request->post);
    var_dump($request->cookie);
    var_dump($request->files);
    var_dump($request->header);
    var_dump($request->server);

    $response->cookie("User", "Swoole");
    $response->header("X-Server", "Swoole");
    $response->end("<h1>Hello Swoole!</h1>");
});

$serv->start();

shell裏使用php swoole_http_server.php運行server。瀏覽器打開http://192.168.1.107:9502/便可看到輸出。

歡迎關注公衆號及時獲取最新文章推送!
clipboard.png

相關文章
相關標籤/搜索