WebSocket\Server

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

$server = new Swoole\WebSocket\Server("0.0.0.0", 9501);

$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();

onRequest回调

WebSocket\Server 继承自 Http\Server

  • 设置了onRequest回调,WebSocket\Server也可以同时作为http服务器
  • 未设置onRequest回调,WebSocket\Server收到http请求后会返回http 400错误页面
  • 如果想通过接收http触发所有websocket的推送,需要注意作用域的问题,面向过程请使用globalWebSocket\Server进行引用,面向对象可以把WebSocket\Server设置成一个成员属性

1、面向过程代码

$server = new Swoole\WebSocket\Server("0.0.0.0", 9501);
$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->on('request', function (Swoole\Http\Request $request, Swoole\Http\Response $response) {
        global $server;//调用外部的server
        // $server->connections 遍历所有websocket连接用户的fd,给所有用户推送
        foreach ($server->connections as $fd) {
            $server->push($fd, $request->get['message']);
        }
    });
$server->start();

2、面向对象代码

class WebsocketTest {
    public $server;
    public function __construct() {
        $this->server = new Swoole\WebSocket\Server("0.0.0.0", 9501);
        $this->server->on('open', function (swoole_websocket_server $server, $request) {
            echo "server: handshake success with fd{$request->fd}\n";
        });
        $this->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");
        });
        $this->server->on('close', function ($ser, $fd) {
            echo "client {$fd} closed\n";
        });
        $this->server->on('request', function ($request, $response) {
            // 接收http请求从get获取message参数的值,给用户推送
            // $this->server->connections 遍历所有websocket连接用户的fd,给所有用户推送
            foreach ($this->server->connections as $fd) {
                $this->server->push($fd, $request->get['message']);
            }
        });
        $this->server->start();
    }
}
new WebsocketTest();

客户端

  • Chrome/Firefox/高版本IE/Safari等浏览器内置了JS语言的WebSocket客户端
  • 微信小程序开发框架内置的WebSocket客户端
  • 异步的PHP程序中可以使用Swoole\Http\Client作为WebSocket客户端
  • apache/php-fpm或其他同步阻塞的PHP程序中可以使用swoole/framework提供的同步WebSocket客户端
  • WebSocket客户端不能与WebSocket服务器通信

  • 张良晖

    message和close事件都是server上的?不应该是connection上的事件吗

  • nfer

    能否也对应的开发一个 swoole_websocket_client

  • 霸气千秋

    源码的 example/websocket 目录下有个 php 实现的 WebSocketClient

  • Just_Fee1ing

    PHP Fatal error: swoole_server::on(): Unknown event types[message] 就我一个人报这个error? swoole版本1.7.17

  • guoerwei

    Argument 2 passed to {closure}() must be an instance of swoole_http_request, integer given on.('open')里面第二个参数传进来的是一个整数…

  • 小马哥

    我怎么就 new swoole_server("127.0.0.1", 9501); 能连接上, new swoole_http_server("127.0.0.1", 9501); 和 new swoole_websocket_server("0.0.0.0", 9501); 都链接不上 ,版本 1.7.19

  • 爱好者

    有没有函数判断客户端还正在链接呢

  • 阿强

    今天试难成功,连上了,按照github上的例子连了一下,服务器端的信息: PHP Notice: Undefined property: swoole_http_request::$get in /var/www/html/ws.php on line 5 int(1) NULL array(9) { ["request_method"]=> string(3) "GET" ["request_uri"]=> string(1) "/" ["path_info"]=> string(1) "/" ["request_time"]=> int(1447532507) ["server_port"]=> int(9502) ["remote_port"]=> int(53188) ["remote_addr"]=> string(13) "192.168.1.102" ["server_protocol"]=> string(8) "HTTP/1.1" ["server_software"]=> string(18) "swoole-http-server" }

  • xcwenn@qq.com

    android 哪个websocket lib 合适?!

  • 他的流年

    您好,请问我如何在服务器主动关闭一个连接呢?

  • 他的流年

    不好意思,问题已解决。是我看得不够清楚,由继承关系直接调用close函数就可以关闭连接

  • seven

    我也想知道 怎么主动关闭一个连接 没看到你的什么意思 求大大给个代码案例看呢

  • 孙佳兵

    为什么我在客户端的js方法 socket.onopen能够相应,socket.opmessage响应不了?

  • jimmy

    swoole_websocket_server 的工作进程数怎么控制?

  • heice

    在吗?请问这个要怎么实现? 接收到redis的数据又把数据从websocket传出去 var app = require('http').createServer(handler); var io = require('socket.io')(app);

    var Redis = require('ioredis'); var redis = new Redis('6379','127.0.0.1');

    app.listen(6001, function() { console.log('Server is running!'); });

    function handler(req, res) { res.writeHead(200); res.end(''); }

    io.on('connection', function(socket) { // console.log('connected'); });

    redis.psubscribe('*', function(err, count) { // console.log('count'); });

    redis.on('pmessage', function(subscribed, channel, message) { console.log(subscribed); console.log(channel); console.log(message); message = JSON.parse(message); io.emit(channel + ':' + message.event, message.data); });

  • 骑驴泡美妞

    您好,可以问下是怎么解决的么?

  • 别怕

    页面直接写上这段js就行吗?为什么我在命令行运行之后 打开有这段js的页面什么也不显示?如果直接输入地址加上端口号的就出来一个websocket已经通电的话

  • 谭少民-倬余

    请问如何分房间?

  • 猫爸爸

    求助大大们,websocket 在IE11下上传超过50M的文件时提示,报文过长然后自动断开了,这是BUG还是我方式不对?chrome没有相关的问题,前端使用FileReader.readAsArrayBuffer()读取文件 WARNING swProtocol_recv_check_length: package is too big, remote_addr=192.168.5.1:52151, length=50772334. [/documents/bin/swoole-src-master/src/network/Port.c:340@swPort_onRead_check_length]Close Event.FD=32|From=0 client 1 quit

  • 谭少民-倬余

    请问单个服务端最大支持多少链接数?

  • 张三丰

    参照max_connection配置

  • 张三丰

    分房间应该是自己业务层去自己实现

  • d7788250

    Swoole\Http\Client作为WebSocket客户端有例程吗?

  • 快捷方式

    server: handshake success with fd1 receive from 1:hello yii,opcode:1,fin:1 client 1 closed [2017-04-20 15:14:42 #11571.2] WARNING swReactorThread_send: connection#18 is closed by client. server: handshake success with fd2 receive from 2:hello yii,opcode:1,fin:1 client 2 closed [2017-04-20 15:14:45 #11571.2] WARNING swReactorThread_send: connection#18 is closed by client. server: handshake success with fd3 receive from 3:hello yii,opcode:1,fin:1 client 3 closed [2017-04-20 15:14:48 #11571.2] WARNING swReactorThread_send: connection#18 is closed by client. server: handshake success with fd4 receive from 4:hello yii,opcode:1,fin:1 client 4 closed [2017-04-20 15:14:51 #11571.2] WARNING swReactorThread_send: connection#18 is closed by client. server: handshake success with fd5 receive from 5:hello yii,opcode:1,fin:1 client 5 closed [2017-04-20 15:14:53 #11571.2] WARNING swReactorThread_send: connection#18 is closed by client.

  • 快捷方式

    $webSocketClient = new \app\exts\WebSocketClient('121.11.71.33', 8988);

        $webSocketClient->connect();
    
        $webSocketClient->send('hello yii');
    
        $webSocketClient->close();
    

  • 快捷方式

    $server = new \swoole_websocket_server("121.11.71.33", 8988);

        $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();
    

  • 快捷方式

    为什么close之后还有warning,这是哪里给clien发送信息了吗

  • 王子

    请问如何使用websocket做分布式转发服务端?貌似swoole的websocket只有server,没有client

  • CodingMan

    failed: Error in connection establishment: net::ERR_CONNECTION_TIMED_OUT 两台服务器,一台能成功,另外一台运行了websocket的例子。浏览器端js连不上报这个错,谁碰到过啊

  • wHiLe(1)追;

            if(!($roomMember = RoomMembers::find($userid)))
            {
                return false;
            }
    
            $roomid = $roomMember->roomid;
    
            //座位找到了,但未找到对应的房间
            if(!($room = Room::find($roomid)))
            {
                $roomMember->delete();
                return false;
            }
    

    如果所示经过几轮异步数据请求后,RoomMembers所获取的对象是仍然是该对象本身,但是属性却变成了Room的属性了。数据在底层发生了混乱。 虽然这是业务逻辑的代码,本应该跟Swoole没有关系。但是同样用Swoole的Socket的时候,没有这个问题(其他代码完全一样,仅接入层不一样)。我是先写好Socket版本测试没问题后,打算接入小程序才尝试的Websocket。

    另外测试方面,我是自己写的机器人,Websocket几乎每次都是跑2~3轮就出现数据混乱。而Socket版本跑几个小时,没有任何问题。由于能力有限,只能根据现象猜测是Swoole的Websocket有问题。还请抽空帮忙看一下,急等接入小程序版本的游戏。多谢!

  • wHiLe(1)追;

    继续楼上:把worker_num 设置为1后,没有这个问题。但是这样不合理啊。 Socket的时候worker_num设置为4,也是正常工作的。 是我哪里设置有问题吗?

  • wHiLe(1)追;

    继续楼上:经过进一步测试,是在采用websocket并且worker_num>1并且并发请求同一个function资源的时候,会发生这个情况。 也已经在码云上面提交BUG了。

  • 初学者想学一下swoole,希望有人给予解答: 是不是一个类似网络棋牌游戏大厅这种网页游戏,服务端就可以用swoole_websocket_server? 客户端是用http_client还是直接js的websocket? 有没有大神给解释下swoole各服务器和客户端到底怎么用?以游戏大厅为例说一下整体系统架构。

  • phper

    请问一下,IE低版本浏览器怎样用flash去连接Websocket

  • 深圳联星美洲商旅

    峰哥,swoole_websocket_server怎么用SSL啊,找了半天没找到呢。

  • 深圳联星美洲商旅

    swoole_websocket_server怎么用SSL啊,找了半天没找到呢。哪位大神给回复一下?

  • 深圳联星美洲商旅

    继续楼上,SSL证书已经取得,就是不知道咋弄……^v^

  • 深圳联星美洲商旅

    问题解决了,还是自己回复吧。在第4个参数设置即可,如: $setConfig = [ 'ssl_key_file' => '/usr/local/nginx/conf/server.key', 'ssl_cert_file' => '/usr/local/nginx/conf/server.crt' ]; $sws = new swoole_websocket_server("0.0.0.0", 9501, SWOOLE_BASE, SWOOLE_SOCK_TCP | SWOOLE_SSL); $sws->set($setConfig);

  • 注意:#onTask#方法中,不能push

  • 火端

    Websocket用起来很方便呀

  • 韩文博1

    设置onRequest回调后 依然 HTTP ERROR 400

  • Winds

    web_socket的server,为什么我每次onRequest后,push到客户端,server总会执行一次onClose,客户端那边我很确定是没有执行关闭操作的

  • rookie

    $ws = new swoole_websocket_server(); 这个是调用的哪里的方法啊 我好想没有这个类

  • 卿本佳人

    采用第二种方式,为神马出现这个错误。PHP Warning: swoole_websocket_server::push(): the connected client of connection[5] is not a websocket client.

  • 卿本佳人

    非WebSocket客户端不能与WebSocket服务器通信 这个意思是什么,只有客户段请求 requst 才可以么

  • xuping

    tick怎么结合websocket使用呢?

  • Heimo

    基于Swoole websocket实现的web聊天室demo https://heimo-he.github.io/2018/03/30/php-swoole-webim/

  • Heimo

    基于Swoole websocket实现的web聊天室demo源码 https://github.com/Heimo-He/webIM

  • Emotion

    3分钟搭建,基于Swoole-WebSocket的多人在线聊天简易版 https://github.com/ouhaohan8023/WebIM

  • 天智老师

    swoole搭建但聊天室确实非常简单,但是对于多聊天室,没看到手册?是临时不支持这个功能?

  • janray

    "Winds web_socket的server,为什么我每次onRequest后,push到客户端,server总会执行一次onClose,客户端那边我很确定是没有执行关闭操作的"

    关于这个问题:其实是浏览器默认会请求/favicon.ico 会触发一次onRequest 导致的,在head头里面加一句 即可屏蔽

  • Nemo

    是不是对面向对象有什么误解。。。。 写在类里就叫面相对象么。。。

  • sunnier

    有个问题啊,用了swoole第一天websocket很正常,第二天出现Invalid frame header,有没有类似的问题,谢谢

  • sunnier

    应该是进程已经挂了,我再试试

  • 寻路记

    websoket服务过一段时间就会连不上,重启服务就又可以了,不知道为什么

  • pandaguo

    PHP创建websocket服务器对象,监听0.0.0.0:9505端口 ,失败,没反应,这是怎么回事呢

  • Berzerk

    在学习中碰到什么问题希望能有人交流,加到群486583931一起探讨吧

  • バ 小丑男°乄°    ?

    为什么没有检测客户端链接类型的函数呐?

  • 拼个Léon

    能不能直接给swoole server增加对websocket的支持,而不是新弄个类——当然如果这个类是继承swoole server那到不必。如果不是继承swoole server,那么最好是swoole server直接支持websocket:收到客户端的第一条消息,判断下是不是websocket,如果是的话自动完成websocket握手,标记为websocket连接,以后收发都按照websocket协议来。这样,一个服务支持普通tcp和websocket,而上层根本不关心客户端用的啥协议。

  • 服务端开启一个服务后,如何主动关闭这个服务 ..只能手动关?

  • 【涩果】

    服务端如何主动推送给所有客户端

  • xfjpeter

    求救:用daemonize方式启动websocket服务器,为啥隔一段时间就会自动销毁进程呢?

  • lovnie

    为什么只能本机才能访问websocket服务端,外网的换了ip一直提示Provisional headers are shown

  • 梦逸灵箭

    nginx配置一直搞不定。。。域名+端口的访问形式。谁能指点下。。

  • &

    群里都是swoole爱好者:820469789,限技术交流,问题解答