php实现实时聊天时在线视频聊天怎么实现?

websocket 作为 HTML5 里一个新的特性一直很受人关注,因为它真的非常酷,打破了 http “请求-响应”的常规思维,实现了服务器向客户端主动推送消息,本文介绍如何使用 PHP 和 JS 应用 websocket 实现一个网页实时聊天室;
以前写过一篇文章讲述如何使用ajax长轮询实现网页实时聊天,见链接:
,但是轮询和服务器的 pending 都是无谓的消耗,websocket 才是新的趋势。
最近艰难地“挤”出了一点时间,完善了很早之前做的 websocket “请求-原样返回”服务器,用js完善了下客户端功能,把过程和思路分享给大家,顺便也普及一下 websocket 相关的知识,当然现在讨论 websocket 的文章也特别多,有些理论性的东西我也就略过了,给出参考文章供大家选择阅读。
正文开始前,先贴一张聊天室的效果图(请不要在意CSS渣的页面):
然后当然是源码:
WebSocket 不是一门技术,而是一种全新的协议。它应用 TCP 的 Socket(套接字),为网络应用定义了一个新的重要的能力:客户端和服务器端的双全工传输和双向通信。是继 Java applets、 XMLHttpRequest、 Adobe Flash,、ActiveXObject、 各类 Comet 技术之后,服务器推送客户端消息的新趋势。
与http的关系
在网络分层上,websocket 与 http 协议都是应用层的协议,它们都是基于 tcp 传输层的,但是 websocket 在建立连接时,是借用 http 的 101 switch protocol 来达到协议转换(Upgrade)的,从 HTTP 协议切换成 WebSocket 通信协议,这个动作协议中称“握手”;
握手成功后,websocket 就使用自己的协议规定的方式进行通讯,跟 http 就没有关系了。
以下是一个我自己的浏览器发送的典型的握手 http 头:&
服务器收到握手请求后,提取出请求头中的 “Sec-WebSocket-Key” 字段,追回一个固定的字符串 ‘258EAFA5-E914-47DA-95CA-C5AB0DC85B11’, 然后进行 sha1 加密,最后转换为 base64 编码,作为 key 以 “Sec-WebSocket-Accept” 字段返回给客户端,客户端匹配此 key 后,便建立了连接,完成了握手;
websocket 有自己规定的数据传输格式,称为 帧(Frame),下图是一个数据帧的结构,其中单位为bit:
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-------+-+-------------+-------------------------------+
|F|R|R|R| opcode|M| Payload len |
Extended payload length
(if payload len==126/127)
+-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
Extended payload length continued, if payload len == 127
+ - - - - - - - - - - - - - - - +-------------------------------+
|Masking-key, if MASK set to 1
+-------------------------------+-------------------------------+
| Masking-key (continued)
Payload Data
+-------------------------------- - - - - - - - - - - - - - - - +
Payload Data continued ...
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
Payload Data continued ...
+---------------------------------------------------------------+
具体每个字段是什么意思,有兴趣的可以看一下这篇文章
感觉自己对二进制的操作还不是很灵活,也就没有挑战自己写算法解析数据了,下面的数据帧解析和封装都是使用的网上的算法。
不过,我工作中写支付网关中还是会经常用到数据的进制操作的,这个一定是要仔细研究总结一下的,嗯,先记下。
PHP 实现 websocket 服务器
PHP 实现 websocket 的话,主要是应用 PHP 的 socket 函数库:
PHP 的 socket 函数库跟 C 语言的 socket 函数非常类似,以前翻过一遍 APUE, 所以觉得还挺好理解。在 PHP 手册中看一遍 socket 函数,我想大家也能对 php 的 socket 编程有一定的认识。
下面会在代码中对所用函数进行简单的注释。
文件描述符
忽然提及'文件描述符',大家可能会有些奇怪。
但作为服务器,是必须要对已经连接的 socket 进行存储和识别的。每一个 socket 代表一个用户,如何关联和查询用户信息与 socket 的对应就是一个问题了,这里便应用了关于文件描述符的一点小技巧。
我们知道 linux 是'万物皆文件'的,C 语言的 socket 的实现便是一个个的’文件描述符‘ ,这个文件描述符一般是打开文件的顺序递增的 int 数值,从 0 一直递增(当然系统是有限制的)。每一个 socket 都对应一个文件,读写 socket 都是操作对应的文件,所以也能像文件系统一样应用 read 和 write 函数。
tips: linux 中, 标准输入对应的是文件描述符 0;标准输出对应的文件描述符是 1; 标准错误对应的文件描述符是 2;所以我们可以使用 0 1 2对输入输出重定向。
那么类似于 C socket 的 PHP socket 自然也继承了这一点,它创建的 socket 也是类型于 int 值为 4 5 之类的资源类型。 我们可以使用 (int) 或 intval() 函数把 socket 转换为一个唯一的ID,从而可以实现用一个 ’类索引数组‘ 来存储 socket 资源和对应的用户信息;
结果类似:
$connected_sockets = array(
(int)$socket =& array(
'resource' =& $socket,
'name' =& $name,
'ip' =& $ip,
'port' =& $port,
创建服务器socket
下面是一段创建服务器 socket 的代码:
// 创建一个 TCP socket, 此函数的可选值在官方文档中写得十分详细,这里不再提了
$this-&master = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
// 设置IP和端口重用,在重启服务器后能重新使用此端口;
socket_set_option($this-&master, SOL_SOCKET, SO_REUSEADDR, 1);
// 将IP和端口绑定在服务器socket上;
socket_bind($this-&master, $host, $port);
// listen函数使主动连接套接口变为被连接套接口,使得此 socket 能被其他 socket 访问,从而实现服务器功能。后面的参数则是自定义的待处理socket的最大数目,并发高的情况下,这个值可以设置大一点,虽然它也受系统环境的约束。
socket_listen($this-&master, self::LISTEN_SOCKET_NUM);
这样,我们就得到一个服务器 socket,当有客户端连接到此 socket 上时,它将改变状态为可读,那就看接下来服务器的处理逻辑了。
服务器逻辑
这里着重讲一下 socket_select($read, $write, $except, $tv_sec [, $tv_usec]):
select 函数使用传统的 select 模型,可读、写、异常的 socket 会被分别放入 $socket, $write, $except 数组中,然后返回 状态改变的 socket 的数目,如果发生了错误,函数将会返回 false.
需要注意的是最后两个时间参数,它们只有单位不同,可以搭配使用,用来表示 socket_select 阻塞的时长,为0时此函数立即返回,可以用于轮询机制。 为 NULL 时,函数会一直阻塞下去, 这里我们置 $tv_sec 参数为null,让它一直阻塞,直到有可操作的 socket 返回。
下面是服务器的主要逻辑:
$write = $except = NULL;
$sockets = array_column($this-&sockets, 'resource'); // 获取到全部的 socket 资源
$read_num = socket_select($sockets, $write, $except, NULL);
foreach ($sockets as $socket) {
// 如果可读的是服务器 socket, 则处理连接逻辑;
if ($socket == $this-&master) {
socket_accept($this-&master);
// socket_accept() 接受 请求 “正在 listen 的 socket(像我们的服务器 socket )” 的连接, 并一个客户端 socket, 错误时返回
self::connect($client);
// 如果可读的是其他已连接 socket ,则读取其数据,并处理应答逻辑
// 函数 socket_recv() 从 socket 中接受长度为 len 字节的数据,并保存在 $buffer 中。
$bytes = @socket_recv($socket, $buffer, 2048, 0);
if ($bytes & 9) {
// 当客户端忽然中断时,服务器会接收到一个 8 字节长度的消息(由于其数据帧机制,8字节的消息我们认为它是客户端异常中断消息),服务器处理下线逻辑,并将其封装为消息广播出去
$recv_msg = $this-&disconnect($socket);
// 如果此客户端还未握手,执行握手逻辑
if (!$this-&sockets[(int)$socket]['handshake']) {
self::handShake($socket, $buffer);
$recv_msg = self::parse($buffer);
// 广播消息
$this-&broadcast($msg);
这里只是服务器处理消息的基础代码,日志记录和异常处理都略过了,而且还有些数据帧解析和封装的方法,各位也不一定看爱,有兴趣的可以去 github 上支持一下我的源码~~
此外,为了便于服务器与客户端的交互,我自己定义了 json 类型的消息格式,形似:
'type' =& $msg_type, // 有普通消息,上下线消息,服务器消息
'from' =& $msg_resource, // 消息来源
'content' =& $msg_content, // 消息内容
'user_list' =& $uname_list, // 便于同步当前在线人数与姓名
创建客户端
前端我们使用 js 调用 Websocket 方法很简单就能创建一个 websocket 连接,服务器会为帮我们完成连接、握手的操作,js 使用事件机制来处理浏览器与服务器的交互:
// 创建一个 websocket 连接
var ws = new WebSocket("ws://127.0.0.1:8080");
// websocket 创建成功事件
ws.onopen = function () {
// websocket 接收到消息事件
ws.onmessage = function (e) {
var msg = JSON.parse(e.data);
// websocket 错误事件
ws.onerror = function () {
发送消息也很简单,直接调用 ws.send(msg) 方法就行了。
页面部分主要是让用户使用起来方便,这里给消息框 textarea 添加了一个键盘监控事件,当用户按下回车键时直接发送消息;
function confirm(event) {
var key_num = event.keyC
if (13 == key_num) {
还有用户打开客户端时生成一个默认唯一用户名;
然后是一些对数据的解析构造,对客户端页面的更新,这里就不再啰嗦了,感兴趣的可以看源码。
用户名异步处理
这里不得不提一下用户登陆时确定用户名时的一个小问题,我原来是想在客户端创建一个连接后直接发送用户名到服务器,可是控制台里报出了 “websocket 仍在连接中或已关闭” 的错误信息。
Uncaught DOMException: Failed to execute 'send' on 'WebSocket': Still in CONNECTING state.
考虑到连接可能还没处理好,我就实现了 sleep 方法等了一秒再发送用户名,可是错误仍然存在。
后来忽然想到 js 的单线程阻塞机制,才明白使用 sleep 一直阻塞也是没有用的,利用好 js 的事件机制才是正道:于是在服务器端添加逻辑,在握手成功后,向客户端发送握手已成功的消息;客户端先将用户名存入一个全局变量,接收到服务器的握手成功的提醒消息后再发送用户名,于是成功在第一时间更新用户名。
聊天室扩展方向
简易聊天室已经完成,当然还要给它带有希望的美好未来,希望有人去实现:
页面美化(信息添加颜色等)
服务器识别 '@' 字符而只向某一个 socket 写数据实现聊天室的私聊;
多进程(使用 redis 等缓存数据库来实现资源的共享),可参考我以前的一篇文章:
消息记录数据库持久化(log 日志还是不方便分析)
多读些经典书籍还是很有用的,有些东西真的是触类旁通,APUE/UNP 还是要再多翻几遍。此外互联网技术日新月异,挑一些自己喜欢的学习一下,跟大家分享一下也是挺舒服的(虽然程序和博客加一块用了至少10个小时...)。
嗯,持续更新。喜欢的可以点个推荐或关注,有错漏之处,请指正,谢谢。
阅读(...) 评论()推荐这篇日记的豆列
······经检测你所在的网络可能存在爬虫,因资源限制,我们只能拒绝你的请求。
如果你是推酷的用户,可以以继续访问使用。
如有疑问,可将IP信息发送到
请求解封。PHP实现WEB即时视频通讯 - 开源中国社区
当前访客身份:游客 [
当前位置:
想做一个在线视频聊天系统。希望大神给个思路。谢谢。
共有6个答案
<span class="a_vote_num" id="a_vote_num_
PHPWebIM是Swoole官方基于PHP Swoole扩展和Swoole Framework开发的WebSocket网页即时聊天工具.
PHPWebIM支持WebSocket+Comet两种协议,可用于所有种类的浏览器包括IE.
/matyhtf/PHPWebIM
WorkerMan HTTP WebSocket聊天室Demo:
http://www.workerman.net/applications
http://chat.workerman.net/
http://kedou.workerman.net/
<span class="a_vote_num" id="a_vote_num_
有php何须再用nodejs, java之类的语言了,对楼上有人所说的,网络IO处理,只能用c++, java 我只能说呵呵了。
即便是java也不一定能达到这样的测试成绩:
短链接(每次请求完成后关闭链接,下次请求建立新的链接):
& & 脚本:./benchmark -n100000 -h1 -c500 -p.0.1
& & 含义: 压测脚本开500个并发线程模拟500个并发用户,每个线程链接Workerman 10W次,每次链接发送1个请求
& & 结果: 吞吐量:1.9W/S , cpu利用率:32%
长链接(每次请求后不关闭链接,下次请求继续复用这个链接):
& & 脚本:./benchmark -n1 -h100000 -c2000 -p.0.1&
& & 含义: 压测脚本开2000个并发线程模拟2000个并发用户,每个线程链接Workerman 1次,每个链接发送10W请求
& & 结果: 吞吐量:36.7W/S , cpu利用率:69%
内存:每个进程内存稳定在6444K,无内存泄漏
workerman可以满足您的需求
刚好有一个workerman编写的视频实时录制,播放实例
摄像头视频直播
LiveCamera是一款基于HTML5+WebSocket+PHP的视频直播系统,通过网页(HTML5)调用摄像头,通过websocket传输给PHP后端(workerman), 再由后端广播给所有在线播放网页,观看者可以通过这个播放页面实时观看摄像头拍摄的内容。此应用支持部分手机浏览器调用摄像头直播摄像头视频流。
http://www.workerman.net/camera
workerman是一个高性能的PHP socket 服务器框架,workerman基于PHP多进程以及libevent事件轮询库,PHP开发者只要实现一两个接口,便可以开发出自己的网络应用,例如Rpc服务、聊天室服务器、手机游戏服务器等。
workerman的目标是让PHP开发者更容易的开发出基于socket的高性能的应用服务,而不用去了解PHP socket以及PHP多进程细节。 workerman本身是一个PHP多进程服务器框架,具有PHP进程管理以及socket通信的模块,所以不依赖php-fpm、nginx或者apache等这些容器便可以独立运行。
--- 共有 1 条评论 ---
高手真高:bowtie:
(12个月前)&nbsp&
<span class="a_vote_num" id="a_vote_num_
送你三字符UDP
<span class="a_vote_num" id="a_vote_num_
网络编程方面(socket)要么直接用C/C++做,要么用java,我个人是javaer,java字节处理方面比PHP强大多了
<span class="a_vote_num" id="a_vote_num_
PHP是地球上最伟大的语言没有之一
PHP需要做这种低级的活?&
PHP是地球上最伟大的语言, 没有之一.
--- 共有 1 条评论 ---
(12个月前)&nbsp&
更多开发者职位上
有什么技术问题吗?
web实习...的其它问题
类似的话题新手园地& & & 硬件问题Linux系统管理Linux网络问题Linux环境编程Linux桌面系统国产LinuxBSD& & & BSD文档中心AIX& & & 新手入门& & & AIX文档中心& & & 资源下载& & & Power高级应用& & & IBM存储AS400Solaris& & & Solaris文档中心HP-UX& & & HP文档中心SCO UNIX& & & SCO文档中心互操作专区IRIXTru64 UNIXMac OS X门户网站运维集群和高可用服务器应用监控和防护虚拟化技术架构设计行业应用和管理服务器及硬件技术& & & 服务器资源下载云计算& & & 云计算文档中心& & & 云计算业界& & & 云计算资源下载存储备份& & & 存储文档中心& & & 存储业界& & & 存储资源下载& & & Symantec技术交流区安全技术网络技术& & & 网络技术文档中心C/C++& & & GUI编程& & & Functional编程内核源码& & & 内核问题移动开发& & & 移动开发技术资料ShellPerlJava& & & Java文档中心PHP& & & php文档中心Python& & & Python文档中心RubyCPU与编译器嵌入式开发驱动开发Web开发VoIP开发技术MySQL& & & MySQL文档中心SybaseOraclePostgreSQLDB2Informix数据仓库与数据挖掘NoSQL技术IT业界新闻与评论IT职业生涯& & & 猎头招聘IT图书与评论& & & CU技术图书大系& & & Linux书友会二手交易下载共享Linux文档专区IT培训与认证& & & 培训交流& & & 认证培训清茶斋投资理财运动地带快乐数码摄影& & & 摄影器材& & & 摄影比赛专区IT爱车族旅游天下站务交流版主会议室博客SNS站务交流区CU活动专区& & & Power活动专区& & & 拍卖交流区频道交流区
稍有积蓄, 积分 303, 距离下一级还需 197 积分
论坛徽章:0
就是在网页里实现聊天,包括可以视频可以语聊,可以打字
我应该怎么做?
&&nbsp|&&nbsp&&nbsp|&&nbsp&&nbsp|&&nbsp&&nbsp|&&nbsp
论坛徽章:1
[应用]php可不可以实现视频聊天?
完全可以,但是你还需要实现客户端,视频和语聊,需要客户端和服务器配合。
客户端就是ActiveX,这个可能需要采用微软的一些手段了。
家境小康, 积分 1842, 距离下一级还需 158 积分
论坛徽章:0
[应用]php可不可以实现视频聊天?
这跟PHP没关系
家境小康, 积分 1042, 距离下一级还需 958 积分
论坛徽章:0
[应用]php可不可以实现视频聊天?
一语道破天机
稍有积蓄, 积分 303, 距离下一级还需 197 积分
论坛徽章:0
[应用]php可不可以实现视频聊天?
HonestQiao& && &
版主 - 法师
能不能具体点,我可是很着急但不知道从那里下手呀
论坛徽章:1
[应用]php可不可以实现视频聊天?
这个可能你要去学习VC或者VS.NET里面的一些东西了。
打个电话问微软好了。
白手起家, 积分 25, 距离下一级还需 175 积分
论坛徽章:0
[应用]php可不可以实现视频聊天?
原帖由 &HonestQiao& 发表:
这个可能你要去学习VC或者VS.NET里面的一些东西了。
打个电话问微软好了。
记着和微软的MM多聊会,赚到手,
稍有积蓄, 积分 303, 距离下一级还需 197 积分
论坛徽章:0
[应用]php可不可以实现视频聊天?
我会说英语
也不知道MM的电话
论坛徽章:1
[应用]php可不可以实现视频聊天?
/gp/cntactms/zh-cn
微软(中国)有限公司
北京市朝阳区霄云路38号盛世大厦19层
邮政编码:100027
上海分公司
上海天钥桥路30号美罗大厦19楼
邮政编码:200030
广州办事处
广州天河北路233号中信广场办公大楼66层03-05
邮政编码:510613
微软联系电话&;&;&;&;&;
Contact Us Customer Service& & & &
我们十分重视您的意见和问题。
&#8226;& & & & 欢迎您对本网站提出意见和问题
&#8226;& & & & 网上提交 您对售前非技术服务,市场活动咨询,及产品注册的问题与反馈
&#8226;& & & & 微软中国有限公司客户服务及反馈中心提供售前非技术服务,市场活动咨询,及产品注册与反馈
&#8226;& & & & 查看 更多客户服务资源
Contact Us Product Support& & & &
产品帮助和支持
产品支持选项和联系信息。
&#8226;& & & & 查看产品支持中心&&查找产品问题的答案。
&#8226;& & & & 参与 微软中文新闻组(微软技术论坛) 和其他用户讨论技术问题 .
&#8226;& & & & 请与您的计算机制造商联系以获取支持 如果您的产品是计算机上预先安装在您的电脑中的
&#8226;& & & & 通过电话或电子邮件与专业支持人员联系 如果您是单独或批量购买的微软产品或拥有支持合同
&#8226;& & & & 付费基础技术支持服务面向在独立单机或小型的网络环境下,使用微软桌面产品及消费类产品的个人、家庭用户、SOHO族(小型办公室、在家办公者)等用户,提供以事件计数的服务,用来诊断有明显症状的,可能由微软产品导致的技术问题。服务范围主要包括对您所购买并已注册的产品的安装、使用、配置等方面的问题诊断与故障排除。
&#8226;& & & & 付费专业技术支持服务面向小型技术团体,包括分销商、顾问、OEMs/SBs、小型开发公司、IT专业人士、微软认证合作伙伴等用户,提供以事件计数的服务,用来诊断有明显症状的,可能由微软产品导致的技术问题。服务范围除了基础故障排除,还包括开发支持,服务器支持,网络支持等,为用户提供涵盖几乎所有微软产品的专业解决方案,帮助用户解决问题、优化业绩。
&#8226;& & & & 免费的安全性技术支持 信息系统安全或病毒问题的免费技术支持。
Contact Public Relations& & & &
企业及合作伙伴支持
察看微软公司对企业以及合作伙伴的支持选项。
&#8226;& & & & 微软合作伙伴技术支持 微软对合作伙伴提供的免费支持选项
&#8226;& & & & 微软企业技术支持服务(Premier Support) 微软企业技术支持服务是面向大、中型企业用户以及微软合作伙伴推出的一站式企业级、高级技术支持服务。
&#8226;& & & & 微软顾问咨询服务(MCS)MCS咨询顾问是一批拥有丰富工作经验、通晓微软技术、产品、方法论和各种工具的系统构架师。他们的任务是协助企业设计、开发、部署、使用构建在微软平台之上的各种IT系统,包括多层结构系统、基于XML Web Services的应用系统等。
Contact Us Sales and Licensing& & & &
销售和许可证
获取有关购买 Microsoft 产品的详细信息。
&#8226;& & & & 访问产品信息中心 获得售前信息
&#8226;& & & & 阅读 微软许可证计划
&#8226;& & & & 察看 购买指南
&#8226;& & & & 查找 Microsoft 全球办事处
Corporate Communication& & & &
关于微软公司的最新信息和新闻。
&#8226;& & & & 最新微软新闻
&#8226;& & & & 活动和培训信息
家境小康, 积分 1733, 距离下一级还需 267 积分
论坛徽章:0
[应用]php可不可以实现视频聊天?
哈哈,对了,有没有在ff中能用的视频聊天?

我要回帖

更多关于 php实现在线即时聊天 的文章

 

随机推荐