php如何实现websocket
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了php如何实现websocket相关的知识,希望对你有一定的参考价值。
php有可用的websocket库,不需要php-fpm。
目前比较成熟的有swoole(swoole.com),和workman(workman.net)
swoole是c写的php扩展, 效率比nodejs还要高,workman是纯php实现,两者都号称可以实现并发百万TCP连接。
给你个例子:
这个要通过cmd运行的 具体带的参数有点忘记了<?php
error_reporting(E_ALL);
set_time_limit(0);
ob_implicit_flush();
//创建一个socket连接 设置参数 绑定 监听 并且返回
$master = WebSocket("localhost",12345);
//标示是否已经进行过握手了
$is_shaked = false;
//是否已经关闭
$is_closed = true;
//将socket变为一个可用的socket
while(true)
//如果是关闭状态并且是没有握手的话 则创建一个可用的socket(貌似第二个条件可以去除)
if($is_closed && !$is_shaked)
if(($sock = socket_accept($master)) < 0)
echo "socket_accept() failed: reason: " . socket_strerror($sock) . "\\n";
//将关闭状态修改为false
$is_closed = false;
//开始进行数据处理
process($sock);
//处理请求的函数
function process($socket)
//先从获取到全局变量
global $is_closed, $is_shaked;
//从socket中获取数据
$buffer = socket_read($socket,2048);
//如果buffer返回值为false并且已经握手的话 则断开连接
if(!$buffer && $is_shaked)
disconnect($socket);
else
//如果没有握手的话则握手 并且修改握手状态
if($is_shaked == false)
$return_str = dohandshake($buffer);
$is_shaked = true;
else
//如果已经握手的话则送入deal函数中进行相应处理
$data_str = decode($buffer); //解析出来的从前端送来的内容
console($data_str);
$return_str = encode(deal($socket, $data_str));
//$return_str = encode($data_str);
//将应该返回的字符串写入socket返回
socket_write($socket,$return_str,strlen($return_str));
function deal($socket, $msgObj)
$obj = json_decode($msgObj);
foreach($obj as $key=>$value)
if($key == 'close')
disconnect($socket);
console('close success');
return 'close success';
else if($key == 'msg')
console($value."\\n");
return $value;
//获取头部信息
function getheaders($req)
$r=$h=$o=null;
if(preg_match("/GET (.*) HTTP/" ,$req,$match)) $r=$match[1];
if(preg_match("/Host: (.*)\\r\\n/" ,$req,$match)) $h=$match[1];
if(preg_match("/Origin: (.*)\\r\\n/",$req,$match)) $o=$match[1];
if(preg_match("/Sec-WebSocket-Key: (.*)\\r\\n/",$req,$match)) $key=$match[1];
if(preg_match("/\\r\\n(.*?)\\$/",$req,$match)) $data=$match[1];
return array($r,$h,$o,$key,$data);
function WebSocket($address,$port)
$master=socket_create(AF_INET, SOCK_STREAM, SOL_TCP) or die("socket_create() failed");
socket_set_option($master, SOL_SOCKET, SO_REUSEADDR, 1) or die("socket_option() failed");
socket_bind($master, $address, $port) or die("socket_bind() failed");
socket_listen($master,20) or die("socket_listen() failed");
echo "Server Started : ".date('Y-m-d H:i:s')."\\n";
echo "Master socket : ".$master."\\n";
echo "Listening on : ".$address." port ".$port."\\n\\n";
return $master;
function dohandshake($buffer)
list($resource,$host,$origin,$key,$data) = getheaders($buffer);
echo "resource is $resource\\n";
echo "origin is $origin\\n";
echo "host is $host\\n";
echo "key is $key\\n\\n";
$response_key = base64_encode(sha1($key.'258EAFA5-E914-47DA-95CA-C5AB0DC85B11', true));
$return_str = "HTTP/1.1 101 Switching Protocols\\r\\n".
"Upgrade: websocket\\r\\n".
"Connection: Upgrade\\r\\n".
"Sec-WebSocket-Accept: $response_key\\r\\n\\r\\n";
return $return_str;
function console($msg)
$msg = transToGBK($msg);
echo "$msg\\n";
return $msg;
function decode($msg="")
$mask = array();
$data = "";
$msg = unpack("H*",$msg);
$head = substr($msg[1],0,2);
if (hexdec($head1) === 8)
$data = false;
else if (hexdec($head1) === 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));
$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++;
return $data;
function encode($msg="")
$frame = array();
$frame[0] = "81";
$msg .= ' is ok';
$len = strlen($msg);
$frame[1] = $len<16?"0".dechex($len):dechex($len);
$frame[2] = ord_hex($msg);
$data = implode("",$frame);
return pack("H*", $data);
function transToGBK($s)//UTF8->GBK
//echo $s;
return iconv("UTF-8", "GBK", $s);
return $s;
function ord_hex($data)
$msg = "";
$l = strlen($data);
for ($i=0; $i<$l; $i++)
//ord是返回字符串第一个字符的ascii值
//dechex把十进制转换为十六进制
$msg .= dechex(ord($data$i));
return $msg;
function disconnect($socket)
global $is_shaked, $is_closed;
$is_shaked = false;
$is_closed = true;
socket_close($socket);
?> 参考技术A 轮训加长连接,php的sleep函数 参考技术B 查看swoole 参考技术C 你问错了吧,websocket是javascript的吧?
用PHP 和Websocket实现实时通讯---GoEasy
说到websocket大家一定不会陌生,WebSocket是HTML5一种新的协议。它实现了浏览器与服务器全双工通信(full-duplex)。一开始的握手需要借助HTTP请求完成,当浏览器和服务器握手成功后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。有了websocket, 大家就可以摒弃以往用轮询来实现实时通讯的方式了。
有了websocket后,应运而生的相关产品也不在少数,选择也成了最大的问题,在这里你可能会说“干嘛用别人的,我可以自己用原始的开发一个啊”对此我只想说你真NB,我也很想知道你是如何解决以下问题的:
1. 你是打算花1个月,2个月还是1年还实现一个websocket通信的?如果你说你打算花一个月,那说明两点,你的技术要上天了(这么刁的东西你可以那么快弄出来还不存在性能问题,除了我现有的膝盖,请把我下辈子的膝盖也拿走),贵公司土豪(贵公司对技术的炙热追求已经达到了行业的巅峰了,看来你们的项目不是很紧嘛,预算挺多嘛,告诉我贵公司的名字我也来钻研技术,哈哈哈)
2. Websocket只支持ie10+, chrome, firefox, safari, opera. 不说多了,当前IE9及低版本的用户群体还有很多,你是怎么觉得这些低版本浏览器的实时通讯的?
上面两个问题无非就是涉及到两方面问题:开发成本和浏览器兼容性问题。站在管理者角度来看,都希望尽可能多的压缩开发成本,所有选择第三方推送服务是众多企业的一个理性选择。
选择产品时需要注意以下几点:
1. 代码结构是否清晰易懂
2. 消息到达率怎么样,数据到达情况是否可视
3. 浏览器兼容性如何
4. 产品的稳定性和安全性
好,重点来了,我不去评判其他产品的优缺点,只给出我对我最终选择的产品-GoEasy推送作一个单方面的评价。GoEasy推送满足我上面列的所有指标。
1. 代码结构是否清晰易懂
GoEasy的代码分为订阅和推送两部分:
订阅时,只需要三句代码:
a. 引入goeasy.js (文件非常小)
<script type="text/javascript" src="http://cdn.goeasy.io/goeasy.js"></script>
b. 创建goeasy实例
var goEasy = new GoEasy({appkey: ‘appkey‘});
c. 订阅channel.
goEasy.subscribe({
channel: ‘channel1‘,
onMessage: function(message){
alert(‘Meessagereceived:‘+message.content);//接收到推送的消息
}
});
推送时,用goeasy提供的restful api来实现,api只需要三个参数即可:
URL: http://goeasy.io/goeasy/publish
Method: Post
Parameters: appkey, channel, content
2. 消息到达率怎么样,数据到达情况是否可视
我们项目的用户并发量目前最高在300人的样子,每天会推送30条消息的样子,每条消息的到达情况都可以在goeasy后台页面进行查看。至于到达率,我们项目的对到达率的要求是98%,就目前来看GoEasy应该是100%的到达率。
3. 浏览器兼容性如何
除了常用的浏览器chrome, firefox, safari, opera外还支持IE 6到IE11的版本,低版本IE浏览器GoEasy采用的是polling的方式。GoEasy在兼容性这方面做的很不错。
4. 产品的稳定性和安全性
稳定性的判定:项目已经持续运行了4个月了,没有出现过消息推不出或接收不到的情况。
安全性的判定:GoEasy在安全控制方面主要是通过appkey来控制,创建好app后系统会生成两个key,一个既可以用来接收又可以用来推送,另一个只可以用来接收。所以用户可以选择性的暴露你的key.
这样轻松用PHP实现客户端与服务器端的实时通信了。
PHP websocket实时消息推送
以上是关于php如何实现websocket的主要内容,如果未能解决你的问题,请参考以下文章
PHP Websocket实现扫码二维码登录---GoEasy