利用Swoole实现PHP+websocket 聊天室

来源:互联网 发布:dota2 maybe知乎 编辑:程序博客网 时间:2024/05/16 15:47

websocket

Websocket只是一个网络通信协议 
就像 http、ftp等都是网络通信的协议;不要多想; 
相对于HTTP这种非持久的协议来说,Websocket是一个持久化网络通信的协议;

WebSocket和HTTP的关系

WebSocket和HTTP的关系 
有交集,但是并不是全部。 
websocket+http

Websocket只是借用了HTTP的一部分协议来完成一次握手。(HTTP的三次握手,此处只完成一次)

http和websocket 请求头对比:

websocket 
http

HTTP: 
原来的时候,客户端通过http(骑马)带着信请求服务器,服务器处理请求(写回信),再次通过http(骑马)返回;链接断开;

WebSocket: 
客户端通过http(骑马)带着信请求服务器,但同时,携带了Upgrade:websocket和Connection:Upgrade(两根管子),服务器如果支持WebSocket协议(有两根管子的接口),使用Websocket协议返回可用信息(丢弃马匹),此后信息的传递,均使用这两个管子,除非有一方人为的将管子切断; 
若服务器不支持webscoket,客户端请求链接失败,返回错误信息;

http和websocket 响应头对比: 
这里写图片描述 
这里写图片描述

websocket和ajax轮询、long poll的区别

首先是 ajax轮询 ,原理非常简单,让浏览器隔个几秒就发送一次请求,询问服务器是否有新信息 
场景再现: 
客户端:啦啦啦,有没有新信息(Request) 
服务端:没有(Response) 
客户端:啦啦啦,有没有新信息(Request) 
服务端:没有。。(Response) 
客户端:啦啦啦,有没有新信息(Request) 
服务端:你好烦啊,没有啊。。(Response) 
客户端:啦啦啦,有没有新消息(Request) 
服务端:好啦好啦,有啦给你。(Response) 
客户端:啦啦啦,有没有新消息(Request) 
服务端:。。。没。。。。没。。没有

long poll 其实原理跟 ajax轮询 差不多,都是采用轮询的方式,不在论述;

从上面可以看出,轮询其实就是在不断地建立HTTP连接,然后等待服务端处理,可以体现HTTP协议的另外一个特点,被动性。同时,http的每一次请求与响应结束后,服务器将客户端信息全部丢弃,下次请求,必须携带身份信息(cookie),无状态性

Websocket的出现,干净利落的解决了这些问题;

所以上面的情景可以做如下修改。 
客户端:啦啦啦,我要建立Websocket协议,需要的服务:chat,Websocket协议版本:17(HTTP Request) 
服务端:ok,确认,已升级为Websocket协议(HTTP Protocols Switched) 
客户端:麻烦你有信息的时候推送给我噢。。 
服务端:ok,有的时候会告诉你的。 
客户端:balab开始斗图alabala 
服务端:苍井空ala 
客户端:流鼻血了,我擦…… 
服务端:哈哈啊哈哈哈哈 
服务端:笑死我了哈哈

很遗憾:Nginx和Apache 不支持WebSocket协议!

Swoole

但是,为了用PHP配合HTML5完成一次WebSocket请求和响应,哥走过千山万水,在密林深处,发现了Swoole : http://www.swoole.com/;

PHP语言的异步、并行、高性能网络通信框架,使用纯C语言编写,提供了PHP语言的异步多线程服务器,异步TCP/UDP网络客户端,异步MySQL,数据库连接池,AsyncTask,消息队列,毫秒定时器,异步文件读写,异步DNS查询。 
支持的服务: 
HttpServer 
WebSocket Server 
TCP Server 
TCP Client 
Async-IO(异步) 
Task(定时任务)

环境依赖: 
仅支持Linux,FreeBSD,MacOS,3类操作系统 
Linux内核版本2.3.32以上 
PHP5.3.10以上版本 
gcc4.4以上版本或者clang 
cmake2.4+,编译为libswoole.so作为C/C++库时需要使用cmake

安装: 
必须保证系统中有以下这些软件: 
php-5.3.10 或更高版本 
gcc-4.4 或更高版本 
make 
autoconf

Swoole是作为PHP扩展来运行的

安装(root权限): 
cd swoole 
phpize 
./configure 
make 
sudo make install 
配置php.ini 
extension=swoole.so

想研究Swoole的同学,自己去看手册(虽然写的不好,但是还是能看懂的)

做一个聊天室

服务器端:socket.php

//创建websocket服务器对象,监听0.0.0.0:9502端口$ws = new swoole_websocket_server("0.0.0.0", 9502);//监听WebSocket连接打开事件$ws->on('open', function ($ws, $request) {    $fd[] = $request->fd;    $GLOBALS['fd'][] = $fd;    //$ws->push($request->fd, "hello, welcome\n");});//监听WebSocket消息事件$ws->on('message', function ($ws, $frame) {    $msg =  'from'.$frame->fd.":{$frame->data}\n";//var_dump($GLOBALS['fd']);//exit;    foreach($GLOBALS['fd'] as $aa){        foreach($aa as $i){            $ws->push($i,$msg);        }    }   // $ws->push($frame->fd, "server: {$frame->data}");    // $ws->push($frame->fd, "server: {$frame->data}");});//监听WebSocket连接关闭事件$ws->on('close', function ($ws, $fd) {    echo "client-{$fd} is closed\n";});$ws->start();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

客户端:Socket.html

<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <title>Title</title></head><body><div id="msg"></div><input type="text" id="text"><input type="submit" value="发送数据" onclick="song()"></body><script>    var msg = document.getElementById("msg");    var wsServer = 'ws://192.168.1.253:9502';    //调用websocket对象建立连接:    //参数:ws/wss(加密)://ip:port (字符串)    var websocket = new WebSocket(wsServer);    //onopen监听连接打开    websocket.onopen = function (evt) {        //websocket.readyState 属性:        /*        CONNECTING  0   The connection is not yet open.        OPEN    1   The connection is open and ready to communicate.        CLOSING 2   The connection is in the process of closing.        CLOSED  3   The connection is closed or couldn't be opened.        */        msg.innerHTML = websocket.readyState;    };    function song(){        var text = document.getElementById('text').value;        document.getElementById('text').value = '';        //向服务器发送数据        websocket.send(text);    }      //监听连接关闭//    websocket.onclose = function (evt) {//        console.log("Disconnected");//    };    //onmessage 监听服务器数据推送    websocket.onmessage = function (evt) {        msg.innerHTML += evt.data +'<br>';//        console.log('Retrieved data from server: ' + evt.data);    };//监听连接错误信息//    websocket.onerror = function (evt, e) {//        console.log('Error occured: ' + evt.data);//    };</script></html>