课程咨询 :13623629309

太原PHP培训 > 达内新闻 > php+websocket搭建简易聊天室实践
  • php+websocket搭建简易聊天室实践

    发布:博客园-原创精华区      来源:博客园-原创精华区      时间:2016-10-24

  • php+websocket搭建简易聊天室实践

    php的运用有很多,可以做很多的工作。太原php培训机构带你一起来搭建聊天室。

    1、前言

    公司游戏里面有个简单的聊天室,了解了之后才知道是node+websocket做的,想想php也来做个简单的聊天室。于是搜集各种资料看文档、找实例自己也写了个简单的聊天室。

    http连接分为短连接和长连接。短连接一般可以用ajax实现,长连接就是websocket。短连接实现起来比较简单,但是太过于消耗资源。websocket高效不过兼容存在点问题。websockethtml5的资源

    如果想要详细了解websocket长连接的原理请看https://www.zhihu.com/question/20215561

    本文主要介绍websocket简易聊天室的实现步骤具体部分知识点的深入会给出链接或者麻烦读者自己搜集资料。

    2、前端

    前端实现websocket很简单直接

    //连接websocket

    var ws = new WebSocket("ws://127.0.0.1:8000");

    //成功连接websoc的时候

    ws.onopen = function(){}

    //成功获取服务端输出的消息

    ws.onmessage = function(e){}

    //连接错误的时候

    ws.onerror = function(){}

    // 向服务端发送数据

    ws.send();

    3、后台

    websocket的难点主要在后台

    3.1websocket连接过程

    websocket 通信图解 这是一个简易的客户端和服务端的通信图解,php主要就做的就是接受加密key 并返回 其中完成套接字的创建和握手操作

    3.2 代码实践

    服务端做的流程大致是:

    、挂起一个socket套接字进程等待连接

    、有socket连接之后遍历套接字数组

    、没有握手的进行握手操作,如果已经握手则接收数据解析并写入缓冲区进行输出

    下面是示例代码(我写的是一个类所以代码是根据函数分段的),文底给出github地址以及自己遇到的一些坑

    1、首先是创建套接字

    //建立套接字

    public function createSocket($address,$port)

    {

    //创建一个套接字

    $socket= socket_create(AF_INET, SOCK_STREAM, SOL_TCP);

    //设置套接字选项

    socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, 1);

    //绑定IP地址和端口

    socket_bind($socket,$address,$port);

    //监听套接字

    socket_listen($socket);

    return $socket;

    }

    2、将套接字放入数组

    public function __construct($address,$port)

    {

    //建立套接字

    $this->soc=$this->createSocket($address,$port);

    $this->socs=array($this->soc);

    }

    3、挂起进程遍历套接字数组,主要操作都是在这里面完成的

    public function run(){

    //挂起进程

    while(true){

    $arr=$this->socs;

    $write=$except=NULL;

    //接收套接字数字 监听他们的状态

    socket_select($arr,$write,$except, NULL);

    //遍历套接字数组

    foreach($arr as $k=>$v){

    //如果是新建立的套接字返回一个有效的 套接字资源

    if($this->soc == $v){

    $client=socket_accept($this->soc);

    if($client <0){

    echo "socket_accept() failed";

    }else{

    // array_push($this->socs,$client);

    // unset($this[]);

    //将有效的套接字资源放到套接字数组

    $this->socs[]=$client;

    }

    }else{

    //从已连接的socket接收数据 返回的是从socket中接收的字节数

    $byte=socket_recv($v, $buff,20480, 0);

    //如果接收的字节是0

    if($byte<7)

    continue;

    //判断有没有握手没有握手则进行握手,如果握手了 则进行处理

    if(!$this->hand[(int)$client]){

    //进行握手操作

    $this->hands($client,$buff,$v);

    }else{

    //处理数据操作

    $mess=$this->decodeData($buff);

    //发送数据

    $this->send($mess,$v);

    }

    }

    }

    }

    }

    4、进行握手 流程是接收websocket内容从Sec-WebSocket-Key:中获取key并通过加密算法写入缓冲区客户端会进行验证(自动验证不需要我们处理)

    public function hands($client,$buff,$v)

    {

    //提取websocket传的key并进行加密 (这是固定的握手机制获取Sec-WebSocket-Key:里面的key)

    $buf = substr($buff,strpos($buff,'Sec-WebSocket-Key:')+18);

    //去除换行空格字符

    $key = trim(substr($buf,0,strpos($buf,"\r\n")));

    //固定的加密算法

    $new_key = base64_encode(sha1($key."258EAFA5-E914-47DA-95CA-C5AB0DC85B11",true));

    $new_message = "HTTP/1.1 101 Switching Protocols\r\n";

    $new_message .= "Upgrade: websocket\r\n";

    $new_message .= "Sec-WebSocket-Version: 13\r\n";

    $new_message .= "Connection: Upgrade\r\n";

    $new_message .= "Sec-WebSocket-Accept: " . $new_key . "\r\n\r\n";

    //将套接字写入缓冲区

    socket_write($v,$new_message,strlen($new_message));

    // socket_write(socket,$upgrade.chr(0), strlen($upgrade.chr(0)));

    //标记此套接字握手成功

    $this->hand[(int)$client]=true;

    }

    5、解析客户端的数据(我这里没有进行加密,如果有需要也可以自己加密 )

    //解析数据

    public function decodeData($buff)

    {

    //$buff 解析数据帧

    $mask = array();

    $data = '';

    $msg = unpack('H*',$buff); //unpack函数从二进制将数据解码

    $head = substr($msg[1],0,2);

    if (hexdec($head{1}) === 8) {

    $data = false;

    }else if (hexdec($head{1}) === 1){

    $mask[] = hexdec(substr($msg[1],4,2));

    $mask[] = hexdec(substr($msg[1],6,2));

    $mask[] = hexdec(substr($msg[1],8,2));

    $mask[] = hexdec(substr($msg[1],10,2));

    //遇到的问题 刚连接的时候就发送数据 显示 state connecting

    $s = 12;

    $e = strlen($msg[1])-2;

    $n = 0;

    for ($i=$s; $i<= $e; $i+= 2) {

    $data .= chr($mask[$n%4]^hexdec(substr($msg[1],$i,2)));

    $n++;

    }

    //发送数据到客户端

    //如果长度大于125 将数据分块

    $block=str_split($data,125);

    $mess=array(

    'mess'=>$block[0],

    );

    return $mess;

    }

    6、将套接字写入缓冲区

    //发送数据

    public function send($mess,$v)

    {

    //遍历套接字数组 成功握手的 进行数据群发

    foreach ($this->socs as $keys => $values) {

    //用系统分配的套接字资源id作为用户昵称

    $mess['name']="Tourist's socket:{$v}";

    $str=json_encode($mess);

    $writes ="\x81".chr(strlen($str)).$str;

    // ob_flush();

    // flush();

    // sleep(3);

    if($this->hand[(int)$values])

    socket_write($values,$writes,strlen($writes));

    }

    }

    7、运行方法

    github地址git@github.com:rsaLive/websocket.git

    最好在控制台运行server.php

    转到server.php脚本目录(可以先php -v 看下有没有配置php如果没有Linux配置下bash windows 配置下path)

    php -f server.php

    如果有错误会提示

    通过服务器访问html文件

    8、踩过的坑,打开调试工作方便查看错误

    ① server.php 挂起的进程中可以打印输出的,如果出现问题可以在代码中加入打印来调试

    可以在各个判断里面做标记在控制台查看代码运行在哪个区间

    不过每次修改完代码之后需要重新运行脚本 php server.php

    如果出现这种错误可能是

    1、在与服务器初始套接字的时候发送数据 (在第一次与服务器验证握手的时候不能发送内容)

    2、如果已经验证过了但是客户端没有发送或者发送的消息为空也会出现这样的情况

    所以要检验已连接的套接字的数据

    可能浏览器不支持或者服务端没有开启socket开始之前最好验证下

    if (window.WebSocket){

    console.log("This browser supports WebSocket!");

    } else {

    console.log("This browser does not support WebSocket.");

    }

    好了,今天就给大家讲这么多吧,喜欢我的内容可以关注或者分享(微信公众平台:tytedu)选择太原达内培训,不再孤军奋战,轻轻松松做IT高薪白领。太原达内培训带领有明确目标的学子迈向成功之路!

上一篇:CodeIgniter 3.1.1 发布,PHP 的 MVC 框架

下一篇:中国行业云安全PCSF论坛推动私有云等级保护升级

最新开班日期  |  更多

php高级开发名企定制班(剩2个名额)

php高级开发名企定制班(剩2个名额)

开班日期:12-30

php高级开发周末班(剩5个名额)

php高级开发周末班(剩5个名额)

开班日期:12-30

php高级开发免费试听(剩5个名额)

php高级开发免费试听(剩5个名额)

开班日期:12-30

更多高级开发工程师精品班

更多高级开发工程师精品班

开班日期:12-30

  • 地址:山西省太原市小店区学府街长治路高新国际A座24层
  • 课程培训电话:13623629309     全国服务监督电话:400-827-0010
  • 服务邮箱 ts@tedu.cn
  • 2001-2016 达内国际公司(TARENA INTERNATIONAL,INC.) 版权所有 京ICP证08000853号-56

    在线客服系统