swoole是否支持websocket协议

2013-11-21 14:48
0
0

Rango - 一枚职业的码农

赞同来自:

支持。这里

2013-11-21 14:58
0

小red - 比起技术优劣,更关心产品体验

赞同来自:

能不能给个脱离swoole framework的例子啊,我是说直接用swoole扩展实现的单纯的websocket_server.php。一般项目都有原有框架了,再套进swoole框架有点不合适啊,只是借助swoole扩展实现实时高并发websocket通信还是很诱人的。

2013-12-19 14:51
0

韩天峰 - 关注外星人

赞同来自:

你从swoole framework中抽取需要的类即可。

2013-12-20 13:24
0

小red - 比起技术优劣,更关心产品体验

赞同来自:

websocket_server.php中: $server = new \Swoole\Network\SelectTCP('0.0.0.0', 9503); class SelectTCP extends \Swoole\Server \Swoole\Server.php中运用的都是stream_socket_***函数,也就是说swoole frame_work中实现的websocket不是基于swoole扩展来的?

2013-12-21 20:30
0

韩天峰 - 关注外星人

赞同来自:

SelectTCP这是另外的驱动。选择 $server = new \Swoole\Network\Server 这个是用swoole扩展的。

2013-12-27 14:11
0

小red - 比起技术优劣,更关心产品体验

赞同来自:

哎,貌似框架你们也不怎么重视,要看懂代码实在费劲,我自己简单实现了基于swoole扩展的websocket通信。。。 Swoole.php

<?php
namespace modules\websocket;
/*
 * 基于swoole扩展实现的websocket服务端
 * @author red
 *
 */
abstract class Swoole
{
    public $host;   // 监听地址
    public $port;   // 监听端口
    public $config; // swoole配置
    public $server; // swoole server
    public $connections = array();
    /**
     * 初始化swoole参数
     * @param unknown $host
     * @param unknown $port
     */
    function __construct($host,$port){
        $this->config = require_once 'config/swoole.php';
        $this->host = $host;
        $this->port = $port;
    }
    /**
     * 启动服务
     */
    function run() {
        $this->server = new \swoole_server($this->host, $this->port, $this->config['mode'],$this->config['sock_type']);
        $this->server->set($this->config['swoole_setting']);
        swoole_server_handler($this->server, 'onConnect', array($this, 'onConnect'));
        swoole_server_handler($this->server, 'onReceive', array($this, 'onReceive'));
        swoole_server_handler($this->server, 'onClose', array($this, 'onClose'));
        $this->server->start();
    }

    /**
     * 新连接进入时触发
     * @param unknown $serv
     * @param unknown $fd
     * @param unknown $from_id
     */
    function onConnect($serv,$fd,$from_id){}
    /**
     * 收到数据时触发
     * @param unknown $serv
     * @param unknown $fd
     * @param unknown $from_id
     * @param unknown $data
     */
    function onReceive($serv,$fd,$from_id,$data){
        if(!isset($this->connections[$fd])){
            $this->handShake($data, $fd);
            $this->connections[$fd] = time();
        }else {
            $data = $this->unmask($data);
            $this->onMessage($fd,$data);
        }
    }
    /**
     * 关闭一个连接时触发
     * @param unknown $serv
     * @param unknown $fd
     * @param unknown $from_id
     */
    function onClose($serv,$fd,$from_id){
        if(isset($this->connections[$fd])){
            unset($this->connections[$fd]);  // 清空连接
        }
    }
    /**
     * 接收到websocket数据时触发
     * @param unknown $fd
     * @param unknown $data
     */
    abstract function onMessage($fd,$data);
    /**
     * websocket 握手过程
     * @param string $receved 浏览器发过来的头信息
     * @param int $fd 连接的文件描述符
     */
    function handShake($receved,$fd){
        $headers = array();
        $lines = preg_split("/\r\n/", $receved);
        foreach($lines as $line)
        {
            $line = chop($line);
            if(preg_match('/\A(\S+): (.*)\z/', $line, $matches))
            {
                $headers[$matches[1]] = $matches[2];
            }
        }

        $secKey = $headers['Sec-WebSocket-Key'];
        $secAccept = base64_encode(pack('H*', sha1($secKey . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11')));
        //hand shaking header
        $upgrade  = "HTTP/1.1 101 Web Socket Protocol Handshake\r\n" .
                "Upgrade: websocket\r\n" .
                "Connection: Upgrade\r\n" .
                "WebSocket-Origin: {$this->host}\r\n" .
                "WebSocket-Location: ws://{$this->host}:{$this->port}/demo/shout.php\r\n".
                "Sec-WebSocket-Accept:$secAccept\r\n\r\n";
        $this->send($fd, $upgrade,FALSE);
    }
    /**
     * 解包发送的信息
     * @param unknown $text
     * @return Ambigous <string, boolean>
     */
    function unmask($text) {
        $length = ord($text[1]) & 127;
        if($length == 126) {
            $masks = substr($text, 4, 4);
            $data = substr($text, 8);
        }
        elseif($length == 127) {
            $masks = substr($text, 10, 4);
            $data = substr($text, 14);
        }
        else {
            $masks = substr($text, 2, 4);
            $data = substr($text, 6);
        }
        $text = "";
        for ($i = 0; $i < strlen($data); ++$i) {
            $text .= $data[$i] ^ $masks[$i%4];
        }
        return $text;
    }
    /**
     * 封包发送信息
     * @param unknown $text
     * @return string
     */
    function mask($text)
    {
        $b1 = 0x80 | (0x1 & 0x0f);
        $length = strlen($text);

        if($length <= 125)
            $header = pack('CC', $b1, $length);
        elseif($length > 125 && $length < 65536)
        $header = pack('CCn', $b1, 126, $length);
        elseif($length >= 65536)
        $header = pack('CCNN', $b1, 127, $length);
        return $header.$text;
    }
    /**
     * 发送数据
     * @param int $fd   连接的文件描述符
     * @param string $data  发送的数据
     */
    function send($fd,$data,$mask=TRUE){
        if($mask){
            $data = $this->mask($data);
        }
        return swoole_server_send($this->server,$fd,$data);
    }
}

config/swoole.php

<?php
return array(
        'mode' => SWOOLE_PROCESS,
        'sock_type' => SWOOLE_SOCK_TCP,
        'swoole_setting' => array(
                'timeout' => 2.5,  //select and epoll_wait timeout.
                'poll_thread_num' => 1,  //reactor thread num
                'writer_num' => 1,       //writer thread num
                'worker_num' => 1,       //worker process num
                'backlog' => 128,        //listen backlog
                'open_cpu_affinity' => 1,
                'open_tcp_nodelay' => 1,
                'log_file' => '/tmp/swoole.log', 
                'daemonize' => 0, 
            ),
);

server.php

<?php
header("Content-type: text/html; charset=utf-8");
/**
 * 自动加载类
 * @param unknown $className
 */
spl_autoload_register(function($className){
    $className=str_replace('\\', '/', $className);
    require "./{$className}.php";
});
/*
 * swoole websocket服务
 */
class server extends modules\websocket\Swoole{
    /**
     * 监听到消息时执行
     * @see \modules\websocket\Swoole::onMessage()
     */
    function onMessage($clinet_id, $data){
        $received = json_decode($data); //json decode
        $response = array('type'=>'usermsg', 'name'=>$received->name, 'message'=>$received->message, 'color'=>$received->color);
        $this->send($clinet_id, json_encode($response)); //send data
    }

}
$server = new server('0.0.0.0', '4401');
$server->run();

client.php

<?php header("Content-type: text/html; charset=utf-8");?>
<!DOCTYPE html>
<html>
<head>
<meta charset='UTF-8' />
<style type="text/css">
<!--
.chat_wrapper {
    width: 500px;
    margin-right: auto;
    margin-left: auto;
    background: #CCCCCC;
    border: 1px solid #999999;
    padding: 10px;
    font: 12px 'lucida grande',tahoma,verdana,arial,sans-serif;
}
.chat_wrapper .message_box {
    background: #FFFFFF;
    height: 150px;
    overflow: auto;
    padding: 10px;
    border: 1px solid #999999;
}
.chat_wrapper .panel input{
    padding: 2px 2px 2px 5px;
}
.system_msg{color: #BDBDBD;font-style: italic;}
.user_name{font-weight:bold;}
.user_message{color: #88B6E0;}
-->
</style>
</head>
<body>    
<?php 
$colours = array('007AFF','FF7000','FF7000','15E25F','CFC700','CFC700','CF1100','CF00BE','F00');
$user_colour = array_rand($colours);
?>

<script src="//ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>

<script language="javascript" type="text/javascript">  
$(document).ready(function(){
    //create a new WebSocket object.
    var wsUri = "ws://127.0.0.1:4401/";   
    websocket = new WebSocket(wsUri); 

    websocket.onopen = function(ev) { // connection is open 
        $('#message_box').append("<div class=\"system_msg\">Connected!</div>"); //notify user
    }

    $('#send-btn').click(function(){ //use clicks message send button   
        var mymessage = $('#message').val(); //get message text
        var myname = $('#name').val(); //get user name

        if(myname == ""){ //empty name?
            alert("Enter your Name please!");
            return;
        }
        if(mymessage == ""){ //emtpy message?
            alert("Enter Some message Please!");
            return;
        }

        //prepare json data
        var msg = {
        message: mymessage,
        name: myname,
        color : '<?php echo $colours[$user_colour]; ?>'
        };
        //convert and send data to server
        websocket.send(JSON.stringify(msg));
    });

    //#### Message received from server?
    websocket.onmessage = function(ev) {
        var msg = JSON.parse(ev.data); //PHP sends Json data
        var type = msg.type; //message type
        var umsg = msg.message; //message text
        var uname = msg.name; //user name
        var ucolor = msg.color; //color

        if(type == 'usermsg') 
        {
            $('#message_box').append("<div><span class=\"user_name\" style=\"color:#"+ucolor+"\">"+uname+"</span> : <span class=\"user_message\">"+umsg+"</span></div>");
        }
        if(type == 'system')
        {
            $('#message_box').append("<div class=\"system_msg\">"+umsg+"</div>");
        }

        $('#message').val(''); //reset text
    };

    websocket.onerror   = function(ev){$('#message_box').append("<div class=\"system_error\">Error Occurred - "+ev.data+"</div>");}; 
    websocket.onclose   = function(ev){$('#message_box').append("<div class=\"system_msg\">Connection Closed</div>");}; 
});
</script>
<div class="chat_wrapper">
<div class="message_box" id="message_box"></div>
<div class="panel">
<input type="text" name="name" id="name" placeholder="Your Name" maxlength="10" style="width:20%"  />
<input type="text" name="message" id="message" placeholder="Message" maxlength="80" style="width:60%" />
<button id="send-btn">Send</button>
</div>
</div>

</body>
</html>
2013-12-27 17:09
0

小red - 比起技术优劣,更关心产品体验

赞同来自:

这代码展示不给力啊。。。。。看起来好乱。服务端主要就是swoole类,在起服务的文件里实例化它并实现onMessage方法就可以了。上面的client.php就是实现了一个发送、自动回复的聊天功能。

2013-12-27 17:18
0

小red - 比起技术优劣,更关心产品体验

赞同来自:

现在貌似有个问题 就是onMessage收到的中文编码问题。。。。。。。

2013-12-27 16:36:29-------------------------
{"message":"范德萨","name":"大法师","color":"FF7000"}
2013-12-27 16:52:16-------------------------
Array
(
    [message] => 范德萨
    [name] => 大法师
    [color] => FF7000
)

客户端发送过来的是中文,服务端也可以json然后推送给客户端解析出正常的中文,但是在服务端怎么解析出正常的中文还没搞明白。。。。貌似这也不是url编码啊。难道是解包函数unmask()的问题? 求大神指点哈!

2013-12-27 17:24
0

小red - 比起技术优劣,更关心产品体验

赞同来自:

这代码展示真心不给力,还不允许放站外的地址。。。。。。

2013-12-27 22:56

要回复问题请先登录注册