socket 以及 swoole

socket聊天室:

<?php
/**
 * Created by PhpStorm.
 * User: Administrator
 * Date: 2019/5/7
 * Time: 10:26
 */

class Wss
{
    public $socket = null;
    public $sockets = [];//连接池~
    public $write = null;
    public $except = null;
    public $user = [];

    public function __construct($ip, $port)
    {
        /**创建一个套接字
         *AF_INET:IPv4 网络协议,
         *SOCK_STREAM:提供一个顺序化的、可靠的、全双工的、基于连接的字节流。支持数据传送流量控制机制。TCP 协议即基于这种流式套接字
         * 如果所需的协议是 TCP 或 UDP,可以直接使用常量 SOL_TCP 和 SOL_UDP 。
         */
        $this->socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
        /**
         * 设置套接字的套接字选项
         * 要在套接字级别检索选项level,SOL_SOCKET将使用参数 。可以通过指定该级别的协议编号来使用其他级别,例如TCP
         * SO_REUSEADDR
         * 允许一个程序在多个实例对同一个端口进行绑定。
         * 如果你定义个SO_REUSEADDR,只定义一个套接字在一个端口上进行监听,如果服务器出现意外而导致没有将这个端口释放,那么服务器重新启动后,你还可以用这个端口,因为你已经规定可以重用了,如果你没定义的话,你就会得到提示,ADDR已在使用中。用在多播的时候,也经常使用SO_REUSEADDR,也是为了防止机器出现意外,导致端口没有释放,而使重启后的绑定失败~
         */
        socket_set_option($this->socket, SOL_SOCKET, SO_REUSEADDR, true);
        /**
         * 给套接字绑定名字
         */
        socket_bind($this->socket, $ip, $port);
        /**
         * 侦听套接字上的连接
         */
        socket_listen($this->socket);
        $this->sockets[] = $this->socket;
        while (true) {
            $tmp_sockets = $this->sockets;
            /**
             * 在指定的超时套接字数组上运行select()系统调用
             *write将监视数组中 列出的套接字以查看写入是否不会阻塞。
             * except将监视阵列中 列出的套接字是否有异常。
             */
            socket_select($tmp_sockets, $this->write, $this->except, null);
            foreach ($tmp_sockets as $sock) {
                if ($sock == $this->socket) {
                    /**
                     * 接受套接字上的连接
                     */
                    $conSock = socket_accept($sock);
                    var_dump("conSock:" . $conSock);
                    $this->sockets = $conSock;
                    $this->user[] = ['socket' => $conSock, 'handshake' => false];
                } else {
                    /**
                     *  从套接字读取最大长度字节
                     */
                    $request = socket_read($sock, 1024);
                    $k = $this->getUserIndex($sock);
                    if (strlen($request) == 8) {
                        $this->close($k);
                        continue;
                    }
                    if (!$this->user[$k]['handshake']) {
                        $response = $this->handleShake($request);
                        var_dump("response:" . $response);
                        socket_write($sock, $response, strlen($response));
                        $this->user[$k]['handshake'] = true;
                    } else {
                        $msg = $this->decode($request);
                        $this->send($msg,$k);
                    }
                }
            }
        }
    }
    private function send($msg,$k){
        $arr=explode('===',$msg);
        if ($arr[0]==='login'){
            $this->user[$k]['name']=$arr[1];
            $res['msg']=$arr[1].':login success';
            $res['type']='login';
            $names['name']=$this->getUserName();
            $names=$this->encode(json_encode($names));
            foreach ($this->user as $v){
                socket_write($v['socket'],$names,strlen($names));
            }
        }
        if ($arr[0]=='con'){
            $res['content']=$arr[1];
            $res['name']=$this->user[$k]['name'];
            $res['time']=date('Y-m-d H:i:s',time());
            $res['type']='con';
        }
        $res=$this->encode(json_encode($res));
        foreach ($this->user as $v){
            socket_write($v['socket'],$res,strlen($res));
        }
    }
    private function encode($msg)
    {

        $frame = [];
        $frame[0] = '81';
        $len = strlen($msg);
        if ($len < 126) {
            $frame[1] = $len < 16 ? '0' . dechex($len) : dechex($len);
        } else if ($len < 65025) {
            $s = dechex($len);
            $frame[1] = '7e' . str_repeat('0', 4 - strlen($s)) . $s;
        } else {
            $s = dechex($len);
            $frame[1] = '7f' . str_repeat('0', 16 - strlen($s)) . $s;
        }
        $data = '';
        $l = strlen($msg);
        for ($i = 0; $i < $l; $i++) {
            $data .= dechex(ord($msg{$i}));
        }
        $frame[2] = $data;
        $data = implode('', $frame);
        return pack("H*", $data);
    }


    private function getUserName(){
        foreach ($this->user as $v){
            $name[]=$v['name'];
        }
        return $name;
    }
    private function decode($buffer)
    {
        $decoded = '';
        $len = ord($buffer[1]) & 127;
        if ($len === 126) {
            $masks = substr($buffer, 4, 4);
            $data = substr($buffer, 8);
        } else if ($len === 127) {
            $masks = substr($buffer, 10, 4);
            $data = substr($buffer, 14);
        } else {
            $masks = substr($buffer, 2, 4);
            $data = substr($buffer, 6);
        }
        for ($index = 0; $index < strlen($data); $index++) {
            $decoded .= $data[$index] ^ $masks[$index % 4];
        }
        return $decoded;
    }

    private function close($k)
    {
        socket_close($this->user[$k]['socket']);
        unset($this->user[$k]);
        $this->sockets = null;
        $this->sockets[] = $this->socket;
        foreach ($this->user as $k => $v) {
            $this->sockets[] = $v['socket'];
        }
    }

    private function getUserIndex($sock)
    {
        foreach ($this->user as $k => $v) {
            if ($v['socket'] == $sock) {
                return $v;
            }
        }
    }
    private function handleShake($request)
    {
        preg_match("/Sec-WebSocket-Key: (.*)\r\n/", $request, $match);
        $key = $match[1];
        $new_key = base64_encode(sha1($key . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11', true));

        $response = "HTTP/1.1 101 Switching Protocols\r\n";
        $response .= "Upgrade: websocket\r\n";
        $response .= "Connection: Upgrade\r\n";
        $response .= "Sec-WebSocket-Accept: $new_key\r\n";
        $response .= "Sec-WebSocket-Protocol: chat\r\n\r\n";
        return $response;
    }

    private function decode($buffer)
    {
        $decoded = '';
        $len = ord($buffer[1]) & 127;
        if ($len === 126) {
            $masks = substr($buffer, 4, 4);
            $data = substr($buffer, 8);
        } else if ($len === 127) {
            $masks = substr($buffer, 10, 4);
            $data = substr($buffer, 14);
        } else {
            $masks = substr($buffer, 2, 4);
            $data = substr($buffer, 6);
        }
        for ($index = 0; $index < strlen($data); $index++) {
            $decoded .= $data[$index] ^ $masks[$index % 4];
        }
        return $decoded;
    }


}
new Wss(0, 9501);

客户端:

<!doctype html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no"/>
    <style type="text/css">
        body,p{margin:0px; padding:0px; font-size:14px; color:#333; font-family:Arial, Helvetica, sans-serif;}
        #box,.but-box{width:50%; margin:5px auto;border-radius:5px}
        #box{border:1px #ccc solid;height:400px;width:700px;margin-top:50px;overflow-y:auto; overflow-x:hidden; position:relative;}
        #user-box{margin-right:111px; height:100%;overflow-y:auto;overflow-x: hidden;}
        #msg-box{width:110px; overflow-y:auto; overflow-x:hidden; float:right; border-left:1px #ccc solid; height:100%; background-color:#F1F1F1;}
        button{float:right; width:80px; height:35px; font-size:18px;}
        input{width:100%; height:30px; padding:2px; line-height:20px; outline:none; border:solid 1px #CCC;}
        .but-box p{margin-right:160px;}

    </style>
    <script src="https://cdn.bootcss.com/jquery/2.2.1/jquery.min.js"></script>
</head>

<body>
<h3 style="margin-left:600px">这是个web聊天室 </h3>
<div id="box">
    <div id="msg-box"></div>
    <div id="user-box"></div>
</div>
<div class="but-box">
    <button id="send">发送</button>
    <p><textarea cols="60"  style="resize:none"    id="content"> </textarea></p>
</div>
</body>
</html>


<script>

    var name = prompt('请输入用户名:');
    socket = new WebSocket('ws://119.23.72.178:9501','char');
    console.log(socket)
    socket.onopen = function(){

        console.log('connected success');
        socket.send('login==='+name);
    }

    socket.onmessage  = function(e){
        data = JSON.parse(e.data);
        console.log(data);
        if(data.type=='login'){
            $('#user-box').append('<li style="color:gray">'+data.msg+'</li>');
        }

        if(data.type=='user'){
            $('#msg-box').html('');
            for(i=0;i<data.name.length;i++){
                $('#msg-box').append('<li style="color:gray">'+data.name[i]+'</li>');
            }
        }

        if(data.type=='con'){
            $('#user-box').append('<li><span style="color:blue">'+data.time+'</span><span style="color:red">'+data.name+'</span><span style="color:blue">'+data.content+'</span></li>');

        }
    }

    document.onkeydown = function(e){
        if(e.keyCode==13){
            send();
        }

    }


    $('#send').click(function(){
        send();

    })

    function send(){
        content = $('#content').val();
        $('#content').val('');
        if(content==''){
            return false;
        }
        socket.send('con==='+content);
    }


</script>




 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值