<?php
header("Content-type: text/html; charset=utf-8");
/*
创建类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;
private $sda = array(); //已接收的数据
private $slen = array(); //数据总长度
private $sjen = array(); //接收数据的长度
private $ar = array(); //加密key
private $n = array();
public function __construct($config) {
if (substr(php_sapi_name(), 0, 3) !== 'cli') {
die("请通过命令行模式运行!");
}
// error_reporting(E_ALL ^ E_NOTICE);
// error_reporting(E_ALL ^ E_WARNING);
//error_reporting(0);
//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((string)$this->master => $this->master);
}
public 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;
}
public 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);
if ($client < 0) {
echo "socket_accept() failed: reason: " . socket_strerror(socket_last_error()) . "\n";
break;
}
$this->sockets[(string)$client] = $client;
$user = array('socket' => $client, 'hand' => false,);
$this->users[(string)$client] = $user;
$k = $this->search($client);
$eventreturn = array('k' => $k, 'sign' => $sign);
$this->eventoutput('in', $eventreturn);
//$this->handshake((string)$sign,1);
} else {
$len = 0;
$buffer = '';
//读取该socket的信息,注意:第二个参数是引用传参即接收数据,第三个参数是接收数据的长度
do {
$l = socket_recv($sign, $buf, 1024, 0);
$len+= $l;
$buffer.= $buf;
} while ($l == 1024);
/*
$len = socket_recv($sign, $buffer, 2222048, 0);
if ($len < 0) {
echo "socket_recv() failed: reason: " . socket_strerror(socket_last_error()) . "\n";
break;
}*/
$k = $this->search($sign);
if ($len < 7) {
$this->close($sign);
$eventreturn = array('k' => (string)$sign, 'sign' => $sign);
$this->eventoutput('out', $eventreturn);
continue;
}
if (!$this->users[(string)$sign]['hand']) { //没有握手进行握手
$this->handshake($sign, $buffer);
} else {
//$buffer = $this->uncode($buff