编程

关于多线程与多进程的区别此处就不再赘述了。
Python3中已经具备了非常完善的多线程与多进程的相关库,可以非常容易的实现程序多进程与多线程的功能。

示例代码如下:

多线程示例

multithread.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

import os
import time
import threading


def test_proc(name):
print( "Run child process %s(%s)" % (name,os.getpid()) )
time.sleep(10)


class MultiThread( threading.Thread ):

def __init__(self,thread_name):
threading.Thread.__init__(self)
self.thread_name = thread_name

def run(self):
test_proc("test")


threads = []
for i in range(1,10):
thread = MultiThread( "Thread-%s" % i )
thread.start()
threads.append( thread )

for t in threads:
t.join()

运行结果:

多进程示例

multiprocess.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

import os
import time
import multiprocessing


def test_proc(name):
print( "Run child process %s(%s)" % (name,os.getpid()) )
time.sleep(10)

if __name__=="__main__":
print("Process start %s" % os.getpid())

processes = []

for i in range( 0, 10):
p=multiprocessing.Process( target=test_proc, args=("Process-%s" % i,) )
p.start()
processes.append(p)


for p in processes:
p.join()

print( "Main process end.")

运行结果:

使用aapt工具获取apk的信息,可以使用

1
aapt dump badging xxx.apk

如果没有aapt,使用apt安装:

1
apt-get install aapt

写个脚本批量获取

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#!/bin/bash 

target=$1
if [ -d $target ]
then
for apk in `ls $target/*.apk`
do
app_name=`aapt dump badging $apk | grep 'application: label' | awk -F "'" '{print $2}'`
echo $apk $app_name
done
elif [ ${target#*.} == "apk" ]
then
app_name=`aapt dump badging $target | grep 'application: label' | awk -F "'" '{print $2}'`
echo $target $app_name
else
echo $target "nOt aN aPk fiLe"
fi

脚本下载链接:

get_apk_name

前言

随着技术的发展,近年很多的网站、移动应用程序、微信小程序等等,采用前后端分离、使用JSON API数据传递这种方式来设计和开发。如此,前端程序可以保持独立、并且相对来说比较完整,后端程序逻辑复杂、性能强劲。前端可以有丰富的对数据的展现方式(图表、动画等等),后端也只需要完善相应的对模型的控制,同时输出一份前端所需要的数据,采用Ajax+JSON方式传递,从而让前后端的开发相对而言都更为轻松,在结构合理、技术完备的情况下,工程层面也能实现较大程度的规模上的突破。

Rails作为一种流行的MVC框架,本身在API的开发上已经有了很成熟的配套设施了。Rails的模板支持.json.jbuilder形式的JSON数据渲染,配合jbuilder从模型对象数组直接创建JSON数据,在开发上有着无与伦比的便利。在此之前,如果使用php开发程序,从数组创建JSON,需要先整理好数组,再json_encode(Array)进行输出,很是麻烦。当然身为PHP程序员的你可能要说,PHP也有很强大的API构建框架,可以很方便的构建出健壮的API,是的,我承认有这些框架的存在,只是限于本人的水平和喜好,在PHP开发方面并没有走的那么深远,也就不熟悉其中的一些高级操作了。如果有兴趣,也可以发邮件就这方面进行一些探讨。

近期由于一个项目的需要,需要从已有的Rails应用中开辟出一个新的独立接口,供客户端程序调用,因此学习了一下Rails API的构建方法,也顺便留下此文,作为记录。关于Rails API的构建,我参考了这篇文章 https://blog.csdn.net/li_001/article/details/65937664

以下就是如何使用Rails构建JSON API

我当前采用的环境是 Ruby 2.4.1 + Rails 5.2.0

配置控制器

首先假设我们的应用已经创建好了,并且建立一个Article模型,包含两个字段,title和content,运行迁移并创建种子数据。

此时进入项目根目录,新建一个控制器:

1
rails g controller api/v1/base --no-assets

这个控制器的代码就会位于app/controllers/api/v1/base_controller.rb,我们需要在其中完善一些权限有关的配置。

由于Rails默认的安全属性,以及我们如果之前自定义了一些控制器中的过滤方法,我们需要在该控制器中跳过它,例如我们首先禁用rails自带的CSRF 保护和CSRF token的输出,以及去除掉返回包中的set-cookies头,由于我的应用还使用了devise作为用户认证的模块,所以还要在此禁用掉authenticate_user方法。
完整的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Api::V1::BaseController < ApplicationController
# disable the CSRF token
protect_from_forgery with: :null_session

# disable cookies (no set-cookies header in response)
before_action :destroy_session

# disable the CSRF token
skip_before_action :verify_authenticity_token

# skip devise user authentication
skip_before_action :authenticate_user!

def destroy_session
request.session_options[:skip] = true
end
end

创建好base控制器以后,我们需要在这个控制器的基础上派生出一些新的控制器,这里我们新建一个articles控制器

1
rails g controller api/v1/articles --no-assets

此时除了会生成控制器代码以外,还会在app/views/api/v1目录下创建articles目录,作为模板存放的目录。

articles控制器的代码位于app/controllers/api/v1/users_controller.rb,内容如下

先在其中定义一个show方法:

1
2
3
4
5
class Api::V1::ArticlesController < Api::V1::BaseController
def show
@article = Article.find(params[:id])
end
end

配置路由

接下来我们对路由config/routes.rb进行配置

1
2
3
4
5
namespace :api do
namespace :v1 do
resources :articles
end
end

配置视图

articles控制器的视图代码位于app/views/api/v1/articles/,我们在其中建立show.json.jbuilder文件,内容如下:

1
2
3
json.article do
json.(@article, :id, :title, :content)
end

上面这段代码,是jbuilder建立json的语句代码,至于jbuilder的用法,可以参考这篇文章http://ohcoder.com/blog/2015/04/19/jbuilder/

访问接口

启动Rails程序,访问/api/v1/articles/1.json,即可看到接口输出的JSON数据。

接口通信

除了从接口获取JSON数据以外,我们还需要向接口POST JSON数据,并希望接口实现数据的解析和保存。
首先像往常一样,需要在控制器中创建create方法,用于新建数据:

1
2
3
def create
@host = Host.create(article_params)
end

呵呵,一行代码,是的,就这么简单。
而article_params,则是个私有方法,大概需要这样实现:

1
2
3
def article_params
params.require(:article).permit(:title, :content)
end

在客户端(或网页中)向该接口发送数据,地址是/api/v1/articles

发送的数据类似下面这样:

1
2
3
4
5
6
{
"article":{
"title":"test",
"content":"a test article from client"
}
}

直接发送这条数据可能会出错,因为在请求的时候需要带上json格式描述

1
2
Content-Type: application/json
Accept: application/json

完整的POST请求,参考下:

1
2
3
4
5
6
7
8
9
10
11
POST /api/v1/articles HTTP/1.1
Host: localhost:3000
Content-Type: application/json
Accept: application/json

{
"article":{
"title":"test",
"content":"a test article from client"
}
}

简介

Devise是Rails中一个功能强大、逻辑复杂的用于实现站点用户管理和登录的组件。鉴于Ruby之不重复造轮子的精神思想,Devise是值得去深入研究学习一下的。由于Devise本身的复杂性,这里对搭建的过程做一个记录,也借此分享一下基于Devise实现最基本的站点用户管理和登录的过程。

环境准备

需要在机器上安装Ruby和Rails。
本次编程环境:

  • Debian 9(Kernel 4.9.0-6-amd64)
  • ruby-2.4.1
  • Rails 5.2.0

开始

新建项目

首先新建一个Rails项目TestSite,创建Post scaffold,包含title和body两个字段

1
2
rails new TestSite
rails g scaffold Post title:string body:string

安装Devise

接着在Gemfile中添加devise

1
gem 'devise'

在项目中执行bundle,以及执行devise:install

1
2
bundle
rails generate devise:install

由于我们暂时只在本地测试,因此修改config/environments/development.rb文件,在其中加入mailer配置:

1
config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }

生成模型

指定Devise将要运行在哪个模型上,这里使用user作为模型,那么运行:

1
rails generate devise User

下一步,就是运行迁移:

1
rails db:migrate

控制器过滤

如果希望在应用运行之前校验用户身份,在ApplicationController中加入以下过滤器:

1
before_action :authenticate_user!

指定路由:

1
root to: 'posts#index'

添加注销功能

在Application的首页,加上用户注销的链接:

1
<%= link_to "Logout", destroy_user_session_path, method: "DELETE"  if current_user %>

配置视图

如果想要自定义登陆界面的视图,则运行以下命令:

1
rails g devise:views users

这里后面带模型名称,就会创建在这个模型范围内的视图(建议这样做,便于以后拓展多重用户身份模型)

此时就可以在相应的视图中自定义登录、注册、重置密码等相应的界面了。

配置控制器

生成控制器就和生成视图的流程是类似的,运行:

1
rails generate devise:controllers users

这样控制器就创建好了。

控制器这一段是值得好好说道说道的。
首先观察下控制器,控制器是可以追加功能的,也可以覆盖原来的方法,不过不推荐这样做,因为从目前经验来看devise自带的控制器已经足够健壮了。但是有时候,我们需要在原有的基础上新增一些功能,例如记录登录日志、增加一点自定义认证方式等等。这里简单介绍下如何在控制器中新增功能。
上一步操作,为我们生成了以下控制器:

1
2
3
4
5
6
app/controllers/users/confirmations_controller.rb
app/controllers/users/passwords_controller.rb
app/controllers/users/registrations_controller.rb
app/controllers/users/sessions_controller.rb
app/controllers/users/unlocks_controller.rb
app/controllers/users/omniauth_callbacks_controller.rb

这里以登录为例,如果我们想要改写登录功能,首先我们要在路由中改写我们要复写的控制器路由:

routes.rb中:

1
2
3
4
5
6
7
8
9
10
11
Rails.application.routes.draw do
#devise_for :users
resources :posts
root to: 'posts#index'

devise_for :users, controllers: {
# 这一行定义了有关sessions的控制选项,交由我们即将复写的sessions控制器处理。
sessions: 'users/sessions'
}

end

接着修改app/controllers/users/sessions_controller.rb,这里我们简单实现一个功能,当用户在前台登陆时,在后台的console中输出用户的登录信息。复写create方法:

1
2
3
4
5
6
7
# POST /resource/sign_in
def create
super
puts "="*64
puts resource.email
puts "="*64
end

尝试在前台登录,控制台输出了我们想要的信息:

待续

内核源码树

arch        特定体系结构的源码
block        Crypto API
crypto        内核源码文档
drivers        设备驱动程序
firmware    
fs        VFS和各种文件系统
include        内核头文件
init        内核引导和初始化
ipc        进程间通信代码
kernel        像调度程序这样的核心子系统
lib        通用内核函数
Makefile    
Makefile.common
mm        内存管理子系统和VM
Module.symvers
net        网络子系统
samples
scripts        编译内核所用的脚本
security    Linux安全模块
sound        语音子系统
System.map
tools
usr        早期用户空间代码
virt

编译内核

配置内核(不同的选项)

make config
make menuconfig
make xconfig
make gconfig

创建默认配置

make defconfig
make oldconfig

编译

make

记录编译信息

make >../log.txt

忽略编译信息

make >/dev/null

衍生多个编译作业

make -j[任务数量]

如双核处理器上,每个处理器衍生两个作业

make -j4

安装内核

把arch/i386/boot/bzImage拷贝到/boot
依照vmlinuz-version来命名
编辑/boot/grub/grub.conf文件,为新内核建立新的启动项
使用LILO的系统则编辑/etc/lilo.conf,然后运行lilo

安装模块

make modules_install

内核开发的特点

  1. 没有libc库

大部分常用的C库函数在内核中都已经得到了实现

  1. GNU C

内联函数

把对时间要求比较高而本身长度又比较短的函数定义成内联函数

1
static inline void test(unsigned long tail_size)

内联函数必须在使用前就定义好,一般在头文件或者文件头中定义内联函数。

内联汇编

分支声明(为了优化)

1
2
3
4
5
6
7
8
9
likely()
unlikely()
if(unlikely(foo){
/*****/
}

if (likely(foo)){
/****/
}
  1. 没有内存保护机制
  2. 不要轻易在内核中使用浮点数
  3. 内核空间具有容积小而固定的栈
  4. 同步和并发
  5. 可移植性

进程管理

进程是处于执行期的程序以及它所包含的资源的总称

  1. 进程描述符及任务结构
  • 内核把进程存放在任务队列中。任务队列是各双向循环链表,链表中的每一项都是类型为task_struct,称为进程描述符的结构,定义在<linux/sched.h>文件中。

  • 进程描述符中包含一个具体进程的所有信息

  • task_struct在32位机器上有1.7k字节,其中包含的数据能完整的描述一个正在执行的程序。(打开的文件,进程的地址空间,挂起的信号,进程的状态还有其他更多信息)

  1. 分配进程描述符

通过slab分配器分配task_struct结构

  1. 进程描述符的存放

内核通过一个唯一的进程标识值或PID类标识每个进程,PID最大默认值为32768(short int的最大值),可以修改/proc/sys/kernle/pid_max来提高上限。

  1. 进程状态

进程描述符中的state域描述了进程的当前状态,系统中每个进程都必须处于五种状态中的一种。

  • TASK_RUNNING(运行)
  • TASK_INTERRUPTIBLE(可中断)
  • TASK_UNINTERRUPTIBLE(不可中断)
  • TASK_ZOMBIE(僵死)
  • TASK_STOPPED(停止)
  1. 设置当前进程状态
1
2
3
set_task_state(task,state);
/*将任务task的状态设置为state*/
set_current_state(state) <=> set_stask_state(current,state)
  1. 进程上下文

进程家族树

  • 所有的进程都是PID为1的init进程的后台

  • 内核在系统启动的最后阶段启动init进程,该进程读取系统的初始化脚本并执行其他的相关程序

  • 进程间的关系存放在进程描述符中,每个tack_struct都包含一个指向其父进程task_struct,叫做parent的指针

获取其父进程的进程描述符:

1
struct task_struct *my_parent = ourrent->parent;

访问子进程:

1
2
3
4
5
6
7
8
9
10
11
12
13
struct task_struct *task;
struct list_head *list;

list_for_each(list,$current->children){
task = list_entry(list,sruct task_struct,sibling);
/* task 现在指向当前的某个子进程*/
}

struct task_struct *task;
for (task =current;task != $init_task; task= task->parent)
/* task 现在指向init */

}

系统调用

  • API.POSIX.C
  • 系统调用(系统调用号)
  • 系统调用处理程序

    int $0x80(十进制128) system_call()
    第128号异常处理程序
    系统调用号通过eax寄存器传递给内核
    call *sys_call_table(,%eax,4)
    系统调用表的表项是以32位类型存放的,所以内核需要将给定的系统调用号乘以4,然后查询
    参数传递:ebx,ecx,edx,esi和edi按照顺序存放前五个参数

  • 系统调用的实现

  • 系统调用上下文

    • entry.s(系统调用表)
  • 中断和中断处理程序

    • IRQ:中断请求
    • ISR:中断服务例程
  • 注册中断处理程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//request_irq()成功执行会返回0
int request_irq(unsigned int irq,
irqreturn_t(*handler)(int,void *,struct pt_regs *),
unsighed long irqflags,
const char* devname,
void *dev_id)

/*
参数说明:
irq:要分配的中断号
handler:指针,指向处理这个中断的世纪中断处理程序。
handler函数的原型是特定的,接受三个参数,并有一个类型为irqresutn_t的返回值。
irqflags:可以为0,也可以为下列标志的位掩码
SA_INTERRUPT:表示给定的中断处理程序是一个快速中断处理程序
SA_SAMPLE_RANDOM:
SA_SHIRQ:
devname:与中断相关的ASCII文本表示法.
dev_id:
*/

Linux内核编程一直是我很想掌握的一个技能。如果问我为什么,我也说不上来。
也许是希望有一天自己的名字也出现在内核开发组的邮件列表里?或是内核发行文件的CREDITS上?
也许是吧。其实更多的,可能是对于底层的崇拜,以及对于内核的求索精神。
想到操作系统的繁杂,想到软件系统之间的衔接,内心觉得精妙的同时,更是深深的迷恋。
所以从这篇文章开始,我要真正的走进Linux内核里了,让代码指引我,去奇妙的世界一探究竟。

在这篇文章中,一起来对内核说Hello World。

本次的编程环境:

  • CentOS 6.8
  • Linux centos 2.6.32-573.8.1.el6.x86_64

没有安装内核的,可能需要安装一下内核源码包

  • kernel-devel-2.6.32-642.4.2.el6.x86_64

    yum install kernel-devel-2.6.32-642.4.2.el6.x86_64

安装好之后,这个版本内核可以在/usr/src/linux找到。

然后话不多说,首先看代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//20160904
//kernel_hello_world.c

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>

static int __init lkp_init(void){
printk("Hello,World! --from the kernel space...\n");
return 0;
}

static void __exit lkp_cleanup(void){
printk("Goodbye,World! --leaving kernel space...");
}

module_init(lkp_init);
module_exit(lkp_cleanup);

以上代码是kernel_hello_world.c内容。
作为内核模块,在编译的时候,Makefile文件这样写:

1
2
#File:Makefile
obj-m += kernel_hello_world.o

然后可以通过这条命令来编译:

1
make -C /usr/src/linux SUBDIRS=$PWD modules

编译好以后,目录下面的文件可能是这样子:

kernel_hello_world.ko.unsigned  kernel_hello_world.o  Module.symvers
kernel_hello_world.c   kernel_hello_world.mod.c        Makefile
kernel_hello_world.ko  kernel_hello_world.mod.o        modules.order

有这么多文件被生成,其中kernel_hello_world.ko就是本次编译出来的内核模块文件,在Linux内核中有很多这样的模块,它们可能充当着不同的角色,可能是驱动,也可能是各种设备。

这个模块会在/var/log/message文件中打印一行字,即Hello,World! –from the kernel space…

可以使用insmod kernel_hello_world.ko来将这个模块载入到内核,使用lsmod来查看是否已经加载,使用rmmod kernel_hello_world.ko来卸载这个模块。

可以tail /var/log/message来看一下是否成功执行了呢?

Hello,Kernel.

本次的编程环境:

  • CentOS 6.8
  • Linux centos 2.6.32-573.8.1.el6.x86_64

在内核的源代码中定义了很多进程和进程调度相关的内容。其实Linux内核中所有关于进程的表示全都放在进程描述符这个庞大的结构体当中,关于这个结构体的内容和定义,可以在内核的linux/sched.h文件中找到。
现在就来通过编程实现对进程描述符的操作,主要是读取。至于修改等操作,将在后面的内容中提到。
通过对进程描述符的读取,可以获取进程的一切内容,包括进程的ID,进程的地址空间等等。

不多说,上代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
//20160912
//currentptr.c

#include <linux/tty.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/module.h>

/*Function To Write Msg To TTY*/
void tty_write_message(struct tty_struct *tty,char *msg){
if(tty && tty->ops->write){
tty->ops->write(tty,msg,strlen(msg));
}
return;
}

static int my_init(void){
char *msg="Hello tty!\n";
tty_write_message(current->signal->tty,msg);
printk("Hello -- from the kernel...\n");
printk("Parent pid: %d(%s)\n",current->parent->pid,current->parent->comm);
printk("Current pid: %d(%s)\n",current->pid,current->comm);
printk("Current fs: %d\n",current->fs);
printk("Current mm: %d\n",current->mm);
return 0;
}

static void my_cleanup(void){
printk("Goodbye -- from the kernel...\n");
}

module_init(my_init);
module_exit(my_cleanup);

以上的代码,主要就是通过引入内核头文件,进而引用进程描述符中的指针,并通过这种方式获取当前进程和相关进程的描述信息。
Makefile文件如下:

#Makefile
obj-m += currentptr.o

编译的指令:

make -C /usr/src/linux SUBDIRS=$PWD modules

然后通过insmod把模块装载进内核,首先tty输出了Hello tty!
同时在/var/log/message中,模块打印出了这些内容:

Sep 12 10:35:36 centos kernel: Hello -- from the kernel...
Sep 12 10:35:36 centos kernel: Parent  pid: 2235(bash)
Sep 12 10:35:36 centos kernel: Current pid: 13197(insmod)
Sep 12 10:35:36 centos kernel: Current fs: 927961856
Sep 12 10:35:36 centos kernel: Current mm: 932613056

分别是这个进程的相关信息。
对于进程描述符的定义,在本次实验用来编译的内核源码包(kernel-devel-2.6.32-642.4.2.el6.x86_64)中,
进程描述符具体定义在include/linux/sched.h的1326行往后。

需要参考的进程具体信息都在其中,可随时参考,以备不时之需。

之前研究Linux设备驱动时做的零零散散的笔记,整理出来,方便以后复习。

驱动程序的的角色

  • 提供机制

例如:
unix图形界面分为X服务器和窗口会话管理器,X服务器理解硬件及提供统一的接口给用户程序,窗口管理器实现了特别的策略但对硬件一无所知。

目标:实现对策略透明

  • 划分内核

进程管理
负责创建和销毁进程,并处理它们与外部的联系(输入和输出)。
实现了多个进程在一个单个或几个CPU之上的抽象。

内存管理
为每一个进程在有限的可用资源上建立了虚拟地址空间。

文件系统
在非结构化的硬件之上建立了一个结构化的文件系统。

设备控制
全部设备的控制操作都由特定的寻址设备相关的代码来进行。

网络
系统负责在程序和网络接口之间递送数据报文。

可加载模块

Linux特性:可以在运行时扩展由内核提供的特性,可以在系统正在运行的时候增加内核的功能(也可以去除)。
每块可以在运行时添加到内核的代码被称为一个模块。通过insmod和rmmod程序去连接。

设备和模块的分类

字符设备

字符(char)设备是一种可以当作字节流来存取的设备。这样的驱动常常实现open,close,read,write系统调用。
例如:文本控制台(/dev/console),串口(/dev/ttyS0)

块设备

通过位于/dev目录的文件系统节点来存取,可以驻有文件系统。与字符设备的区别在于内部管理数据的方式上–块设备允许一次传送任意数据的字节。

网络接口

负责发送和接收数据报文

安全问题

小心对待输入,未初始化的内存等,从内核获取的任何内存应当清零或者在其可用之前进行初始化。

版本编号

Linux系统中使用的每一个软件包存有自己的发行版本号,它们之间存在相互依赖性。

版权条款

字符驱动

scull
Simple Character Utility for Loading Localities

设备编号

[root@centos ~]$ ll /dev
total 0                                        主编号,次编号
drwxr-xr-x. 2 root    root         640 May 12 22:24 block
crw-------. 1 root    root     10, 234 May 12 22:24 btrfs-control
drwxr-xr-x. 3 root    root          60 May 12 22:24 bus
lrwxrwxrwx. 1 root    root           3 May 12 22:24 cdrom -> sr0
drwxr-xr-x. 3 root    root          80 May 12 22:24 cpu
crw-rw----. 1 root    root     10,  62 May 12 22:24 crash
drwxr-xr-x. 6 root    root         120 May 12 22:24 disk
brw-rw----. 1 root    disk    253,   0 May 12 22:24 dm-0
drwxr-xr-x. 2 root    root          60 May 12 22:24 dri
lrwxrwxrwx. 1 root    root           3 May 12 22:24 fb -> fb0
crw-rw----. 1 root    root     29,   0 May 12 22:24 fb0
crw-rw-rw-. 1 root    root      1,   7 May 12 22:24 full

主编号标识设备相连的驱动,次编号被内核用来决定引用哪个设备。

默认安装的MySQL数据库,无法远程连接。
登录MySQL之后,运行

1
SELECT user,host from mysql.user;

如果只有一条记录,说明是这个原因。
将下面的脚本保存成user.sql,登录MySQL,运行:

1
2
3
use mysql;
source user.sql;
flush privileges;

Notice: 会重置MySQL user表,并且将root用户密码设置为空。

脚本内容: 点这里直接下载

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------
-- Table structure for `user`
-- ----------------------------
USE mysql;
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`Host` char(60) COLLATE utf8_bin NOT NULL DEFAULT '',
`User` char(16) COLLATE utf8_bin NOT NULL DEFAULT '',
`Password` char(41) CHARACTER SET latin1 COLLATE latin1_bin NOT NULL DEFAULT '',
`Select_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
`Insert_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
`Update_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
`Delete_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
`Create_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
`Drop_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
`Reload_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
`Shutdown_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
`Process_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
`File_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
`Grant_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
`References_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
`Index_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
`Alter_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
`Show_db_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
`Super_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
`Create_tmp_table_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
`Lock_tables_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
`Execute_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
`Repl_slave_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
`Repl_client_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
`Create_view_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
`Show_view_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
`Create_routine_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
`Alter_routine_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
`Create_user_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
`Event_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
`Trigger_priv` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
`ssl_type` enum('','ANY','X509','SPECIFIED') CHARACTER SET utf8 NOT NULL DEFAULT '',
`ssl_cipher` blob NOT NULL,
`x509_issuer` blob NOT NULL,
`x509_subject` blob NOT NULL,
`max_questions` int(11) unsigned NOT NULL DEFAULT '0',
`max_updates` int(11) unsigned NOT NULL DEFAULT '0',
`max_connections` int(11) unsigned NOT NULL DEFAULT '0',
`max_user_connections` int(11) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`Host`,`User`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='Users and global privileges';

-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES ('localhost', 'root', '', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', '', '', '', '', '0', '0', '0', '0');
INSERT INTO `user` VALUES ('127.0.0.1', 'root', '', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', '', '', '', '', '0', '0', '0', '0');
INSERT INTO `user` VALUES ('%', 'root', '', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', 'Y', '', '', '', '', '0', '0', '0', '0');
flush privileges;

Python
先按F5,之后将下面的命令保存,再设置快捷键。

1
cmd /k  c:\python27\python "$(FULL_CURRENT_PATH)" & PAUSE & EXIT

我使用的是Ctrl+F9
之后按Ctrl+s保存更改,再按Ctrl+F7即可快速在cmd中运行代码,方便调试。

Ruby

1
cmd /k  C:\Ruby22-x64\bin\ruby "$(FULL_CURRENT_PATH)" & PAUSE & EXIT
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×