windows下使用php socket 和 html5 websocket实现服务器和客户端之间通信

13 篇文章 1 订阅
10 篇文章 0 订阅

首先感谢打开这篇文章,但是运行时候有一点点错误,所以我把自己整理后的内容发布上来
下载代码github下载1csdn下载2

之所以选择websocket,而不是使用ajax理由如下:
1、ajax轮询 ,ajax轮询 的原理非常简单,让浏览器隔个几秒就发送一次请求,询问服务器是否有新信息。
2、long poll 其实原理跟 ajax轮询 差不多,都是采用轮询的方式,不过采取的是阻塞模型(一直打电话,没收到就不挂电话),也就是说,客户端发起连接后,如果没消息,就一直不返回Response给客户端。直到有消 息才返回或超时,返回完之后,客户端再次建立连接,周而复始,基于事件的触发,一个事件接一个事件。
Ajax轮询与long poll都属于不断发送http请求,然后等待服务器处理,可以看到http协议一个特点,被动性,服务端不能主动联系客户端,只有客户端发起。
缺点:Ajax轮询需要服务器有很快的处理速度与快速响应。long poll需要很高的并发,体现在同时容纳请求的能力。
3、webSocket是HTML5一种新的协议,实现了浏览器与服务器之间的全双工通信,能很好的节省服务器资源与带宽,并在服务器端与浏览器端实现实时通行,他建立在TCP之上, 同http一样,通过tcp来传输数据。
只需要一次HTTP握手,所以说整个通讯过程是建立在一次连接/状态中,服务器端会知道连接的信息,知道客户端关闭请求,同时由服务器主动推送,当有信息需要发送时,直接发送。客户端的连接通过session对象存储,能够实现实时推送。
所以选择webSocket进行实现。

1、运行脚本
保存为 run.bat

cd D:\Program Files\PHP  
php D:\www\websocket\Server_socket.php 

其中第一行代表PHP文件的安装目录
第二行是接下来介绍的文件存放目录

2、Server_socket.php 服务器端的处理文件
使用php socket


<?php 

/**
* 聊天室服务器  websocket 专用
*/
class Server_socket
{
    private $socket;
    private $accept = [];
    private $hands = [];
    function __construct($host, $port, $max)
    {
        $this->socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
        socket_set_option($this->socket, SOL_SOCKET, SO_REUSEADDR, TRUE);
        socket_bind($this->socket, $host,$port);
        socket_listen($this->socket,$max); 
        print_r($this->socket);
    }

    public function start()
    {
        $i = 0;
        while (true) {

            $cycle = $this->accept;
            $cycle[] = $this->socket;
            socket_select($cycle, $write, $except, null);

            foreach ($cycle as $sock) {
                if ($sock == $this->socket) {
                    $this->accept[] = socket_accept($sock);
                    $arr =  array_keys($this->accept);
                    $key = end($arr);
                    $this->hands[$key] = false;
                }else{
                    $length = socket_recv($sock, $buffer, 204800, null);
                    $key = array_search($sock, $this->accept);
                    if (!$this->hands[$key]) {
                        $this->dohandshake($sock,$buffer,$key);
                    }else if($length < 1){
                        $this->close($sock);
                    }else{
                        //接收从客户端发送的内容 解码
                        $data = $this->decode($buffer);
                        print_r("\nThis is the data received from client,".$data);
                        //服务器端的内容  编码
                        $data = "This is the data sent by server".$i.", so smart";
                        $data = $this->encode($data);
                        print_r($data);
                        //将信息传递给从机
                        foreach ($this->accept as $client) {
                            socket_write($client,$data ,strlen($data));
                        }
                        $i++;  
                    }        
                }
            }
            sleep(1);
        }
    }/* end of start*/

    /**
     * 首次与客户端握手
     */
    public function dohandshake($sock, $data, $key) {
        if (preg_match("/Sec-WebSocket-Key: (.*)\r\n/", $data, $match)) {
            $response = base64_encode(sha1($match[1] . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11', true));
            $upgrade  = "HTTP/1.1 101 Switching Protocol\r\n" .
                    "Upgrade: websocket\r\n" .
                    "Connection: Upgrade\r\n" .
                    "Sec-WebSocket-Accept: " . $response . "\r\n\r\n";
            socket_write($sock, $upgrade, strlen($upgrade));
            $this->hands[$key] = true;
        }
    }/*dohandshake*/

    /**
     * 关闭一个客户端连接
     */
    public function close($sock) {
        $key = array_search($sock, $this->accept);
        socket_close($sock);
        unset($this->accept[$key]);
        unset($this->hands[$key]);
    }

    /**
     * 字符解码
     */
    public function decode($buffer) {
        $len = $masks = $data = $decoded = null;
        $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;
    }

    /**
     * 字符编码
     */
    public function encode($buffer) {
        $length = strlen($buffer);
        if($length <= 125) {
            return "\x81".chr($length).$buffer;
        } else if($length <= 65535) {
            return "\x81".chr(126).pack("n", $length).$buffer;
        } else {
            return "\x81".char(127).pack("xxxxN", $length).$buffer;
        }
    }

}/* end of class Server_socket*/

$server_socket = new Server_socket('127.0.0.1',9000,20);
$server_socket->start(); sleep(2); 
?>

主要的函数是start()函数,当中写了注释内容,可以根据自己的需要进行修改

3、客户端JavaScript websocket


<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>websocket</title>
</head>

<body>
    <div>
        <button id='send'> 发送</button>
    </div>
</body>
<script>
// var socket = new WebSocket('ws://127.0.0.1:9000');
var url = "ws://127.0.0.1:9000";
//兼容 FireFox
if ("WebSocket" in window) {
    socket = new WebSocket(url);
} else if ("MozWebSocket" in window) {
    socket = new MozWebSocket(url);
}
socket.onopen = function(event) {
    console.log("connected");
    socket.send("client say hello\n");
    alert('连接');
};
socket.onmessage = function(event) {//当客户端收到服务端发来的消息时,会触发onmessage事件,参数event.data中包含server传输过来的数据
    var content = event.data;//获取消息
    console.log(content);
    if (content.length > 0) {
        alert("server said"+content);
    }
};
socket.onclose = function(evt)
{
  console.log("WebSocketClosed!");
};
socket.onerror = function(evt)
{
  console.log("WebSocketError!");
};
var send = document.getElementById('send');
send.addEventListener('click', function() {
    var content = 'client sent\n';
    console.log(content);
    socket.send(content);
    alert('发送');
});
</script>
</html>

这里客户端页面加载后就与服务器端进行连接,如果成功之后,就会执行onopen,如果服务器发送内容,执行onmessage,其中event是服务器发送的对象。查看更多

4、运行步骤
1)下载源代码至本地
2)修改run.bat文件存放路径
3)双击运行脚本
4)打开浏览器,我是放在Apache的www文件夹下面的,输入http://127.0.0.1/websocket/wobsocket.html
5)如果报错
这里写图片描述
表示Server_socket.php 没有执行,也可能是火狐浏览器的websocket没有打开。
打开火狐浏览器的websocket方法
1)地址栏输入about:config
2)回车,搜索框输入websocket,将与websocket有关的内容全部打开,重启浏览器。
这里写图片描述
6)执行效果
这里写图片描述
左边的cmd是执行run.bat的脚本
右边的控制台是客户端执行的有关打印
可以看出,客户端发送的信息被服务端接收,并且服务端发送的内容客户端也可以被接收。

之所以要做这个是有关实现团队前端主机创建成员,从机加入后,推送消息给主机,是哪一个成员加入,以及主机点击开始操作之后,主机和从机同时进入操作页面。

另外,还可能后期还会有操作期间的会话,其实这个已经可以简单实现,不过问题是需要区分团队,每一个团队有一个聊天室。以及发送消息区分每一个用户。可能后期会参考打开,以及打开

参考链接:
[连载] Socket 深度探索 4 PHP (一)http://blog.csdn.net/shagoo/article/details/6396089
php中socket的使用 http://www.cnblogs.com/phpzxh/archive/2010/12/09/1901437.html
PHP-Socket服务端客户端发送接收通信实例详解 http://fighter.blog.51cto.com/1318618/1533957/
写了websocket个聊天室,然后终于弄懂了php的socket
http://www.tuicool.com/articles/iEV3Aje
简单又好用的聊天室技术——WebSocket https://segmentfault.com/a/1190000005041671
php socket 和 html5 websocket 通讯 http://blog.csdn.net/little_rabbit_baby/article/details/53184595
聊天室http://www.cnblogs.com/Wayou/p/hichat_built_with_nodejs_socket.html
WebSocket的JavaScript例子http://www.xyhtml5.com/websocket-javascript-example.html
webSocket、Ajax轮询、长轮询(long poll)http://blog.csdn.net/lb7758zx/article/details/51513353

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值