创建websocket服务器

建议先阅读官方文档WebSocket\Server章节

  • 一、websocket介绍

  • 二、Swoole_websocket简介

  • 三、websoket服务创建

一、websocket介绍

1、websocket是什么呢?

websocket是一个协议,它仅仅就是一个协议而已,跟我们所了解的http协议、https协议、ftp协议等等一样,都是一种单纯的协议。

2、websocket的特点呢?

相对于Http这种非持久连接而言,websocket协议是一种持久化连接,它是一种独立的,基于TCP的协议。基于websocket,我们可以实现客户端和服务端双向通信。

在websocket出现之前,为了解决此类问题,常用的解决方法有轮询和long pull,这两种技术都是客户端和服务端建立源源不断的HTTP连接,非常消耗带宽和服务器资源。

websocket是双向持久连接,客户端和服务端只需要第一次建立连接即可实现双向通信。

列出WebSocket特点:

  • 建立在TCP协议

  • 性能开销小通信高效

  • 客户端可以与任意服务器通信

  • 协议标识符ws wss

  • 持久化网络通信协议(长连接)

二、Swoole_websocket简介

  • Swoole增加了内置的WebSocket服务器支持,通过几行PHP代码就可以写出一个异步非阻塞多进程的WebSocket服务器。

  • 1、websocket_server是在swoole_http_server基础之上做了协议解析

  • 2、完整的websocket协议会封装在frame对象当中

三、websoket服务创建

简单示例:

<?php

$server = new swoole_websocket_server("0.0.0.0", 8812);

//监听websocket连接打开事件
$server->on('open', 'onOpen');
function onOpen($server, $request) {
    print_r($request->fd);
}

// 监听ws消息事件
$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, "singwa-push-secesss");
});

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

$server->start();

onOpen

function onOpen(swoole_websocket_server $svr, swoole_http_request $req);
  • WebSocket客户端与服务器建立连接并完成握手后会回调此函数。

  • $req 是一个Http请求对象,包含了客户端发来的握手请求信息

  • onOpen事件函数中可以调用push向客户端发送数据或者调用close关闭连接

  • onOpen事件回调是可选的

onMessage

当服务器收到来自客户端的数据帧时会回调此函数。

function onMessage(swoole_websocket_server  $server, swoole_websocket_frame $frame)
  • $frame 是swoole_websocket_frame对象,包含了客户端发来的数据帧信息

  • onMessage回调必须被设置,未设置服务器将无法启动

$frame

$frame 共有4个属性,分别是:

  • $frame->fd,客户端的socket_id,使用$server->push推送数据时需要用到。

  • $frame->data,数据内容,可以是文本内容也可以是二进制数据,可以通过opcode的值来判断

  • $frame->opcode,WebSocket的OpCode类型,可以参考WebSocket协议标准文档

  • $frame->finish, 表示数据帧是否完整,一个WebSocket请求可能会分成多个数据帧进行发送

Push方法

function WebSocket\Server->push(int $fd, $data, int $opcode = 1, bool $finish = true);

$fd 客户端连接的ID,如果指定的$fd对应的TCP连接并非websocket客户端,将会发送失败

$data 要发送的数据内容向websocket客户端连接推送数据,长度最大不得超过2M。

$data 如果是文本类型,编码格式必然是UTF-8,这是WebSocket协议规定的

$opcode,指定发送数据内容的格式,默认为文本。发送其它格式可以参考文档常量

注意:

1、连接保持+心跳

Websocket也是长连接的形式,同样支持自己实现心跳包的检测

2、校验客户端连接的有效性

我们创建的websocket_server,是对外开放的,也就是任何人都能连接过来,对于非websocket协议同样能触发,所以我们要判断当前是websocket客户端并且能够通讯才进行发送。

根据以上注意的两点,示例:

<?php

$server=new swoole\websocket\server('0.0.0.0',9500);

$server->set([
      'heartbeat_idle_time'=>30,
      'heartbeat_check_interval'=>10,
    ]
);
$server->on('open', function (swoole_websocket_server $server, $request) {
    //var_dump($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";

    //得到所有连接的客户端
   //var_dump($server->getClientList(0, 10));

    //消息广播
    sleep(3);
    foreach ($server->connection_list() as $fd ){

         //检测websocket客户端是否有效
        if($server->exist($fd)){
            //发送给客户端
            //$server->push($fd, "receive from {$fd}的消息");
            $server->push($fd, "receive from {$fd}的消息",2);
        }else{
            $server->close($fd); //关闭掉指定客户端
        }
    }
});

$server->on('receive', function ($server, $fd, $from_id, $data) {
        var_dump($data);
});

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

$server->start();

websocket client端的代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<script>

    ws = new WebSocket('ws://218.64.129.244:9500');

    ws.onopen = function(){
        ws.send('内容');
        console.log("已经打开了websocket连接,可以进行实时通信了");
    };

    ws.onmessage = function(e){
        console.log("接受到来自服务器端的数据:"+e.data);
    }

    ws.onerror=function (e) {
        console.log("连接失败");
    }


</script>
</body>
</html>

Last updated