php+websocket搭建简易聊天室实践
1、前言
公司游戏里面有个简单的聊天室,了解了之后才知道是node+websocket做的,想想php也来做个简单的聊天室。于是搜集各种资料看文档、找实例自己也写了个简单的聊天室。
http连接分为短连接和长连接。短连接一般可以用ajax实现,长连接就是websocket。短连接实现起来比较简单,但是太过于消耗资源。websocket高效不过兼容存在点问题。websocket是html5的资源
如果想要详细了解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 并返回 其中完成套接字的创建和握手操作

下图是一张详细的服务端处理websocket的流程图

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.");
}
如有不正欢迎指出
php+websocket搭建简易聊天室实践的更多相关文章
- 使用Html5下WebSocket搭建简易聊天室
一.Html5WebSocket介绍 WebSocket protocol 是HTML5一种新的协议(protocol).它是实现了浏览器与服务器全双工通信(full-duplex). 现在,很多网站 ...
- 基于Node.js + WebSocket 的简易聊天室
代码地址如下:http://www.demodashi.com/demo/13282.html Node.js聊天室运行说明 Node.js的本质就是运行在服务端的JavaScript.Node.js ...
- node.js+websocket实现简易聊天室
(文章是从我的个人主页上粘贴过来的,大家也可以访问我的主页 www.iwangzheng.com) websocket提供了一种全双工客户端服务器的异步通信方法,这种通信方法使用ws或者wss协议,可 ...
- node+websocket创建简易聊天室
关于websocket的介绍太多,在这就不一一介绍了,本文主要实现通过websocket创建一个简易聊天室,就是90年代那种聊天室 服务端 1.安装ws模块,uuid模块,ws是websocket模块 ...
- Python开发【笔记】:aiohttp搭建简易聊天室
简易聊天室: 1.入口main.py import logging import jinja2 import aiohttp_jinja2 from aiohttp import web from a ...
- 学习JavaSE TCP/IP协议与搭建简易聊天室
一.TCP/IP协议 1.TCP/IP协议包括TCP.IP和UDP等 2.域名通过dns服务器转换为IP地址 3.局域网可以通过IP或者主机地址寻找到相应的主机 4.TCP是可靠的连接,效率低,且连接 ...
- nodejs+mongoose+websocket搭建xxx聊天室
简介 本文是由nodejs+mongoose+websocket打造的一个即时聊天系统:本来打算开发一个类似于网页QQ类似功能的聊天系统,但是目前只是开发了一个模块功能 --- 类似群聊的,即一对多的 ...
- websocket搭建的聊天室
在前后端数据交互的时候我们经常使用的是ajax,用的是传统的http协议,而http协议有个致命的缺点,就是请求一结束,连接就断开了, 我们为了保持这个链接的,通常会使用cookie,而自从h5出现w ...
- WebSocket实现简易聊天室
前台页面: <html> <head> <meta http-equiv="Content-Type" content="text/html ...
随机推荐
- 探究@property申明对象属性时copy与strong的区别
一.问题来源 一直没有搞清楚NSString.NSArray.NSDictionary--属性描述关键字copy和strong的区别,看别人的项目中属性定义有的用copy,有的用strong.自己在开 ...
- 再谈C#采集,一个绕过高强度安全验证的采集方案?方案很Low,慎入
说起采集,其实我是个外行,以前拔过阿里巴巴的客户数据,在我博客的文章:C#+HtmlAgilityPack+XPath带你采集数据(以采集天气数据为例子) 中,介绍过采集用的工具,其实很Low的,分析 ...
- 免费高效实用的.NET操作Excel组件NPOI(.NET组件介绍之六)
很多的软件项目几乎都包含着对文档的操作,前面已经介绍过两款操作文档的组件,现在介绍一款文档操作的组件NPOI. NPOI可以生成没有安装在您的服务器上的Microsoft Office套件的Excel ...
- sql的那些事(一)
一.概述 书写sql是我们程序猿在开发中必不可少的技能,优秀的sql语句,执行起来吊炸天,性能杠杠的.差劲的sql,不仅使查询效率降低,维护起来也十分不便.一切都是为了性能,一切都是为了业务,你觉得你 ...
- c# Enumerable中Aggregate和Join的使用
参考页面: http://www.yuanjiaocheng.net/ASPNET-CORE/asp.net-core-environment.html http://www.yuanjiaochen ...
- 初识npm
一.npm简介: npm全称为Node Package Manager,是一个基于Node.js的包管理器,也是整个Node.js社区最流行.支持的第三方模块最多的包管理器. npm的初衷:JavaS ...
- 你从未知道如此强大的ASP.NET MVC DefaultModelBinder
看到很多ASP.NET MVC项目还在从request.querystring或者formContext里面获取数据,这实在是非常落后的做法.也有的项目建了大量的自定义的modelbinder,以为很 ...
- Hadoop学习笔记系列文章导航
一.为何要学习Hadoop? 这是一个信息爆炸的时代.经过数十年的积累,很多企业都聚集了大量的数据.这些数据也是企业的核心财富之一,怎样从累积的数据里寻找价值,变废为宝炼数成金成为当务之急.但数据增长 ...
- 使用 GCC 和 GNU Binutils 编写能在 x86 实模式运行的 16 位代码
不可否认,这次的标题有点长.之所以把标题写得这么详细,主要是为了搜索引擎能够准确地把确实需要了解 GCC 生成 16 位实模式代码方法的朋友带到我的博客.先说一下背景,编写能在 x86 实模式下运行的 ...
- 使用T4模板生成不同部署环境下的配置文件
在开发企业级应用的时候,通常会有不同的开发环境,比如有开发环境,测试环境,正式环境,生产环境等.在一份代码部署到不同环境的时候,不同环境的配置文件可能需要根据目标环境不同而不同.比如在开发环境中,数据 ...