网站如何做防劫持/网络建站流程

网站如何做防劫持,网络建站流程,wordpress https登陆,网站建设需要哪些技术在之前的博文中,我们已经学完了如果使用swoole搭建websocket长连接,也学会了swoole的多进程数据共享操作。但在一个完整的websocket长连接日常操作链中,服务端往往会主动给在线的用户单独推送消息,会群发一些消息。在Swoole-webso…

7092c096dce3d9c7c1df20b3f3034a52.png

在之前的博文中,我们已经学完了如果使用swoole搭建websocket长连接,也学会了swoole的多进程数据共享操作。

但在一个完整的websocket长连接日常操作链中,服务端往往会主动给在线的用户单独推送消息,会群发一些消息。

在Swoole-websocket中给我们提供了一个onRequest事件,该事件用于监听外部请求。

也就是我们可以通过http请求向websocket中调取数据,进而发送消息。

onRequest的示例代码如下:

官网文档是:https://wiki.swoole.com/wiki/page/397.html

 $this->_ws->on('request', function ($request, $response) {//var_dump($request);# 如果你是get的,就改成get,可以用dump看看$request$param = $request->post;$data  = [];$data['code'] = 3;$data['user_nice'] = '系统通知';$data['content'] = $param['content'];# 下面我们来广播消息if (empty($param['user_id'])) {# 群发$this->broadcast($this->_ws, $this->json($data));# 返回消息$this->endRequest('200', '发送成功', $request, $response);} else {# 单发if (empty($this->_ws->user[$param['user_id']]['fd'])) {# 返回消息$this->endRequest('500', '客户不存在', $request, $response);} else {$user = $this->_ws->user[$param['user_id']];if ($user['status'] == 0) {# 返回消息$this->endRequest('500', '客户已下线', $request, $response);} else {$this->_ws->push($user['fd'], $this->json($data));# 返回消息$this->endRequest('200', '发送成功', $request, $response);}}}
});
其中最重要的是endRequest这个方法的代码,我们接着往下看:/*** request事件返回值
*/
private function endRequest($code, $msg, $request, $response) {$json = ['code' => "$code",'msg'  => "$msg",];# 输出响应$return = json_encode($json, JSON_UNESCAPED_UNICODE);# 需要end事件,否注会报500错误,并无结果返回# 不知道为啥,CLI模式下这个事件一次请求会有2次监听,但发现最后一次其中的server->request_uri会有个/favicon.ico参数# 所以凭借这个参数,我们可以做判断,放弃掉第一次监听返回# 还有,如果我们直接在onRequest中过滤掉第一次监听,那第二次监听就不会执行,也会报500错误# 所以我们只能在返回的时候做下手脚//if($request->server['request_uri'] == '/favicon.ico') {$response->end($return);//}# 而且我发现经过这样处理,onRequest事件那边也只会有一次请求了,特别奇怪。# 而且这样返回之后,浏览器直接请求还是报500错误。# 熟悉Swoole的朋友可以在下方留言,指教下我的疑惑。
}

从上面的注释中我们可以看出,endRequest的输出值很奇怪,它支持CLI模式下运行,但该模式下的会有2次endRequest监听,需要使用server->request_uri/favicon.ico参数进行拦截输出返回值,否注将报错。

而通过CURL或浏览器发包的方式则不能拦截,同时这种请求方式只有1次endRequest监听,所以不能拦截返回值。

同时需要注意,endRequest同步输出返回值,不能直接使用echo,而是需要把返回内容放在$response->end()中。

下面我们来看看完整的server.php端代码:

<?php
// +----------------------------------------------------------------------
// 小黄牛blog - Swoole 即时通讯交互处理
// +----------------------------------------------------------------------
// Copyright (c) 2018 https://xiuxian.junphp.com All rights reserved.
// +----------------------------------------------------------------------
// Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// Author: 小黄牛 <1731223728@qq.com>
// +----------------------------------------------------------------------
class Server{/*** 客户端身份存储器*/private $_table = []; /*** WS的启动实例*/private $_ws;/*** host-IP,0.0.0.0表示允许接收所有请求*/private $_host = '0.0.0.0';/*** 端口号*/private $_port = '9502';/*** 最大服务端心跳重连次数*/private $_max  = 3;/*** 强制心跳重连启动状态*/private $_status = true;/*** 这是启动服务端的入口*/public function run() { $this->start_service(); $this->start_table(); $this->request();$this->start_handshake();$this->start_message();$this->end();}/*** ①启动websocker服务*/private function start_service() {# 创建websocket服务器对象,监听0.0.0.0:9502端口$this->_ws = new swoole_websocket_server($this->_host, $this->_port);$this->_ws->set(['worker_num' => 4,// 开4个工作进程]);}/*** ①创建Table服务*/private function start_table() {# 创建最大只能存储1024个用户的数据$this->_table = new swoole_table(1024);# 创建字段$this->_table->column('fd', swoole_table::TYPE_INT, 8); // FD$this->_table->column('status', swoole_table::TYPE_INT, 8); // 离线状态$this->_table->column('heartbeat', swoole_table::TYPE_INT, 8); // 心跳重连数$this->_table->column('user_id', swoole_table::TYPE_STRING, 32); // 会员ID$this->_table->column('user_nice', swoole_table::TYPE_STRING, 32); // 会员名称$this->_table->create();# 将表附加到ws实例里,方便后续使用$this->_ws->user = $this->_table;}/*** ②监听WebSocket握手申请*/private function start_handshake() {# 监听WebSocket连接打开事件$this->_ws->on('open', function ($ws, $request){# 这里可以做些鉴权验证之类的});}/*** ③监听客户端消息发送请求*/private function start_message() {# 监听WebSocket消息事件$this->_ws->on('message', function ($ws, $frame) {$data    = json_decode($frame->data, true);$user_id = $data['user_id'];# 加入存储器$this->_ws->user->set($user_id, ['fd'        => $frame->fd, # FD'status'    => 1, # 设置上线状态'heartbeat' => 0, # 重置心跳重连数'user_id' => $data['user_id'], # 用户ID'user_nice' => $data['user_nice'], # 用户昵称]);# 登录广播处理if ($data['code'] == 1) {# 发送广播上线消息$data['content'] = '【'.$data['user_nice'].'】骑着小黄牛上线啦~!';$this->broadcast($ws, $this->json($data), $user_id);# 心跳重连检测} else if ($data['code'] == 4) {$this->broadcast($ws, $frame->data, $user_id);$this->timer();# 其他请求} else {# 广播消息$this->broadcast($ws, $frame->data, $user_id);}});} /*** ④监听客户端退出事件*/private function end() {# 这里加入了unset,清除open存储器,防止存储器无限增大# 监听WebSocket连接关闭事件$this->_ws->on('close', function ($ws, $fd) {$user = null;foreach ($this->_ws->user as $k=>$v) {if ($v['fd'] == $fd) {$user = $v;}}# 如果没用用户就跳过if (!$user) {return false;}# 获取用户ID$user_id = $user['user_id'];# 获取用户nice$user_nice = $user['user_nice'];# 设置离线状态$this->_ws->user->set($user_id, ['status'    => 0, # 设置离线状态]);$data = ['code' => 2,'user_id' => $user_id,'user_nice' => $user_nice,'content' => '【'.$user_nice.'】骑着小扫帚灰溜溜的走了~~!'];# 广播消息$this->broadcast($ws, $this->json($data));});$this->_ws->start();}/*** ④监听外部请求推送事件*/private function request() {$this->_ws->on('request', function ($request, $response) {//var_dump($request);# 如果你是get的,就改成get,可以用dump看看$request$param = $request->post;$data  = [];$data['code'] = 3;$data['user_nice'] = '系统通知';$data['content'] = $param['content'];# 下面我们来广播消息if (empty($param['user_id'])) {# 群发$this->broadcast($this->_ws, $this->json($data));# 返回消息$this->endRequest('200', '发送成功', $request, $response);} else {# 单发if (empty($this->_ws->user[$param['user_id']]['fd'])) {# 返回消息$this->endRequest('500', '客户不存在', $request, $response);} else {$user = $this->_ws->user[$param['user_id']];if ($user['status'] == 0) {# 返回消息$this->endRequest('500', '客户已下线', $request, $response);} else {$this->_ws->push($user['fd'], $this->json($data));# 返回消息$this->endRequest('200', '发送成功', $request, $response);}}}});}/*** request事件返回值*/private function endRequest($code, $msg, $request, $response) {$json = ['code' => "$code",'msg'  => "$msg",];# 输出响应$return = json_encode($json, JSON_UNESCAPED_UNICODE);# 需要end事件,否注会报500错误,并无结果返回# 不知道为啥,CLI模式下这个事件一次请求会有2次监听,但发现最后一次其中的server->request_uri会有个/favicon.ico参数# 所以凭借这个参数,我们可以做判断,放弃掉第一次监听返回# 还有,如果我们直接在onRequest中过滤掉第一次监听,那第二次监听就不会执行,也会报500错误# 所以我们只能在返回的时候做下手脚//if($request->server['request_uri'] == '/favicon.ico') {$response->end($return);//}# 而且我发现经过这样处理,onRequest事件那边也只会有一次请求了,特别奇怪。# 而且这样返回之后,浏览器直接请求还是报500错误。# 熟悉Swoole的朋友可以在下方留言,指教下我的疑惑。}/*** 广播消息* @todo 无* @author 小黄牛* @version v1.0.0.1 + 2018.11.12* @deprecated 暂不弃用* @global 无* @param object $wx 实例* @param string $content 广播内容* @param string $id 用户的userid*  @param bool $status 是否做心跳限制 * @return void*/private function broadcast($ws, $content, $id=null, $status=false) {# 向所有人广播foreach ($this->_ws->user as $k=>$v) {# 不向自己广播,并且要在线的# 注意,这里一定要有上线状态的限制,否则假设用户已经退出,但你的进程还开着,实际上已经关闭,这时候push就会报错# 只有正常在线的用户才能接收到广播# 加入心跳检测限制if ($k != $id && $v['status'] == 1 && $status == true) {$ws->push($v['fd'], $content);} else if ($v['user_id'] != $id && $v['status'] == 1 && $v['heartbeat'] == 0) {$ws->push($v['fd'], $content);}}}/*** 数组转json* @todo 无* @author 小黄牛* @version v1.0.0.1 + 2018.11.08* @deprecated 暂不弃用* @global 无* @param array $array 数组* @return json*/private function json($array) {return json_encode($array, JSON_UNESCAPED_UNICODE);}/*** 服务端定时强制心跳检测* @todo 无* @author 小黄牛* @version v1.0.0.1 + 2018.11.08* @deprecated 暂不弃用* @global 无* @return void*/private function timer() {# 注意强制心跳触发器不能放在open事件里,因为那时候用户还没有提交登录请求,是还没有userID的# 还有,强制心跳定时器只能触发一次,否则会出现生成多个定时器的情况if ($this->_status) {$this->_status = false;/*** ⑤服务端强制心跳检测* 每隔1分钟发送1次,如果连续3次强制心跳检测未通过,服务端将强制断开连接*/$obj = $this;swoole_timer_tick(60000, function ($timer_id) use (&$obj) {# 广播消息$obj->broadcast($obj->_ws, $obj->json(['code' => 5]), null, true);# 所有人的心跳次数+1foreach ($this->_ws->user as $k=>$v) {if (empty($v['heartbeat'])) {# 重置心跳次数$this->_ws->user->set($v['user_id'], ['heartbeat' => 0,]);}# 心跳次数累加$this->_ws->user->set($v['user_id'], ['heartbeat' => $v['heartbeat']+1]);# 心跳次数大于等于_max && 在线的 的连接关闭if ($v['heartbeat'] >= $obj->_max && $v['status'] == 1) {$data = $v;# 发送强制掉线广播$data['code'] = 6;$data['content'] = '【'.$data['user_nice'].'】已被服务端强制下线!';$obj->broadcast($obj->_ws, $obj->json($data), null, true);# 这里不需要unset连接,因为在close事件中,已经将这个连接设置为离线了# 主动关闭连接k$obj->_ws->close($v['fd']);}}});}}
}
$socketServer = new Server();
$socketServer->run();

然后再看如何给websocket主动推送的client.php端代码:

<?php
// +----------------------------------------------------------------------
// 小黄牛blog - websocket - http发包给TCP
// +----------------------------------------------------------------------
// Copyright (c) 2018 https://xiuxian.junphp.com All rights reserved.
// +----------------------------------------------------------------------
// Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// Author: 小黄牛 <1731223728@qq.com>
// +----------------------------------------------------------------------
function https_request($url, $data = null){# 初始化一个cURL会话$curl = curl_init();  //设置请求选项, 包括具体的urlcurl_setopt($curl, CURLOPT_URL, $url);curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);  //禁用后cURL将终止从服务端进行验证curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);if (!empty($data)){curl_setopt($curl, CURLOPT_POSTFIELDS, $data);  //设置具体的post数据}curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);        $response = curl_exec($curl);  //执行一个cURL会话并且获取相关回复//$httpCode = curl_getinfo($curl,CURLINFO_HTTP_CODE); //echo $httpCode;curl_close($curl);  //释放cURL句柄,关闭一个cURL会话return $response;
}
var_dump(https_request('http://IP:端口', ['user_id' => '用户ID',// 为空群发'content'=> '测试内容'
]));

我们只需要通过访问client.php,就能给指定用户推送消息拉。

同时我们需要注意,在真正开发中,我们还需要对onRequest事件的请求进行加密跟鉴权处理,否注很容易被竞争对手恶意攻击。

而且服务端还可以通过onRequest事件拉取到所有的在线用户消息,更多相关的功能都可自行扩展。


最后推荐大家可以用下我开源的一个基于Swoole4.5+研发的PHP框架。该框架基于注解实现了很多好玩的功能,很适合新人快速上手Swoole扩展。

SW-X框架-专注高性能便捷开发而生的PHP-SwooleX框架​www.sw-x.cn
604f8e745dacdb12498ada925ea17262.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/498976.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python因子分析法_python——因子分析

因子分析用Python做的一个典型例子 一、实验目的 采用合适的数据分析方法对下面的题进行解答二、实验要求 采用因子分析方法&#xff0c;根据48位应聘者的15项指标得分&#xff0c;选出6名最优秀的应聘者。 三、代码 importpandas aspd importnumpy asnp importmath asmath imp…

polycom安卓手机客户端_三款免费「游戏串流」APP,在手机/电视上玩PC游戏

以前想把电脑游戏输出到电视机上玩&#xff0c;得用HDMI线输出&#xff0c;如果电脑主机和电视机离太远&#xff0c;HDMI线不够长&#xff0c;还得抱电脑主机到电视机旁边&#xff0c;非常不方便。随着技术的发展&#xff0c;现在已经有「串流」功能&#xff0c;只要电视机和电…

python获取返回值_python如何获取函数的返回值

函数需要先定义后调用&#xff0c;函数体中 return 语句的结果就是返回值。如果一个函数没有 reutrn 语句&#xff0c;其实它有一个隐含的 return 语句&#xff0c;返回值是 None&#xff0c;类型也是 NoneType。return 语句的作用&#xff1a;结束函数调用、返回值 指定返回值…

java模拟器百度_Java模拟实现百度文档在线浏览

这个思路是我参考网上而来&#xff0c;代码是我实现。采用Apache下面的OpenOffice将资源文件转化为pdf文件&#xff0c;然后将pdf文件转化为swf文件&#xff0c;用FlexPaper浏览。ok&#xff0c;A、下载OpenOffice (转换资源文件)B、下载JodConverter(调用OpenOffice)C、下载Sw…

body click js 委托_JS 事件循环

进程 线程CPU 分配资源的最小单位是进程&#xff0c;同一个时间内单个 CPU 只能运行一个进程&#xff0c;单个 CPU 一次只能运行一个任务CPU 调度的最小单位是线程&#xff0c;一个进程里面包含多个线程。可以看看阮老师的这篇文章&#xff0c;进程与线程的一个简单解释浏览器的…

django jsonresponse_利用 Django 动态展示 Pyecharts 图表数据的几种方法

本文将介绍如何在 web 框架 Django 中使用可视化工具 Pyecharts, 看完本教程你将掌握几种动态展示可视化数据的方法!Django 模板渲染1. 新建一个 Django 项目命令行中输入以下命令django-admin startproject pyecharts_django_demo创建一个应用程序python manage.py startapp d…

python网页登录验证码不显示_进网页需要验证码?不好意思,Python从来不惧各种验证码!...

今天要来说说滑动验证码了大家应该都很熟悉点击滑块然后移动到图片缺口进行验证现在越来越多的网站使用这样的验证方式为的是增加验证码识别的难度那么&#xff0c;对于这种验证码应该怎么破呢接下来就是见证神奇的时刻打开 b 站的登录页面可以看到登录的时候需要进行滑块验证按…

怎么调用新建模型里文章的内容_优雅地进行Tensorflow Lite模型转换

初涉知乎江湖&#xff0c;知道大佬很多&#xff0c;请温柔以待&#xff01;&#xff01;&#xff01;七日凌晨&#xff0c;谷歌连夜发布了有关于Tensorflow最新成果和技术&#xff0c;这应该是贾扬清离开脸书后另一个深度学习界令人惊呼的事件了吧&#xff01;&#xff08;旁白…

git add后取消_Git常用命令-总结

创建git用户$ git config --global user.name "Your Name"$ git config --global user.email "emailexample.com"初始化一个Git仓库&#xff0c;使用git init命令。添加文件到Git仓库&#xff0c;分两步&#xff1a;使用命令git add &#xff0c;注意&…

查看csv编码_[小O地图-数据] - 坐标转地址文字(逆地理编码)

小O地图是一款基于互联网地图进行地理数据处理、分析、图表的软件。致力为广大科研人员提供专业地图数据&#xff0c;用于科研及学习。小&#xff2f;地图提供将【经纬度坐标转换为地址】的功能&#xff0c;例如&#xff1a;将“116.359861, 39.917225” 转换为 “北京市西城区…

python自动化办公源码_python自动化办公:文件篇(自动整理文件,一键完成)

import os list_all[]#初始化一个空列表 for root ,dirs,files in os.walk(rC:UsersShineionDesktop新建文件夹): for name in files: file_pathos.path.join(root,name)#包含路径的文件 file_nameos.path.split(file_path)[-1] list_all.append(file_name) print(list_all)如果…

ocr中文数据集_CNOCR:测试集准确率最高98%,自带识别模型的中文OCR包

今天 Gitee 为大家介绍的是一款中文 OCR 包。大家都知道&#xff0c;训练模型是一件非常费时费力的事情&#xff0c;但今天这款项目已经自带训练好的识别模型&#xff0c;我们只需要下载下来使用即可&#xff0c;可以说是非常方便了&#xff0c;那么下面我们就去看看这个项目的…

sha算法源代码java_SHA算法Java实现

一 简介安全散列算法固定长度摘要信息二 SHA算法SHA-1、SHA-2(SHA-224、SHA-256、SHA384、SHA-512)三 SHA算法实现package com.imooc.security.sha; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.Security; impo…

arraylist remove() java_执行ArrayList的remove(object)方法抛异常?

简介或许有很多小伙伴都尝试过如下的代码&#xff1a;然后会发现抛出java.util.ConcurrentModificationException异常&#xff0c;这是一个并发异常。那么这个到底是什么情况&#xff1f;首先需要介绍一下增强for循环增强for循环增强for循环是Java1.5后&#xff0c;Collection实…

centos gdb调试_gdb-miss-debuginfo

使用gdb调试core时候&#xff0c;提示Missing separate debuginfos的解决办法。错误提示错误提示信息如下&#xff1a;Missing separate debuginfos, use: debuginfo-install glibc-2.17-106.el7_2.8.x86_64 libaio-0.3.109-13.el7.x86_64 libgcc-4.8.5-4.el7.x86_64 libstdc-4…

怎么判断自己启动的线程是否执行完成 java_多线程?怎么用?

Java线程&#xff1a;概念与原理操作系统中线程和进程的概念现在的操作系统是多任务操作系统。多线程是实现多任务的一种方式。进程是指一个内存中运行的应用程序&#xff0c;每个进程都有自己独立的一块内存空间&#xff0c;一个进程中可以启动多个线程。比如在Windows系统中&…

mysql设置中文_Flask中MySQL预热

Flask和MySQL导读现在Flask已经学习到了类视图,它其实是这样一个关系FLask高级视图视图函数app.route\add_url_rule类视图蓝图blueprint(这个接下来要讲)结束蓝图后,接着就是Flask数据库的结合SQLAlchemy.在学习SQLAlchemy之前,希望和大家一起了解学习一下mysql这篇文章不涉及理…

html首行缩进2字符怎么设置_Word如何设置首行缩进2字符

在使用Word编写书籍或者文稿时&#xff0c;我们都会有个习惯将每个段落前面空两个字符&#xff0c;这样可以很好的方便读者阅读时分辨段落。有的人习惯用几个空格来代替&#xff0c;有的人习惯用空白字符V1来代替(像Word联盟网站上的每篇教程就是用V1来标记段落的)。其实在Word…

java 面试什么是类_Java 面试题代码类收集

long temp(int)3.9;System.out.println(temp);temp%2;System.out.println(temp);31View CodeJava里面类的方法名可以与类名一样&#xff0c;与构造函数的区别是方法有返回值&#xff0c;构造函数没有。public classUserInfo {publicUserInfo(){}publicString UserInfo(){return…

idea jdk配置_在IDEA中DEBUG Javac源码

背景在做JSR269的深度解析的时候&#xff0c;需要对javac的源代码进行单步调试并跟踪。因此在这里记录下具体的调试步骤。调试环境&#xff1a;OS: MacOS 10.14.5JDK&#xff1a;JDK_1.8IDEA: IntelliJ IDEA 2019.1.3下载Javac源码可以直接用JDK的github镜像仓库处下载&#xf…