<?php
/**
* 一个简单的socke服务端
*/
class Socket{
public $address ="0.0.0.0";
public $port=8081;
private $_server;
public function __construct(){
echo "开始创建对象...".PHP_EOL;
$socket = socket_create(AF_INET,SOCK_STREAM,SOL_TCP) or self::error($socket );
echo "绑定端口:".$this->address.":".$this->port."...".PHP_EOL;
$tmp = socket_bind($socket,$this->address,$this->port) or self::error($tmp);;
echo "开始监听...".PHP_EOL;
$tmp = socket_listen($socket, 4) or self::error($tmp );
echo "服务启动成功".PHP_EOL;
$this->_server = &$socket;
}
public static function error($server){
die(socket_strerror(socket_last_error($server)) . "/n");
}
/**
* 解析http报文为数组
* @param $data
* @return array
*/
public function analysisBuffer($data){
$herder =[];
$lines = preg_split("/\r\n/",$data);
foreach ($lines as $line){
$row =explode(": ",$line);
if(count($row) ==2){
$herder[$row[0]] =$row[1];
}
}
return $herder;
}
/**
* 返回报文
* @param $buffer
* @param $client
* @return bool
*/
public function hand_shake($buffer,$client){
$headers = $this->analysisBuffer($buffer);
$key =$headers['Sec-WebSocket-Key'];
$new_key = base64_encode(sha1($key."258EAFA5-E914-47DA-95CA-C5AB0DC85B11",true));
$message = "HTTP/1.1 101 Switching Protocols\r\n";
$message .= "Upgrade: websocket\r\n";
$message .= "Sec-WebSocket-Version: 13\r\n";
$message .= "Connection: Upgrade\r\n";
$message .= "Sec-WebSocket-Accept: " . $new_key . "\r\n\r\n";
socket_write($client,$message,strlen($message));
return true;
}
/**
* 加密
* @param $message
* @return string
*/
public function encode($message){
$len = strlen($message);
if($len <=125){
return "\x81".chr($len).$message;
}elseif ($len<=65535){
return "\x81".chr(126).pack("n",$len).$message;
}else{
return "\x81".chr(127).pack("xxxxN",$len).$message;
}
}
/**
* 解密
* @param $buffer
* @return string|null
*/
public function decode($buffer){
$len = $masks = $data = $decode =null;
$len = ord($buffer[1]) & 127;
if($len === 126){
$masks = substr($buffer,4,4);
$data = substr($buffer,8);
}elseif ($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++){
$decode .= $data[$index] ^ $masks[$index % 4];
}
return $decode;
}
public function run(){
$clients = [$this->_server];
do {
$read =$clients;
$write =null;
$except =null;
if (socket_select($read,$write,$except,null)>0){
foreach ($read as $item){
if($item === $this->_server){
// 首次链接
if(!$socket_client = socket_accept($item)){
continue;
}else{
$client_data = @socket_read($socket_client,1024);
if($client_data=== false){
socket_close($socket_client);
}
// 建立握手
$this->hand_shake($client_data ,$socket_client);
// 获取客户端信息
socket_getpeername($socket_client,$ip,$port);
$clients[$ip.":".$port]= $socket_client;
echo "有一个新的链接".$ip.":".$port."\n";
}
}else{
$result = @socket_recv($item,$msg,1024,0);
if($result === false){continue;}
if ($result ===0 ){
socket_close($item);
$key1 =array_search($item,$read);
unset($read[$key1]);
$key2 = array_search($item,$clients);
unset($clients[$key2]);
}else{
// 解码客户端消息
$web_msg= $this->decode($msg);
$id = array_search($item ,$clients);
echo "client:".$id ."说:".$web_msg."\n";
// 加密客户端消息
$response = $this->encode($web_msg);
// 广播
foreach ($clients as $client){
if($client != $this->_server ){
if(false == @socket_write($client,$response,strlen($response))){
socket_close($client);
$key1 = array_search($client,$read);
unset($read[$key1]);
$key2 = array_search($client,$clients);
unset($clients[$key2]);
}
}
}
}
}
}
}
} while (true);
}
}
$server = new Socket();
$server->run();
-
近期文章
- Apple Script 常用函数
- ubuntu 18.04 搭建wordress(LAMP)
- Node.js 爬电影天堂种子
- js常用正则验证器
- node.js 的爬虫puppeteer基本使用
- expect登录mysql
- 自己写一个简陋版Vue
- 超级全面的php文件操作
- Linux 使用expect交互方式ssh登录
- Linux 中添加登录通知脚本
- 一个简单的php socket服务端
- php 拓展包,依赖包,可视化
- 快捷指令:自动登录,上报健康,填写表单,上传图片
- Php在不实话化类的情况下,获取类的所有方法和形参
- php 获取函数或方法的形参和实参
- 免费的东西 你凭什么收费 “氧化钙” “化钙” “氧化钙”
- 我要创建“创建您自己的证书颁发机构”,看官方文档缺少选项。请极速回复
- jvectorMap 地理数据包整理集合
- GitHub Desktop for Mac 汉化语言包
- Vue项目中定时器动态修改时间间隔
- Vue-CLI中配置postcss-pxtorem自动将px转换为rem
- Layui V2.6.3 Table
- V2Ray 安装配置教程
- js中new Date().format()方法不可用问题
- 2022年前端CSS 框架排名
- wordpress 站点统计jMaps插件(测试版)
- ubuntu18.04 sudo apt-get install E: 无法定位软件包
- Js当前页面截图,并保存到本地
- appserv 的php多版本下载工具
- appserv本地开发环境,经常需要添加多站点,手动操作很麻烦,于是创建控制台操作
- fastAdmin 框架api模块认证问题
- php 控制台打印二维数组
- php QrReader解析二维码数据
- wordpress中mac风格代码高亮显示
- 原生js首字母大写
- python win32con 剪切板操作
近期评论
归档
分类