菜鸟公园
  • 编程技能
    • PHP
    • CPP
    • Golang
    • MySQL
    • 工具分享
  • 英语学习
  • 信文随笔
  • 关于本站
sign in/up

博客

2022-04-23 作者:菜鸟DJ 0
信文随笔

记一次和流氓软件战斗的过程

一次偶然的机会,看到了一个软件的输出日志上有一个很奇怪的代理请求。本地的随机端口访问到我的代理软件端口,请求转发数据到localhost:[50051-500053]。而且是不停循环。用netstat查看,发现本地并没有监听50051-50053的端口,于是盲猜开始了。

起先以为是我的代理配置错了,导致请求被错误的导向了代理软件。所以把所有软件检查一遍,关闭代理配置。发现连接依旧,不停的创建tcp。
在搜索引擎的帮助下,检查了所有搜出来可能出问题的软件。并且将其卸载了,问题依旧。

难道我电脑因为前段时间装了360中病毒了?于是下载终极杀器-360系统急救箱,花了3个多小时全盘扫描。换来的结果确实系统很干净,只有几个无关痛痒的处理。

好了,这下有点意思了。于是打开proxifier劫持所有localhost上的流量。创建一个不存在的proxy server。然后就坐看监控后台,等待目标出现。

有意思的一幕出现了。explorer.exe 这个软件创建tcp的目标居然是我原本的proxy server。这就神奇了,我没设置系统代理,所有代理都是软件层面配置。explorer.exe 是一个windows的外壳程序,他怎么知道我的代理软件是什么。这下真的是丈二和尚摸不着头脑了。加上夜深了,于是睡觉放弃。等脑子清醒了在搞。

时间来到了第二天,按照习惯更新每天github仓库,在同步github的上突然想到git bash上是不是也配置了代理,于是echo $http_proxy。发现还真他娘的有。然而查看profile文件时,它居然没有 .bash_rc 文件,又是一头雾水。

$ cat ~/.bash_history
Display all 53 possibilities? (y or n)

于是打开搜索工具,发现gitbash可以读环境变量。打开系统环境变量设置一看,果然在个人环境变量里设置了http_proxy=localhost:xxxxx(我真的不记得我啥时候配置的)。删除之。

再次打开proxifier软件,重复之前的步骤,这些explorer.exe 的目标到了localhost:[50051-50053],那么代理工具的这个疑点解决了。但是为什么频繁的访问50051-500053端口呢?

在微软社区上看到一条同样信息的描述

explorer一直在访问localhost的50051,50052,50053端口,请问有人知道这是在做什么吗?
最近偶尔,几个小时内,都会不断开启explorer进程,然后都在用tcp访问localhost的端口,先50051,不通就关闭,再开一个进程访问50052,再不通访问50053,然后又从50051开始,删除explorer进程、重启都没效果,只有几个小时后它才会停下来。 我再本机开了tcplistener,监听端口,读取访问的信息,我挑一些明文贴出来 PRI * HTTP/2.0 SM :authoritylocalhost:50052@:path2/fileExplorerPlugin.FileService/ConfigNotification user-agent4grpc-c++/1.19.1 grpc-c/7.0.0 (windows; chttp2; gold)@grpc-accept-encodingidentity,deflate,gzip@accept-encoding 请问有人知道这是在做什么吗?

底下的回答是让用户执行干净启动,于是我按照要求,禁用了各种非必要服务,关闭自启,重启后问题依旧。

没办法硬着头皮继续按照前面的排查,搜索引擎出现的最多结果是企业微信,但是我已经卸载了问题还在,到底是谁在作妖?那是不是没有卸载干净,抱着试试看的想法,打算删除企业微信的日志文件夹。

神奇的事情发生了,真的删不掉。这我的暴脾气了就来了。上资源管理器一看,果然这个文件夹被explorer.exe 占用了。直觉告诉我,真相就要出来了。

于是按图索骥,根据文章内容,到企业微信社区下载官方提供的反注册插件工具。
1.反注册wedriveplugin插件(双击uninstall_plugins\uninstall_wxdrive.bat) https://share.weiyun.com/0ZTrbRlD
当我满怀欣喜的点开执行时,我内心的冲动再也无法压制,企业微信–垃圾国产软件。

但这并不妨碍我删除他,于是打开火绒的强制清理工具,没有什么问题是不能通过暴力解决的。

删掉,重启explorer.exe。再看监控后台,很清爽了,再也没有异常连接了。世界安静,仿佛电脑运行速度都变快了。

最后总结下:算了,不骂同行了,也许我写的代码也被别人骂过,积点德。给腾讯比个心。真棒,浪费了我将近2天的时间。也算在压抑的疫情氛围下找点乐子。

2022-02-22 作者:菜鸟DJ 0
信文随笔

【油猴脚本】关闭CSDN中占用资源过高的雪点动画

以前用老笔记本访问csdn某些页面时,机器就很卡,一看任务管理器gpu占用很高。mac因为垃圾集显所以特别明显。
排查下来发现是网页里css加载某些动画,那么我们通过油猴脚本来删除。

// ==FeHelperMonkey==
// @reminder        请不要删除这部分代码注释,这是FeHelper油猴脚本能正常工作的基本条件!当然,你可以按需修改这里的内容!
// @id              mf_1645510946779
// @name            csdn移除雪点动画
// @url-pattern     https://blog.csdn.net/*
// @enable          true
// @require-js      
// @auto-refresh    0
// @updated         2022-02-22 14:59:35
// ==/FeHelperMonkey==


// 在这里,可以随便写你的代码,并且,你的代码中
// 1. 可以进行页面上的所有DOM操作
// 2. 可以访问页面上原本已挂载的所有Js变量,比如页面上已经有了jQuery,你可以直接使用
// 3. 可以依赖注入一个第三方js脚本,然后在你的代码中直接使用,如:依赖jQuery后直接使用
// 4. 好了,你的代码可以这样写:

(() => {
  let sources = document.getElementsByTagName('link')
  let i=0;
  for (let bb of sources) {
    if(bb.href.search("whitemove") > 0){
        console.log("删除浪费机器性能的动画!"+bb.href);
        document.getElementsByTagName('head')[i].removeChild(bb)
        i++
    }
  }
})();


删除动画前资源占用:

删除动画前资源占用

删除动画后资源占用:

删除动画后资源占用

2020-12-21 作者:菜鸟DJ 0
信文随笔

冬至快乐,“菜鸟公园”博客迁移后第一篇

今天是冬至,祝大家冬至快乐,吃饺子,圆圆满满。

博客已经顺利迁移完成了,再也不用忍受阿里云的各种限制了,没有crontab,网速又慢。以后就用 https://sophie520.top 这个网址了。 sophie520.top 这个网址因为需要备案的原因,所以不指向新博客地址了,避免不必要的麻烦。

关于迁移

其实很早就想迁移博客,只不过因为想用微信公众号的开发者,就一直放在了阿里云的虚拟主机上。但是最近接二连三的宕机,让我对阿里云的服务很不满意,提了技术工单,都是把责任推卸给我,说我博客的 wp-cron 导致了cpu 100%宕机了。我承认这个是耗性能,但是阿里的那个cpu监控,只有0%和100%的跳跃让我笑了。咱也不是不会整是不是,这不就有了迁移这件事了。虽然迁移到了境外,但是从用户角度来看响应速度似乎比阿里云杭州机房还快。这就不得不怀疑阿里云在高价卖垃圾。

记录下迁移的步骤

  1. 从阿里提取网站代码备份,数据库备份
  2. 开设新服务器,推荐Ubuntu,安装mariadb,nginx,php,fpm,并调试好。环境搭建可以参考这篇文章

我一般创建下面的文件调试看信息。

<?php
echo phpinfo();
  1. 创建网站的工作目录,并设置拥有者为 www-data ,并且记住设置该目录的上级目录是否能被 www-data用户读取。这个问题一般是导致 403 报错的根源。

  2. 修改 wp-config.php文件里的DB配置,打开同文件内的 WP_DEBUG 调试开关。

  3. 导入备份的数据库,更新表 wp_options ,如下所示,网址改为新网址,不然网站的跳转会有问题
    wp_options

  4. 测试下邮件能否正常发送

  5. 批量修改发表的文章里面的图片地址,主题的图片地址,或者手动修改也行。

关于网站SSL证书

在阿里云申请免费的DV证书,每个账号能申请20张,具体请 Google,签发只需要几分钟。
nginx 里的配置可以参考阿里云给的帮助。

server {
    ···
    listen 443 ssl default_server;
    listen [::]:443 ssl default_server;

    ssl_certificate xxxx.pem;  #需要将xxxx.pem替换成已上传的证书文件的名称。
    ssl_certificate_key xxxx.key; #需要将xxxx.key替换成已上传的证书密钥文件的名称。
    ssl_session_timeout 5m;
    ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
    # 表示使用的加密套件的类型。
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2; #表示使用的TLS协议的类型。
    ssl_prefer_server_ciphers on;
    ···
}

本站点也增加了80端口的跳转,所以大家输入sophie520.top 可以自动跳转到安全的 https 站点。

关于公众号

以后公众号就不提供快递,翻译等查询了,因为国内备案的机器我已经清退了。境外服务器无法接入微信开发。反正公众号也没有多少人看,逃)

wordpress 迁移 阿里云

2020-11-30 作者:菜鸟DJ 0
工具分享, 编程技能

让浏览器自动移除知乎的登录弹窗(已更新)

由于某些原因,我注销了知乎的账号。但是在网页的搜索中,会出现一些知乎的内容。当我点进去会发现,知乎会强制登录才能查看内容。以前会有一个关闭的按钮,最近关闭的按钮被去除了。

作为程序员,肯定不希望阅读体验这么差,所以用 油猴工具 制作了如下脚本,自动移除弹窗,并恢复页面的滚动条。

// ==FeHelperMonkey==
// @reminder        请不要删除这部分代码注释,这是FeHelper油猴脚本能正常工作的基本条件!当然,你可以按需修改这里的内容!
// @id              mf_1606719966367
// @name            关闭知乎登录
// @url-pattern     https://*.zhihu.com/question/*
// @enable          true
// @require-js      
// @auto-refresh    0
// @updated         2020-12-01 10:03:30
// ==/FeHelperMonkey==


// 在这里,可以随便写你的代码,并且,你的代码中
// 1. 可以进行页面上的所有DOM操作
// 2. 可以访问页面上原本已挂载的所有Js变量,比如页面上已经有了jQuery,你可以直接使用
// 3. 可以依赖注入一个第三方js脚本,然后在你的代码中直接使用,如:依赖jQuery后直接使用
// 4. 好了,你的代码可以这样写:
var toast = (content,time) => {
    return new Promise((resolve,reject) => {
      let elAlertMsg = document.querySelector("#fehelper_alertmsg");
      if (!elAlertMsg) {
          let elWrapper = document.createElement('div');
          elWrapper.innerHTML = '<div id="fehelper_alertmsg" width="100%" style="position:absolute;top:10px;left:50%;-webkit-transform:translateX(-50%);z-index:100">' +
              '<tb style="background:red;display:inline-block;color:white;text-align:center;' +
              'padding:10px 10px;margin:0 auto;font-size:20px;border-radius:8px;">' + content + '</tb></div>';
          elAlertMsg = elWrapper.childNodes[0];

        document.body.appendChild(elAlertMsg);
        // elAlertMsg = document.getElementById("fehelper_alertmsg");
        // elAlertMsg.style.left=(document.body.clientWidth-elAlertMsg.offsetWidth)/2+"px";
      } else {
          elAlertMsg.querySelector('p').innerHTML = content;
          elAlertMsg.style.display = 'block';
      }

        window.setTimeout(function () {
          elAlertMsg.style.display = 'none';
            resolve && resolve();
      }, time || 1000);
  });
};

(()=>{
  toast("【菜鸟公园】关闭知乎登录弹窗",2000).then(()=>{
    let a = document.getElementsByClassName('Modal-wrapper');
    for (i=0;i<a.length;i++){
      a[i].parentNode.removeChild(a[i]);
    }
    document.documentElement.style.overflow='visible';
  });
})();

js zhihu 弹窗 油猴 登录 知乎 脚本

2020-11-11 作者:菜鸟DJ 0
工具分享, 编程技能

如何在Windows中体验极致的Linux开发环境

1. 背景

相当长的一段时间,我的工作平台都是MAC,清爽干净的界面,没有广告烦扰,方便的快捷键,好用的触摸板等等。但是换了工作之后,公司配备的是一台Windows台式机,虽然可以带自己的笔记本工作,但是总有些不便。于是一直在折腾Windows下的Linux开发环境。

之前一直是用 vm 搭建,也没有觉得不方便的地方。但是最近一直被安利 wsl2 。于是就安装试用了一番。发现在我的开发环境下完全可以抛弃 vm 了。那么对比 vm 有哪些优势劣势呢。

优势

  • 不用每次点击启动vm,然后点开机或者恢复。直接在终端中选择打开。
  • 不用配置网络,实际上wsl2 你也没有机会配置。wsl2深度融合Windows环境,在wsl启动的服务,在Windows 可以直接 localhost:port 访问
  • 挂载了本地磁盘,虽然vm也可以共享,但是没有这个方便。

劣势

  • 只有Ubuntu可以选择
  • 没有systemd,需要自己些reload脚本
  • 启用hyper v之后,影响vm和模拟器运行

2. 安装WSL2

  1. 从启用或关闭 Windows 功能里勾选适用于 Linux 的 Windows 子系统和虚拟机平台,重启电脑
  2. 以管理员身份启动 powershell ,输入下面指令

    wsl --set-default-version 2

  3. 如果提示要升级内核,按照提示走
  4. 从 Microsoft Store 下载最新 Linux 分发版, 下载完后点击启动,安装
  5. [ 可选 ] 换源,使用阿里Ubuntu镜像。 换完之后执行sudo apt update
  6. [ 可选 ] 从 Microsoft Store 安装 Windows Terminal

3. 搭建开发环境

nginx,php,fpm,mariadb,redis,golang,openssh 等软件均可以通过 apt install 来安装。
通过 service xxx start|restart|stop 来控制状态

  • 特别说明
    mariadb安装完后需要配置root账号密码,参考文章
# 第一次设置密码
sudo mysql_secure_installation

# 控制台登录, 如果有报错,记得使用sudo
sudo mysql -u root -p

# 修改mysqld 绑定IP
sudo vim /etc/mysql/my.cnf
# 注释下面的语句
bind-address  = 127.0.0.1

# php连mysql需要安装扩展
sudo apt install php-mysql

# fastcgi listen字段,需要跟nginx.conf 对应
sudo vim /etc/php/7.4/fpm/pool.d/www.conf
  • Ubuntu20.04 apt install 的服务配置文件目录整理
服务 默认路径 默认配置文件名
nginx /etc/nginx/nginx.conf nginx.conf
maraiadb /etc/mysql/mariadb.conf.d/50-server.cnf my.conf
redis /etc/redis/redis.conf redis.conf
php-fpm /etc/php/7.4/fpm/php-fpm.conf
/etc/php/7.4/fpm/pool.d/www.conf
php-fpm.conf
php /etc/php/7.4/cli/php.ini php.ini
sshd /etc/ssh/ssh_config ssh_config

4. 总结唠嗑

关于wsl2的使用说明,建议阅读官方文档
在 windows 宿主机使用 localhost 就能登录wsl2,不要被国内博客误导!!! 前提是重新安装 openssh 服务。

最后两个安装步骤虽然是可选,但是强烈建议做完,能很大程度的提升使用体验。
换源的好处自然是加快包安装速度
使用 windows Terminal 时让我有点在 MAC 下工作的感觉。总结下有几点:
– 支持多标签页
– 能快捷进入wsl,下拉菜单中点选进入
– 界面重新设计,很清爽,有 Linux 终端的味道,离 MAC 还差点
– 支持 Ctrl C 复制,Ctrl V 粘贴,我很喜欢这个设定。并且 Ctrl C原本的中断功能不受影响

wsl 不支持 systemd ,所以不用折腾开机启动了。需要的服务建议通过 sudo service 服务启动,或者写一个 shell 脚本。

wsl把 windows 磁盘挂载在 /mnt/ 目录下,可以对该目录下文件进行读写操作。

配合 VS CODE 敲代码,只需要安装一个Remote - WSL插件。在 远程资源管理器里选择 WSL Targets 一键连接。 本地开发,即在服务器上开发。NICE

测试过 php 项目 和 golang 的 web 项目,目前没有发现任何功能上的问题。

5. 目前遇到的?坑?

由于我装 ohmyzsh 了,它在git的目录会有额外的操作,所以进入到挂载在 /mnt/ 下面的目录时,会有一段时间读取过程,耗时较长。不用 ohmyzsh 不会有问题。

linux macos terminal ubuntu vm windows wsl

2020-09-05 作者:菜鸟DJ 0
信文随笔, 工具分享

一个方便的数据库操作shell脚本

用法说明

这个脚本可以方便的备份和恢复数据库,而且通过show参数可以用来查看该实例中有多少个数据库。
唯一需要手动操作的是到脚本里配置账号密码。账号密码放在脚本的目的是为了避免每次输入。

导出文件格式是tar.gz。导入的文件格式是zip。这部分跟我的习惯有关系,我备份的数据库都会在本地进行处理压缩成zip上传,就是为了防止没有经过处理的数据库直接拿去导入。

#!/bin/bash

# 这是一个自动化导出MySQL数据库的脚本

# 修改此处
user="root"
passwd="123456"
port=3306
host="127.0.0.1"
dblist=(
"test"
)
root=`pwd`"/"
function printUsage {
    echo "Usage:"
    echo "$0 [-t dump|import|show] [-f file]"
    echo "导出/导入数据库脚本 v1.1"
    echo "导出的sql以数据库命名。"
    echo "导入的文件同样是提取sql文件名!"
    echo "show 参数可以打印数据库名,用于替换dblist"
    echo "dump文件是tar.gz的压缩包,import的文件是zip的压缩包"
}
function printParaErr {
    echo "参数错误!"
}

function printFileNotExist {
    echo "文件不存在!"
}

function printFileNotSupport {
    echo "仅支持压缩文件!(zip)"
}

function cleanOutDir {
    if [ -d $outDir ]; then 
        echo "清理临时目录:" $outDir
        rm -rf $outDir
    fi
}

function addNote {
    echo "是否添加备注文件?[回车跳过]"
    read note

    if [ ${#note} -gt 1 ];then 
        cd $root$outDir
        echo $note > note.txt
    fi
}

if [ $# == 0 ]; then 
    printUsage
    exit 0
fi

GETOPTOUT=`getopt t:f: "$@"`
    set -- $GETOPTOUT
    while [ -n "$1" ]
    do
    case $1 in
        -t)
            type=$2
            shift
            ;;
        -f)
            inputfile=$2
            shift
            ;;
        --)
            shift
            break
            ;;
        *)
            printParaErr
            printUsage;
            exit 1;
            ;;
    esac
    shift
    done
if [ $type == 'dump' ]; then
    echo "目标数据库为 $user@$host:$port"
elif [ $type == 'import' ]; then
    if [ ! -f "$inputfile" ]; then
        printFileNotExist
        printUsage
        exit 0
    fi

    ext_name="${inputfile##*.}"

    if [ $ext_name != 'zip' ]; then
        printFileNotSupport
        printUsage
        exit 0
    fi


    echo "导入源数据为: $inputfile"
    echo "目标数据库为: $user@$host:$port"
elif [ $type == 'show' ]; then
    echo "当前实例存在的数据库:(已排除系统数据库)"
else
    printParaErr
    printUsage;
    exit 1;
fi

# echo "请输入数据库密码,按回车键结束"
# stty -echo # 设置输入字符不回显
# read passwd
# stty echo  # 取消不回显状态

runTime=`date '+%Y%m%d%H%M'`
outDir="./sqlHandler_$runTime/"

cleanOutDir

if [ $type == 'dump' ]; then
    echo "创建导出目录:" $outDir
    mkdir -p $outDir

    for db_name in ${dblist[*]}; do
        cmd="mysqldump -h $host -u $user -P $port -p$passwd $db_name"
        echo $cmd | sed "s/-p$passwd/-p****/g";
        $cmd > "$outDir$db_name.sql";
    done
    cd $outDir
    tar cvzf "dbbak_$runTime.tar.gz" *
    rm -rf *.sql
    addNote
    echo "导出文件为:"
    echo $root$outDir"/"`ls|grep tar`|sed -e "s/\/\//\//g" -e "s/\/\.\//\//g"

elif [ $type == 'import' ]; then
    echo "创建临时目录:" $outDir
    mkdir -p $outDir
    unzip -d $outDir $inputfile
    files=$(ls $outDir)
    cd $outDir
    echo "mysql command:"
    for file in ${files[*]}; do
        db_name="${file%.*}"
        # ext_name="${file##*.}"
        cmd="mysql -h $host -u $user -P $port -p$passwd --default-character-set=utf8 $db_name"
        echo -e "\t"$cmd " < $file" | sed "s/-p$passwd/-p****/g";
        $cmd < $file
    done
    cd $root
    cleanOutDir
    # $cmd < $inputfile
elif [ $type == 'show' ]; then
    rm -rf $outDir
    cmd="mysql -h $host -u $user -P $port -p$passwd "
    $cmd -e "show databases;" |grep -v -E 'Database|mysql|information_schema|performance_schema'|sed -e 's/^/"/g' -e 's/$/"/g'
    # echo $result
fi

if [[ $? == 0 ]]; then
    echo "操作完成!";
else
    echo "┗━━ 操作失败!";
fi

bash MySQL mysqldump shell

2020-05-03 作者:菜鸟DJ 0
PHP

PHP中静态变量作用域浅谈

最近看代码,发现有个代码写的有意思,在函数内用static修饰局部变量。当时心想,难道是跟global一样,扩大作用域?又看到同一个类里面,两个方法都用static修饰了同样的变量,我明白了,事情肯定没有我想象的这么简单,所以我写了下面的这个方法来测试下。

<?php
class MyTest
{
    public static function func1($arg1)
    {
        static $result = [];
        $p = serialize($arg1);
        var_dump($p);
        if (isset($result[$p])) {
            return $result[$p];
        }
        $result[$p] = date('Y-m-d H:i:s') . " by func1 rand:".rand(0,100);
        return $result[$p];
    }
    public static function func2($arg1)
    {
        static $result = [];
        $p = serialize($arg1);
        var_dump($p);
        if (isset($result[$p])) {
            return $result[$p];
        }
        $result[$p] = date('Y-m-d H:i:s') . " by func2 rand:".rand(0,100);
        return $result[$p];
    }
}
$arg = ['1' => '2'];
var_dump(MyTest::func1($arg));
var_dump(MyTest::func2($arg));
var_dump(MyTest::func1($arg));
var_dump(MyTest::func2($arg));

这个输出应该是如何呢?大家不妨想一想。同样的static $result 结果会相同吗?

好了我们一起来看输出。

string(18) "a:1:{i:1;s:1:"2";}"
string(36) "2020-04-28 03:30:04 by func1 rand:45"
string(18) "a:1:{i:1;s:1:"2";}"
string(36) "2020-04-28 03:30:04 by func2 rand:40"
string(18) "a:1:{i:1;s:1:"2";}"
string(36) "2020-04-28 03:30:04 by func1 rand:45"
string(18) "a:1:{i:1;s:1:"2";}"
string(36) "2020-04-28 03:30:04 by func2 rand:40"

从上面可以看出,static $result的作用域还是自己的函数内。但是在类实例化的生命周期内,当函数返回结果时,其生命周期并没有释放。
那么我们可以利用这个特性来缓存函数操作的结果,而又不需要定义类的成员变量。

2020-03-28 作者:菜鸟DJ 0
工具分享

手机app https抓包步骤一揽

1. 工具准备

  • WireShark
    下载地址 开源工具,免费使用,支持WIN与OSX平台。
    Wireshark(前称Ethereal)是一个网络封包分析软件。网络封包分析软件的功能是撷取网络封包,并尽可能显示出最为详细的网络封包资料。Wireshark使用WinPCAP作为接口,直接与网卡进行数据报文交换。

  • Fiddler
    下载地址 开源工具,免费试用,支持WIN平台,OSX需要自行编译。
    Fiddler是一个http协议调试代理工具,它能够记录并检查所有你的电脑和互联网之间的http通讯,设置断点,查看所有的“进出”Fiddler的数据(指cookie,html,js,css等文件)。 Fiddler 要比其他的网络调试器要更加简单,因为它不仅仅暴露http通讯还提供了一个用户友好的格式。

2. 如何使用

http的抓包使用Fiddler 或者其他代理软件很直接的就可以完成。但是https的抓包因为经过了加密,所以并不能直接看到抓包的内容,只能看到密文。那么如何使用http来进行抓包呢?

设置界面-打开HTTPS抓包
设置界面-打开代理
设置完成后,关闭软件重新打开。条件允许的情况下最好是重启电脑。
然后在手机里输入网址 http://pc.ip:8080 看是否出现如下截图。出现表示fiddler设置正确。
手机安装证书
iOS只能下载该证书,要安装证书需要2个步骤。 安卓机暂不清楚。
1. 点设置-> 通用 -> 描述文件。 找到刚下载的“DO_NOT_TRUST_FiddlerRoot”点击安装
2. 点设置-> 通用 -> 关于本机 -> 证书信任设置。 点击完全信任。

然后打开浏览器,输入任意网址,能正常打开即表示完成。

3. 抓包结果

现在打开手机app,便可以看到fiddler里出现http和https的访问记录了。看下面的实例。

2020-02-27 作者:菜鸟DJ 0
PHP

记一下RabblitMQ的安装和RPC的工作模式

1. 什么是Rabbitmq

Rabbitmq 是一款由erlang开发的基于AMQP协议的消息队列。官网地址https://www.rabbitmq.com 有六种工作模式。详细的教程在本文就不再赘述,可以直接去官网阅读。

2. 安装RabbitMq

安装环境CentOS7,步骤如下:

  • 从源码安装
#下面是从源码master分支安装示例
git clone https://github.com/erlang/otp.git
cd otp
./otp_build autoconf
./configure
make
make install

安装完成之后,记得修改/etc/profile,设置erlang的路径

vim /etc/profile
export ERLANG="/usr/local/lib/erlang/bin/"
export PATH=/usr/local/php/bin:/usr/local/nginx/sbin:$PATH:$ERLANG

source /etc/profile
  • 安装socat
    sudo yum install socat
  • 下载Rabbitmq-server安装包
wget https://github.com/rabbitmq/rabbitmq-server/releases/download/v3.8.2/rabbitmq-server-3.8.2-1.el7.noarch.rpm
rpm -ivh --nodeps rabbitmq-server-3.8.2-1.el7.noarch.rpm

一定要注意加上--nodeps, 不然会提示erlang依赖版本问题

  • 启动服务端
rabbitmq-plugins list #查看组件是否正常显示
rabbitmq-plugins enable rabbitmq_management # 加载web管理组件
rabbitmq-server #启动服务端

在浏览器里输入http://localhost:15672,看后台是否出来,默认账号密码都是guest

3. RPC下如何工作

在上面的web页可以添加用户,由于默认的guest是不允许在外网访问,所以我们新增了yhw这个用户
从官网下载教程代码。到php目录下执行composer install。修改好配置之后我们启动rpc_server.php和rpc_client.php即可。
最后附上修改的测试代码。
rpc_server.php

<?php

require_once __DIR__ . '/vendor/autoload.php';
use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Message\AMQPMessage;

$connection = new AMQPStreamConnection('10.211.55.3', 5672, 'yhw', 'yhw');
$channel = $connection->channel();

$channel->queue_declare('rpc_queue', false, false, false, false);

function fib($n)
{
    if ($n == 0) {
        return 0;
    }
    if ($n == 1) {
        return 1;
    }
    return fib($n - 1) + fib($n - 2);
}

// 我增加的测试函数
function sayHello($n)
{
    return sprintf(
        "%s Hello gentleman, I am rabbitmq, working on RPC mode. You typed %d, the result is %d",
        date('Y-m-d H:i:s'),
        $n,
        fib($n)
    );
}

echo " [x] Awaiting RPC requests\n";
$callback = function ($req) {
    $n = intval($req->body);
    echo ' [.] fib(', $n, ")\n";

    $msg = new AMQPMessage(
        (string)sayHello($n),
        array('correlation_id' => $req->get('correlation_id'))
    );

    $req->delivery_info['channel']->basic_publish(
        $msg,
        '',
        $req->get('reply_to')
    );
    $req->delivery_info['channel']->basic_ack(
        $req->delivery_info['delivery_tag']
    );
};

$channel->basic_qos(null, 1, null);
$channel->basic_consume('rpc_queue', '', false, false, false, false, $callback);

while ($channel->is_consuming()) {
    $channel->wait();
}

$channel->close();
$connection->close();
?>

rpc_client.php

<?php

require_once __DIR__ . '/vendor/autoload.php';
use PhpAmqpLib\Connection\AMQPStreamConnection;
use PhpAmqpLib\Message\AMQPMessage;

class FibonacciRpcClient
{
    private $connection;
    private $channel;
    private $callback_queue;
    private $response;
    private $corr_id;

    public function __construct()
    {
        $this->connection = new AMQPStreamConnection(
            '10.211.55.3',
            5672,
            'yhw',
            'yhw'
        );
        $this->channel = $this->connection->channel();
        list($this->callback_queue, ,) = $this->channel->queue_declare(
            "",
            false,
            false,
            true,
            false
        );
        $this->channel->basic_consume(
            $this->callback_queue,
            '',
            false,
            true,
            false,
            false,
            array(
                $this,
                'onResponse'
            )
        );
    }

    public function onResponse($rep)
    {
        if ($rep->get('correlation_id') == $this->corr_id) {
            $this->response = $rep->body;
        }
    }

    public function call($n)
    {
        $this->response = null;
        $this->corr_id = uniqid();

        // 此处为调用参数,以及回复
        $msg = new AMQPMessage(
            (string) $n,
            array(
                'correlation_id' => $this->corr_id,
                'reply_to' => $this->callback_queue
            )
        );
        $this->channel->basic_publish($msg, '', 'rpc_queue');
        while (!$this->response) {
            $this->channel->wait();
        }
        return $this->response;
    }
}

$fibonacci_rpc = new FibonacciRpcClient();
$n = (int)$argv[1];
while(1){
    $response = $fibonacci_rpc->call($n);
    echo ' [.] Got ', $response, "\n";
    usleep(100);
}
?>

稍微改动下,客户端的代码,多起几个php脚本,看执行结果是否能回复正确。看下面截图结果完全正确。
运行结果

看看后台

2020-02-23 作者:菜鸟DJ 0
Golang, PHP, 信文随笔

聊一聊快排算法

曾经有一个人让我写下快排算法,我给他写出来了,然后就被Diss了,怎么申请这么多临时变量。来,各位看官一起看看本菜🐔的作业。各位看官也可以动手写一写。

快速排序的逻辑 — 来自百度百科

快速排序算法通过多次比较和交换来实现排序,其排序流程如下:
(1)首先设定一个分界值,通过该分界值将数组分成左右两部分。
(2)将大于或等于分界值的数据集中到数组右边,小于分界值的数据集中到数组的左边。此时,左边部分中各元素都小于或等于分界值,而右边部分中各元素都大于或等于分界值。
(3)然后,左边和右边的数据可以独立排序。对于左侧的数组数据,又可以取一个分界值,将该部分数据分成左右两部分,同样在左边放置较小值,右边放置较大值。右侧的数组数据也可以做类似处理。
(4)重复上述过程,可以看出,这是一个递归定义。通过递归将左侧部分排好序后,再递归排好右侧部分的顺序。当左、右两个部分各数据排序完成后,整个数组的排序也就完成了。

<?php

$input = [100, 23, 452, 234, 56223, 6234, 134, 51, 234];
$ret = quickSort($input);
printf("%s\n", json_encode($ret));


function quickSort($input)
{
    $len = count($input);
    if ($len <= 1) {
        return $input;
    }

    $temp = $input[0];
    $left = $right = [];
    for ($i = 1; $i < $len; $i++) {
        if ($temp >= $input[$i]) {
            $left[] = $input[$i];
        } else {
            $right[] = $input[$i];
        }
    }

    $left = quickSort($left);
    $right = quickSort($right);
    return array_merge($left, [$temp], $right);
}

基本上也是符合快速排序的标准,不过确实$left和$right这两个属于数组copy,会需要大量的内存空间的。但是既然说到利用了中间变量来存放数组,那么是否有别的方式呢?

答案肯定是有的了,既然不能用中间变量存数组,那么我可以使用交换的方式,因为反正都是比大小,我们通过一个临时变量将原数组的数据挖一个出来,然后再去比较,可以看下面的示例。

[100, 23, 452, 234, 56223, 6234, 134, 51, 234]
第一趟,我先取100出来,然后从右向左扫描,比他小的(51<100)放入他的坑,那么结果如下:
[---, 23, 452, 234, 56223, 6234, 134, 51, 234]
从左扫发现51,填入左边的坑。
[51, 23, 452, 234, 56223, 6234, 134, ---, 234]
然后从51的下个值往右扫,发现452>100,那么把452填入上面挖的坑
[51, 23, ---, 234, 56223, 6234, 134, 452, 234]
然后从452往左扫描,发现没有小于100的。那么100 就只能去填坑了。自此我们做了一个循环。
[51, 23, 100 234, 56223, 6234, 134, 452, 234]

那么下一个循环我们怎么开始呢?因为100的右边肯定是大于它的,100的左边肯定是小于它的。PS.这不是废话吗?上面的快排就是这样要求的。
我们就从51,到100 这三个元素之间继续排序。
[51,23,100]
[--,23,100]
[23,--,100]
[23,50,100]
最左边的完成了,那么我们来看看最右边的
[234,56223,6234, 134, 452, 234]
.... 各位看官自己实现下看看?

好了直接上代码

<?php 
function quickSort(&$input, $low, $high)
{
    if ($high <= $low) return;
    $i = $low;
    $j = $high;
    $key = $input[$low];
    while ($i < $j) {
        while ($i < $j && $input[$j] >= $key) {
            $j--;
        }
        if ($i < $j) {
            $input[$i] = $input[$j];
            $i++;
        }
        while ($i < $j && $input[$i] < $key) {
            $i++;
        }
        if ($i < $j) {
            $input[$j] = $input[$i];
            $j--;
        }
        // printf("find i(%d),j(%d)\n", $i, $j);

    }

    $input[$i] = $key;
    quickSort($input, $low, $i - 1);
    quickSort($input, $i + 1, $high);
    // return $input;
}

为了节省递归参数赋值,我们传了引用进去,更加节省内存空间。那么具体效果如何呢,我们来看看跟内置函数sort的对比结果。

排序个数:100000
内置排序耗时:27.215004 ms
手写排序耗时:104.742050 ms
结果抽查 1

排序个数:200000
内置排序耗时:61.784983 ms
手写排序耗时:241.871119 ms
结果抽查 1

排序个数:300000
内置排序耗时:87.085009 ms
手写排序耗时:448.505878 ms
结果抽查 1

排序个数:400000
内置排序耗时:120.175838 ms
手写排序耗时:618.201971 ms
结果抽查 1

排序个数:500000
内置排序耗时:149.783850 ms
手写排序耗时:796.765804 ms
结果抽查 1

排序个数:600000
内置排序耗时:182.029963 ms
手写排序耗时:1063.417196 ms
结果抽查 1

排序个数:700000
内置排序耗时:209.767103 ms
手写排序耗时:1333.762884 ms
结果抽查 1

排序个数:800000
内置排序耗时:241.870165 ms
手写排序耗时:1633.098841 ms
结果抽查 1

排序个数:900000
内置排序耗时:272.398949 ms
手写排序耗时:1975.782871 ms
结果抽查 1

排序个数:1000000
内置排序耗时:299.492121 ms
手写排序耗时:2303.519964 ms
结果抽查 1

可以看出虽然我们采用了传引用的方法,在大量的数据排序的时候,自己写的还是没有内置的厉害。基本上内置的算法只需要自己写的1/5的时间。
那么是否别的语言也是这样的呢?我们来看看golang吧。

排序个数: 100000
内置排序耗时: 16.072056ms
手写排序耗时: 6.95578ms
结果抽查: true

排序个数: 200000
内置排序耗时: 31.831613ms
手写排序耗时: 14.822814ms
结果抽查: true

排序个数: 300000
内置排序耗时: 46.872946ms
手写排序耗时: 24.190585ms
结果抽查: true

排序个数: 400000
内置排序耗时: 66.008501ms
手写排序耗时: 33.844555ms
结果抽查: true

排序个数: 500000
内置排序耗时: 77.824994ms
手写排序耗时: 43.05986ms
结果抽查: true

排序个数: 600000
内置排序耗时: 106.42095ms
手写排序耗时: 53.728681ms
结果抽查: true

排序个数: 700000
内置排序耗时: 117.377987ms
手写排序耗时: 65.855924ms
结果抽查: true

排序个数: 800000
内置排序耗时: 125.352682ms
手写排序耗时: 80.507389ms
结果抽查: true

排序个数: 900000
内置排序耗时: 140.563745ms
手写排序耗时: 92.550294ms
结果抽查: true

排序个数: 1000000
内置排序耗时: 162.15016ms
手写排序耗时: 100.330999ms
结果抽查: true

可以看到golang手写的居然比内置的快。100万个int排序,golang内置需要162ms,手写的居然只要100ms,php内置需要299ms,而手写居然需要2300多ms。
看来php的执行效率确实低,不过惊讶的是php内置函数排序居然只比golang慢一倍。

电脑配置

CPU:2.8 GHz 双核Intel Core i5 
MEM:8 GB 1600 MHz DDR3
PHP version:7.4.2
Golang version :go1.13.7

最后贴上golang代码

package main

import (
    "fmt"
    "math/rand"
    "sort"
    "time"
)

func quickSortCustom(nums *[]int, start int, end int) {
    // 起点和终点重合的时候,退出
    if start >= end {
        return
    }
    i, j := start, end
    //左节点的坑挖出来,备用
    mid := (*nums)[start]
    for {
        // 左节点位移到跟右节点重合时退出for循环
        if i >= j {
            break
        }

        // 右节点开始向左查找,直到比基准值小
        for {

            if j > i && (*nums)[j] >= mid {
                j--
            } else {
                break
            }
        }
        // 把右节点的坑,填入左节点。现在右节点j空出来了
        if i < j {
            (*nums)[i] = (*nums)[j]
            i++
        }

        // 左节点开始向右寻找,直到找到比基准值大的
        for {
            if j > i && (*nums)[i] < mid {
                i++
            } else {
                break
            }
        }
        //把左节点的值填入右节点的坑,(上面的右节点j是空的没有变过)。此时左节点i空出来了
        if i < j {
            (*nums)[j] = (*nums)[i]
            j--
        }

    }
    // 把最开始挖出来的坑放到新坑里面
    (*nums)[i] = mid
    quickSortCustom(nums, start, i-1)
    quickSortCustom(nums, i+1, end)
}

type IntSlice []int

func (s IntSlice) Less(i, j int) bool { return s[i] < s[j] }
func (s IntSlice) Len() int           { return len(s) }
func (s IntSlice) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }

func main() {
    startTime := time.Now()
    for i := 100000; i <= 1000000; i += 100000 {
        numsIn := make(IntSlice, 0)
        numsMy := make([]int, 0)
        for n := 0; n < i; n++ {
            //rand.Seed(int64(n))
            x := rand.Intn(10000)
            numsIn = append(numsIn, x)
            numsMy = append(numsMy, x)

        }

        l := len(numsMy)
        //fmt.Println("原始:", numsMy, "排序个数:", l)
        fmt.Println("排序个数:", l)

        // ---------------- 内置排序 开始----------------
        startTime = time.Now()
        sort.Ints(numsIn)
        cost := time.Since(startTime)
        fmt.Println("内置排序耗时:", cost)
        // ---------------- 内置排序 结束----------------

        // ---------------- 手写排序 开始----------------
        startTime = time.Now()
        quickSortCustom(&numsMy, 0, l-1)
        cost = time.Since(startTime)
        fmt.Println("手写排序耗时:", cost)
        // ---------------- 手写排序 结束----------------

        fmt.Println("结果抽查:", numsMy[l/2] == numsIn[l/2])

        //fmt.Println("内置:", numsIn)
        //fmt.Println("手写:", numsMy)

        fmt.Println(" ")

    }

    //nums := []int{8081, 7887, 1847, 4059, 2081, 1318, 4425, 2540, 456, 3300}
    //fmt.Println("原始的数据:", nums)
    //quickSortCustom(&nums, 0, len(nums)-1)
    //fmt.Println("自己排序后:", nums)
    //
    //nums2 := IntSlice{8081, 7887, 1847, 4059, 2081, 1318, 4425, 2540, 456, 3300}
    ////fmt.Println("排序前:",nums2)
    //sort.Stable(nums2)
    //fmt.Println("内置排序后:", nums2)
}

文章分页

1 2 下一页
10/17

天气

分类目录

热门文章

记一次和流氓软件战斗的过程0 comments
手机app https抓包步骤一揽0 comments
记一下RabblitMQ的安装和RPC的工作模式0 comments
聊一聊快排算法0 comments
MAC & WIN 平台效率工具清单0 comments
你真的会用MySQL里的max函数吗?0 comments
MySQL 分组之后如何取Top(N)?0 comments
B站代码解读 — LRUCache0 comments
解搜索二维矩阵题0 comments
解一道字符串变化题0 comments

微信公众号:菜鸟公园

微信公众号
微信公众号:菜鸟公园
隐私政策