websocket的php测试demo
<?php
class WS {
var $master;
var $sockets = array();
var $debug = false;
var $handshake = false; function __construct($address, $port){
$this->master=socket_create(AF_INET, SOCK_STREAM, SOL_TCP) or die("socket_create() failed");
socket_set_option($this->master, SOL_SOCKET, SO_REUSEADDR, 1) or die("socket_option() failed");
socket_bind($this->master, $address, $port) or die("socket_bind() failed");
socket_listen($this->master,20) or die("socket_listen() failed"); $this->sockets[] = $this->master;
$this->say("Server Started : ".date('Y-m-d H:i:s'));
$this->say("Listening on : ".$address." port ".$port);
$this->say("Master socket : ".$this->master."\n"); while(true){
$socketArr = $this->sockets;
$write = NULL;
$except = NULL;
socket_select($socketArr, $write, $except, NULL); //自动选择来消息的socket 如果是握手 自动选择主机
foreach ($socketArr as $socket){
if ($socket == $this->master){ //主机
$client = socket_accept($this->master);
if ($client < 0){
$this->log("socket_accept() failed");
continue;
} else{
$this->connect($client);
}
} else {
$this->log("^^^^");
$bytes = @socket_recv($socket,$buffer,2048,0);
$this->log("^^^^");
if ($bytes == 0){
$this->disConnect($socket);
}
else{
if (!$this->handshake){
$this->doHandShake($socket, $buffer);
}
else{
$buffer = $this->decode($buffer);
$this->send($socket, $buffer);
}
}
}
}
}
} function send($client, $msg){
$this->log("> " . $msg);
$msg = $this->frame($msg);
socket_write($client, $msg, strlen($msg));
$this->log("! " . strlen($msg));
}
function connect($socket){
array_push($this->sockets, $socket);
$this->say("\n" . $socket . " CONNECTED!");
$this->say(date("Y-n-d H:i:s"));
}
function disConnect($socket){
$index = array_search($socket, $this->sockets);
socket_close($socket);
$this->say($socket . " DISCONNECTED!");
if ($index >= 0){
array_splice($this->sockets, $index, 1);
}
}
function doHandShake($socket, $buffer){
$this->log("\nRequesting handshake...");
$this->log($buffer);
list($resource, $host, $origin, $key) = $this->getHeaders($buffer);
$this->log("Handshaking...");
$upgrade = "HTTP/1.1 101 Switching Protocol\r\n" .
"Upgrade: websocket\r\n" .
"Connection: Upgrade\r\n" .
"Sec-WebSocket-Accept: " . $this->calcKey($key) . "\r\n\r\n"; //必须以两个回车结尾
$this->log($upgrade);
$sent = socket_write($socket, $upgrade, strlen($upgrade));
$this->handshake=true;
$this->log("Done handshaking...");
return true;
} function getHeaders($req){
$r = $h = $o = $key = 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]; }
return array($r, $h, $o, $key);
} function calcKey($key){
//基于websocket version 13
$accept = base64_encode(sha1($key . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11', true));
return $accept;
} 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;
} function frame($s){
$a = str_split($s, 125);
if (count($a) == 1){
return "\x81" . chr(strlen($a[0])) . $a[0];
}
$ns = "";
foreach ($a as $o){
$ns .= "\x81" . chr(strlen($o)) . $o;
}
return $ns;
} function say($msg = ""){
echo $msg . "\n";
}
function log($msg = ""){
if ($this->debug){
echo $msg . "\n";
}
}
} new WS('localhost', 4000);
<script type="text/javascript">
var ws = new WebSocket("ws://localhost:4000");
ws.onopen = function(){
console.log("握手成功");
}
ws.onmessage = function(e){
console.log("message:" + e.data);
}
ws.onerror = function(){
console.log("error");
}
</script>
demo2:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>websocket_TEST</title>
</head>
<body>
<textarea class="log" style="width: 100%; height: 500px;">
=======websocket======
</textarea>
<input type="button" value="连接" onClick="link()">
<input type="button" value="断开" onClick="dis()">
<input type="text" id="text">
<input type="button" value="发送" onClick="send()">
<script type="text/javascript" src="http://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
<script>
function link(){
var url='ws://devapp.yaolan.com:8000';
socket=new WebSocket(url);
socket.onopen=function(){log('连接成功')}
socket.onmessage=function(msg){log('获得消息:'+msg.data);console.log(msg);}
socket.onclose=function(){log('断开连接')}
}
function dis(){
socket.close();
socket=null;
}
function log(var1){
$('.log').append(var1+"\r\n");
}
function send(){
socket.send($('#text').attr('value'));
}
function send2(){
var json = JSON.stringify({'type':'php','msg':$('#text2').attr('value')})
socket.send(json);
}
</script>
</body>
</html>
<?php
/*
创建类websocket($config);
$config结构:
$config=array(
'address'=>'192.168.0.200',//绑定地址
'port'=>'8000',//绑定端口
'event'=>'WSevent',//回调函数的函数名
'log'=>true,//命令行显示记录
); 回调函数返回数据格式
function WSevent($type,$event) $type字符串 事件类型有以下三种
in 客户端进入
out 客户端断开
msg 客户端消息到达
均为小写 $event 数组
$event['k']内置用户列表的userid;
$event['sign']客户标示
$event['msg']收到的消息 $type='msg'时才有该信息 方法:
run()运行
search(标示)遍历取得该标示的id
close(标示)断开连接
write(标示,信息)推送信息
idwrite(id,信息)推送信息 属性:
$users 客户列表
结构:
$users=array(
[用户id]=>array('socket'=>[标示],'hand'=[是否握手-布尔值]),
[用户id]=>arr.....
)
*/ class websocket{
public $log;
public $event;
public $signets;
public $users;
public $master;
public function __construct($config){
if (substr(php_sapi_name(), 0, 3) !== 'cli') {
die("请通过命令行模式运行!");
}
error_reporting(E_ALL);
set_time_limit(0);
ob_implicit_flush();
$this->event = $config['event'];
$this->log = $config['log'];
$this->master=$this->WebSocket($config['address'], $config['port']);
$this->sockets=array('s'=>$this->master);
}
function WebSocket($address,$port){
$server = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_set_option($server, SOL_SOCKET, SO_REUSEADDR, 1);
socket_bind($server, $address, $port);
socket_listen($server);
$this->log('开始监听: '.$address.' : '.$port);
return $server;
}
function run(){
while(true){
$changes=$this->sockets;
@socket_select($changes,$write=NULL,$except=NULL,NULL);
foreach($changes as $sign){
if($sign==$this->master){
$client=socket_accept($this->master);
$this->sockets[]=$client;
$user = array(
'socket'=>$client,
'hand'=>false,
);
$this->users[] = $user;
$k=$this->search($client);
$eventreturn = array('k'=>$k,'sign'=>$sign);
$this->eventoutput('in',$eventreturn);
}else{
$len=socket_recv($sign,$buffer,2048,0);
$k=$this->search($sign);
$user=$this->users[$k];
if($len<7){
$this->close($sign);
$eventreturn = array('k'=>$k,'sign'=>$sign);
$this->eventoutput('out',$eventreturn);
continue;
}
if(!$this->users[$k]['hand']){//没有握手进行握手
$this->handshake($k,$buffer);
}else{
$buffer = $this->uncode($buffer);
$eventreturn = array('k'=>$k,'sign'=>$sign,'msg'=>$buffer);
$this->eventoutput('msg',$eventreturn);
}
}
}
}
}
function search($sign){//通过标示遍历获取id
foreach ($this->users as $k=>$v){
if($sign==$v['socket'])
return $k;
}
return false;
}
function close($sign){//通过标示断开连接
$k=array_search($sign, $this->sockets);
socket_close($sign);
unset($this->sockets[$k]);
unset($this->users[$k]);
}
function handshake($k,$buffer){
$buf = substr($buffer,strpos($buffer,'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($this->users[$k]['socket'],$new_message,strlen($new_message));
$this->users[$k]['hand']=true;
return true;
}
function uncode($str){
$mask = array();
$data = '';
$msg = unpack('H*',$str);
$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));
$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 code($msg){
$msg = preg_replace(array('/\r$/','/\n$/','/\r\n$/',), '', $msg);
$frame = array();
$frame[0] = '81';
$len = strlen($msg);
$frame[1] = $len<16?'0'.dechex($len):dechex($len);
$frame[2] = $this->ord_hex($msg);
$data = implode('',$frame);
return pack("H*", $data);
}
function ord_hex($data) {
$msg = '';
$l = strlen($data);
for ($i= 0; $i<$l; $i++) {
$msg .= dechex(ord($data{$i}));
}
return $msg;
} function idwrite($id,$t){//通过id推送信息
if(!$this->users[$id]['socket']){return false;}//没有这个标示
$t=$this->code($t);
return socket_write($this->users[$id]['socket'],$t,strlen($t));
}
function write($k,$t){//通过标示推送信息
$t=$this->code($t);
return socket_write($k,$t,strlen($t));
}
function eventoutput($type,$event){//事件回调
call_user_func($this->event,$type,$event);
}
function log($t){//控制台输出
if($this->log){
$t=$t."\r\n";
fwrite(STDOUT, iconv('utf-8','gbk//IGNORE',$t));
}
}
}
<?
include 'websocket.class.php'; $config=array(
'address'=>'devapp.yaolan.com',
'port'=>'8000',
'event'=>'WSevent',//回调函数的函数名
'log'=>true,
);
$websocket = new websocket($config);
$websocket->run();
function WSevent($type,$event){
global $websocket;
if('in'==$type){
$websocket->log('客户进入id:'.$event['k']);
}elseif('out'==$type){
$websocket->log('客户退出id:'.$event['k']);
}elseif('msg'==$type){
$websocket->log($event['k'].'消息:'.$event['msg']);
roboot($event['sign'],$event['msg']);
}
} function roboot($sign,$t){
global $websocket;
switch ($t)
{
case 'hello':
$show='hello,GIt @ OSC';
break;
case 'name':
$show='Robot';
break;
case 'time':
$show='当前时间:'.date('Y-m-d H:i:s');
break;
case '再见':
$show='( ^_^ )/~~拜拜';
$websocket->write($sign,'Robot:'.$show);
$websocket->close($sign);
return;
break;
case '天王盖地虎':
$array = array('小鸡炖蘑菇','宝塔震河妖','粒粒皆辛苦');
$show = $array[rand(0,2)];
break;
default:
$show='( ⊙o⊙?)不懂,你可以尝试说:hello,name,time,再见,天王盖地虎.';
}
$websocket->write($sign,'Robot:'.$show);
}
?>
websocket的php测试demo的更多相关文章
- Win7搭建nginx+php+mysql开发环境以及websocket聊天实例测试
Win7搭建nginx+php+mysql开发环境以及websocket聊天实例测试一.下载相关安装包 1.下载nginx最新版本(nginx1.3.13版之后才支持websocket协议) 下载地址 ...
- android gps开发必备资料(含测试demo下载)
入门资料参考: How accurate is Android GPS? Part 1: Understanding Location Data How accurate is Android GPS ...
- websocket 70K连接测试
websocket 70K连接测试 最近使用socket.io做了一个实时应用,实时性.稳定性还是很让人满意的.如果拿socket.io来做小型应用,综合效率应该是最高的.但是网上少有socket.i ...
- 所有文章的测试Demo
Mqtt C++ Client 测试Demo https://pan.baidu.com/s/1Ue00GYv2SUd8aTquhvOW1w
- <正则吃饺子> :关于redis集群的测试demo
redis集群的测试demo,来自网络,具体不详. 1.下载地址,如下:http://download.csdn.net/detail/u012543819/9729291 2.项目是java项目,结 ...
- mock api测试demo
前言 本测试demo基于Spring框架测试,这几个月也是刚刚接触Spring的项目.如果不对的地方请多谅解. 正文 1.创建测试类,添加注解 @RunWith(SpringRunner.class) ...
- HTML5 WebSocket 实时推送信息测试demo
测试一下HTML5的websocket功能,实现了客户端→服务器实时推送信息到客户端,包括推送图片: websocket实现MessageInbound类 onTextMessage()/onBina ...
- websocket ----简介,以及demo
#导报 from dwebsocket.decorators import accept_websocket WebSocket是一种在单个TCP连接上进行全双工通信的协议 WebSocket使得客户 ...
- webSocket ws协议测试
最近公司做了个直播的项目,需要用到Websocket进行通信,因而需要对socket最大连接数及稳定性进行测试.当初得到这一需求的时候,唯一想到的就是jmeter,从百度下载相应的socket依赖ja ...
随机推荐
- 抛出自定义异常,spring AOP事务不回滚的解决方案
spring AOP 默认对RuntimeException()异常或是其子类进行事务回滚,也就是说 事务回滚:throw new RuntimeException("xxxxxxxxxxx ...
- DOJO 如何清空表单
在Dojo里,清空表单非常简单 在设置好了相关的环境之后,只要设置dom.byId('formid').reset(); / dijit.byId('formid').reset; Jqu ...
- 最新 Arduino 驱动 12接口/户外 LED显示屏/LED点阵屏/LED单元板
起因 现有的驱动LED显示屏的资料,比较好的只有这个.但是它驱动的是08接口的室内显示屏,而我要驱动的是12接口的户外显示屏.两种屏幕的区别在于户外屏幕点阵比较稀疏,而且二者的扫描方式,驱动方式都不太 ...
- Yii入门,登录
验证和授权在页面需要限制访问时用到.验证就是确认某人就是他所声称的那个人.通常涉及到用户名和密码,但也包含其他方式,例如智能卡,指纹等.授权是在验证用户后,查明他是否被允许管理指定的资源.通常判断他是 ...
- 把php.exe加入系统环境变量-使用命令行可快速执行PHP命令
有时候在执行长时间运行的脚本程序的时候,浏览器是架不住的.我们就可以使用CMD命令行或者LINUX命令行执行PHP程序 1.把PHP.EXE加入到环境变量,不用每次都进入到PHP的目录 ① 右击我的 ...
- 浏览器的DNS缓存
通过设置hosts文件可以强制指定域名对应的IP,当修改hosts文件,想要浏览器生效,最直接的方法关闭浏览器后重新开启:如果不想重启浏览器,只需要清空浏览器的DNS缓存即可.清空DNS缓存在chro ...
- 【JNI】OPUS压缩与解压的JNI调用(.DLL版本)
OPUS压缩与解压的JNI调用(.DLL版本) 一.写在开头: 理论上讲,这是我在博客园的第一篇原创的博客,之前也一直想找个地方写点东西,把最近做的一些东西归纳总结下,但是一般工程做完了一高兴就把东西 ...
- HTML 学习进度备忘
书签:”HTML 高级教程“及后面的内容尚未学习,另外跳过的内容有待跟进 __________________ 学习资源:W3School. 开始时间:2013.11.20 简述:此网址做为学习教程相 ...
- .Net 学习
.Net 的微型Web框架Nancy ORM工具 Simple Data Ojbective-C 与 swift Xamarin for VisualStudio jQuery 1. 绝对的万金油,核 ...
- [LeetCode] Missing Number (A New Questions Added Today)
Given an array containing n distinct numbers taken from 0, 1, 2, ..., n, find the one that is missin ...