一、Paramiko简介

首先来看谁创造了paramiko,是一个名叫Jeff Forcier创建了paramiko项目。项目主页:http://www.paramiko.org,可以去看上面有很多相关的信息。然后这个项目是开源的,源码维护在github上,源码地址:https://github.com/paramiko/paramiko。

这个paramiko是Python下面一个非常著名的ssh项目,很多人贡献源码,当然这个Jeff Forcier它是一个主要的维护者。

我们首先看一下paramiko的起源,最开始它是用Python的对这个ssh进行一个封装,封装就是对一些面向对象的方法,就是把变量和方法给它包装起来。提供一些外部的api给大家很方便的使用它,比如说ssh,它很复杂但是通过它的一个包装把它很简单的提供给大家使用,那么问题来了。什么是ssh呢?

二、Ssh基本原理

简单来说ssh是用于计算机之间加密登陆的网络协议,协议就是端对端的一种通讯交互,我们可以看一下这个ssh它有什么特点?

传统的网络服务程序,如rsh、FTP、POP和Telnet其本质上都是不安全的;因为它们在网络上用明文传送数据、用户帐号和用户口令,很容易受到中间人(man-in-the-middle)攻击方式的攻击。就是存在另一个人或者一台机器冒充真正的服务器接收用户传给服务器的数据,然后再冒充用户把数据传给真正的服务器。

而SSH是目前较可靠,专为远程登录会话和其它网络服务提供安全性的协议。利用SSH协议可以有效防止远程管理过程中的信息泄露问题。通过SSH可以对所有传输的数据进行加密,也能够防止DNS欺骗和IP欺骗。

ssh之另一项优点为其传输的数据可以是经过压缩的,所以可以加快传输的速度。SSH有很多功能,它既可以代替Telnet,又可以为FTP、POP、甚至为PPP提供一个安全的“通道”。

ssh是Linux,MAC上的标配,比如说你的电脑是苹果电脑,它是osx系统,默认的它就有ssh是可以直接用的。ssh的命令行基本上就是ssh+username和ip,默认端口是22。它的使用是非常简单的,我们一旦知道一台机子的它的IP跟用户名和密码,就能ssh来进行登录这样就可以进行交互式的操作,而且上面看它的特点它是,进过加密的是相对安全的,那我们本次所用的paramiko和ssh这个相互之间有什么特点呢?

关于SSH更多可以看:安全连接工具OpenSSH介绍

三、Paramiko vs Ssh shell

首先ssh它是自带的使用非常的简单,但是paramiko呢它是一个更高层次的封装,可以实现更复杂的命令,一个实际工作中遇到的问题就是,面对自动化运维面对若干台机器Shell脚本,用ssh指令写Shell脚本是非常麻烦的。而且Shell脚本的话本身它的语法是不太好操作,但paramiko是基于Python的它明显是一个更好的选择,这个Python语言它本身更就是语法非常的简洁,语法非常的好写。paramiko就是基于Python的所以说用paramiko来操作这些指令的话是相对容易的。然后paramiko又跟好的扩展性。我们之后就可以看到其它用paramiko的一些扩展,但是用ssh的直接用它和这个Shell的话,扩展性是很差的。我们可以看出paramiko是有很大的优势的。

paramiko目前使用非常广泛,首先在DevOps这个领域内它的使用广泛,而且很多paramiko二次开发工具,比如fabic,这个是Jeff Forcier本人在paramiko的基础上开发。当然也有其它的开发者,基于paramiko进行了其它的适用于自己项目的二次开发。

四、Paramiko基于用户名和密码的SSHClient方式连接

使用paramiko模块有两种连接方式,一种是通过paramiko.SSHClient()函数,另外一种是通过paramiko.Transport()函数。

1. 新建paramiko.SSHClient

>>> import paramiko
>>> client = paramiko.SSHClient()
1
2
>>> import paramiko
>>> client = paramiko.SSHClient()

Paramiko连接远程服务器,它的过程是这样的,首先是新建一个SSHClient,这个SSHClient是什么呢?它是Paramiko提供给我们的一个api中的类,因为Paramiko它是一个基于ssh协议的一个封装的类库,它提供了一些好用的api给我们使用,让我们来完成各种各样的操作。这个SSHClient就是它提供的一个要访问远程,和文件传输的一个最基本的接口。

2. 设置hot key机制

>>> client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
1
>>> client.set_missing_host_key_policy(paramiko.AutoAddPolicy())

另外一个就是要设置它的hot key,处理服务器端发来的公钥的机制。允许将信任的主机自动加入到host_allow列表,此方法必须放在connect方法的前面。Paramiko它提供给我们一个比较简单的设置的办法。

3. 调用API connect

>>> client.connect(hostname="10.10.0.112", port=22, username="root", password="123456", timeout=10)
1
>>> client.connect(hostname="10.10.0.112", port=22, username="root", password="123456", timeout=10)

最后就是调用它的的connect API连接。它的connect方法有很多的参数,有IP、端口、用户名、密码、还有一些其它的很多参数。我们在用其中一个比较重要的参数就是timeout就是超时时间,就是建立这个链接的时候我们想让它,如果多久没有直接连接,就返回异常。

4. 执行命令

成功建立连接之后,就可以进行对远程服务器执行命令了。它其实也是非常简单的,调用方法exec_command()即可,有好几个参数,比如说command、bufsize,我们现在就只用它的command参数,打印远程服务器时间。

>>> stdin, stdout, stderr = client.exec_command('date')
1
>>> stdin, stdout, stderr = client.exec_command('date')

这个command返回的是一个元组,有三个变量,分别是有输入(stdin)输出(stdout)和错误(stderr),我们用的最多的是它的输出。如果直接打印输出,其实,是把一些内部的信息给打印出来了。可以使用read或者readlines直接打印出结果:

>>> print(stdout.read())
b'Tue Oct 24 05:18:14 EDT 2017\n'
1
2
>>> print(stdout.read())
b'Tue Oct 24 05:18:14 EDT 2017\n'

decode方法只是让输出好看一些。

>>> print(stdout.read().decode())
Sun Oct 22 23:24:06 EDT 2017
1
2
>>> print(stdout.read().decode())
Sun Oct 22 23:24:06 EDT 2017

或者使用迭代的方式打印:

>>> for i in stdout:
... print(i, end='')
...
Sun Oct 22 23:27:01 EDT 2017
1
2
3
4
>>> for i in stdout:
...     print(i, end='')
...
Sun Oct 22 23:27:01 EDT 2017

这里print使用end参数去掉了自动换行功能(\n),因为执行完命令再得到结果时就已经带了\n,如
print(stdout.read())所示。所以这里如果不去掉,print时就会发现多出现一行空格。

5. 关闭连接

当命令执行完了之后,就可以调用close方法把连接关闭了。

>>> client.close()
1
>>> client.close()

五、Paramiko基于密钥的SSHClient方式连接

首先需要建立好服务端和客户端的秘钥对(把客户端公钥信息上传到服务器/User/.ssh/authorized_keys文件中)。

然后指定本地的私钥文件,使用不同的算法初始化不同的类,一般常用的就是RSA算法。如果建立密钥对时设置有密码,需要指定password为设定的密,如果没有则不用指定password参数。

>>> import paramiko
>>> pkey = paramiko.RSAKey.from_private_key_file('/root/.ssh/id_rsa')
1
2
>>> import paramiko
>>> pkey = paramiko.RSAKey.from_private_key_file('/root/.ssh/id_rsa')

其余的使用方法跟普通的用户名密码连接方式操作基本相同,如下:

>>> client = paramiko.SSHClient()
>>> client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
>>> client.connect(hostname='10.10.0.112', port=22, username='root', pkey=pkey)
>>> stdin, stdout, stderr = client.exec_command('date')
>>> print(stdout.read().decode())
Sun Oct 22 23:52:56 EDT 2017
>>> client.close()
1
2
3
4
5
6
7
>>> client = paramiko.SSHClient()
>>> client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
>>> client.connect(hostname='10.10.0.112', port=22, username='root', pkey=pkey)      
>>> stdin, stdout, stderr = client.exec_command('date')
>>> print(stdout.read().decode())                      
Sun Oct 22 23:52:56 EDT 2017
>>> client.close()

六、Paramiko基于Transport方式连接

基于传统的连接服务器、执行命令、关闭连接这样的一个操作能够满足单次执行,互相之间没有联系的操作,但有时候需要登录上服务器执行多个操作,比如执行多个命令、上传/下载文件,传统方式则满足不了。但可以通过Transport方式来操作。

# 实例化一个transport对象;
>>> transport = paramiko.Transport(('10.10.0.112', 22))

# 建立连接;
>>> transport.connect(username='root', password='123456')

# 将sshclient的对象的transport指定为以上的transport;
>>> ssh = paramiko.SSHClient()
>>> ssh._transport = transport

# 执行命令,和传统方法一样;
>>> stdin, stdout, stderr = ssh.exec_command('df -hl')
>>> print(stdout.read().decode())

# 关闭连接;
>>> transport.close()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 实例化一个transport对象;
>>> transport = paramiko.Transport(('10.10.0.112', 22))
 
# 建立连接;
>>> transport.connect(username='root', password='123456')
 
# 将sshclient的对象的transport指定为以上的transport;
>>> ssh = paramiko.SSHClient()
>>> ssh._transport = transport
 
# 执行命令,和传统方法一样;
>>> stdin, stdout, stderr = ssh.exec_command('df -hl')
>>> print(stdout.read().decode())
 
# 关闭连接;
>>> transport.close()

同样,对于秘钥方式的transport连接,只需要变更connect连接方法的参数即可:

>>> transport.connect(username='root', pkey=pkey)
1
>>> transport.connect(username='root', pkey=pkey)

七、Paramiko上传下载文件

Paramiko除了执行命令之外,还可以用来上传下载文件。一般选择SCP或者SFTP。

SCP

SCP全写是:Secure Copy,是基于SSH协议的文件拷贝方法,可以在本机与远程主机或两个远程主机之间进行文件拷贝。SCP的实现需要通过SCP协议以及SCP程序。

SFTP

在计算机领域,SSH文件传输协议 (英语:SSH File Transfer Protocol,也称Secret File Transfer Protocol,Secure FTP或SFTP) 是一数据流连线,提供档案存取、传输和管理功能的网络传输协定。由互联网工程任务组 (IETF) 设计,透过SSH 2.0 的扩充提供安全档案传输能力,但也能够被其它协定使用。

Paramiko选择SFTP作为上传下载工具,它提供给我们paramiko.SFTPClient这个类,然后这个类提供了很多的这个函数来供我们来调用来处理SFTP它的各种各样的运用,看一下这个编码的实现。

# 实例化一个transport对象;
>>> transport = paramiko.Transport(('10.10.0.112', 22))

# 建立transport连接;
>>> transport.connect(username='root', password='123456')

# 实例化一个sftp对象,指定连接的通道;
>>> sftp = paramiko.SFTPClient.from_transport(transport)

# 使用put方法上传文件;
>>> sftp.put(localpath='/root/ParamikoClient.py',remotepath='/tmp/ParamikoClient.py')

# 使用get方法下载文件;
>>> sftp.get(remotepath='/tmp/ParamikoClient.py',localpath='/tmp/ParamikoClient.py')

# 关闭通道;
>>> sftp.close()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 实例化一个transport对象;
>>> transport = paramiko.Transport(('10.10.0.112', 22))
 
# 建立transport连接;
>>> transport.connect(username='root', password='123456')
 
# 实例化一个sftp对象,指定连接的通道;
>>> sftp = paramiko.SFTPClient.from_transport(transport)
 
# 使用put方法上传文件;
>>> sftp.put(localpath='/root/ParamikoClient.py',remotepath='/tmp/ParamikoClient.py')
 
# 使用get方法下载文件;
>>> sftp.get(remotepath='/tmp/ParamikoClient.py',localpath='/tmp/ParamikoClient.py')
 
# 关闭通道;
>>> sftp.close()

sftp还有很多方法,如remove、rename、chmod、chown、listdir、mkdir、rmdir、open、truncate、symlink、unlink等等。

另外如果批量上传下载,可以使用如下方式:

>>> files = sftp.listdir('/root')
>>> for i in files:
... sftp.get(remotepath=os.path.join('/root/', i), localpath=os.path.join('/tmp', i))
1
2
3
>>> files = sftp.listdir('/root')
>>> for i in files:
...     sftp.get(remotepath=os.path.join('/root/', i), localpath=os.path.join('/tmp', i))

八、编写优雅实现

1. 消除硬编码

第一个就是它有硬编码的情况,什么是硬编码,什么是硬编码就是说在代码里面,你用的一些变量它是写死的,比如说我们刚才调用connect APId的时候它的,ip地址端口用户名和密码都是我们写死的,什么192.168.3.106,用户名,密码,如果它的对端的这个端口它变了,或者说是密码用户名一般不会变。它的密码改变我们是不是要去修改代码,如果在实际工作中这样是非常不方便的,而且是有一定风险的,修改代码就意味着它可能是bug产生的边缘。所以说我们最好把这个可配置的代码,和变量分离开来。就是说消除硬编码的一个办法就是让它可配置。

2. 异常捕捉

其次就是异常的捕捉,我们可以看到刚开始我们想列了,那个设置hot key机制时候,它调用connect方法,就抛出来一个sshaexception这个异常,但是我们并没有对它进行处理。这样的话就会在 实际的工作中它就非常的不好,甚至是有一些风险,因为不捕获这个异常的话,可能你的代码,就没办法在执行下去了,然后你写了这个软件可能就当掉了实际生产环境下,是一个非常严重的问题。

3. 封装

另外就是进行一下封装,我们看到Paramiko它是对这个,它其实就是对ssh协议的一个封装,然而我们在实际的使用Paramiko的过程中,可以针对自己项目的需要。对它进行二次封装,就是说我封装成我们大家,一起,团队的人它更方便的使用它,甚至它可以不知道Paramiko这个的存在,而调用你封装的接口。来进行一个更方便的操作。

那我们就看实际的过程中我们是怎样来解决这几个问题的,首先就是消除硬编码的问题,我们引入另外一个configparser这个库,configparser就是可以把这个配置很方便的读进来。

>>> import configparser
>>> config = configparser.ConfigParser()
1
2
>>> import configparser
>>> config = configparser.ConfigParser()

然后它有一个read的API就是读取文件。

那现在我们就一起来建立一个文件,叫做config.conf

[ssh]
host=10.10.0.112
port=22
username=root
password=123456
timeout=1.0
1
2
3
4
5
6
[ssh]
host=10.10.0.112
port=22
username=root
password=123456
timeout=1.0

然后我们read这个config.conf。那么这些硬编码的地方,就可以换成对应的配置,如下:

client.connect(hostname = config.get('ssh','host'),
port = config.getint('ssh','port'),
username = config.get('ssh','username'),
password = config.get('ssh','password'),
timeout = config.getfloat('ssh','timeout'))
1
2
3
4
5
client.connect(hostname = config.get('ssh','host'),
    port = config.getint('ssh','port'),
    username = config.get('ssh','username'),
    password = config.get('ssh','password'),
    timeout = config.getfloat('ssh','timeout'))

这样我们把这些变量给替换成用这个配置来解析出来它实际的值。我们就是用这个configparser来完成的,现在它运行的是非常的好,然后我们就把这些实际的参数给用配置给它隐藏起来,如果将来我们配置一旦更改的时候我们只需要更改这个config.conf就可以。

完整代码如下:

import paramiko
import configparser

config = configparser.ConfigParser()
config.read('config.conf')

client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect(hostname = config.get('ssh','host'),
port = config.getint('ssh','port'),
username = config.get('ssh','username'),
password = config.get('ssh','password'),
timeout = config.getfloat('ssh','timeout'))

stdin, stdout, stderr = client.exec_command('date')
print(stdout.read().decode())
client.close()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import paramiko
import configparser
 
config = configparser.ConfigParser()
config.read('config.conf')
 
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect(hostname = config.get('ssh','host'),
    port = config.getint('ssh','port'),
    username = config.get('ssh','username'),
    password = config.get('ssh','password'),
    timeout = config.getfloat('ssh','timeout'))
 
stdin, stdout, stderr = client.exec_command('date')
print(stdout.read().decode())
client.close()

然后我们来看一下,如何进行异常的捕获。首先这个connect它会抛出这个异常的时候我们其实就应该用Python的try来捕获它,然后用这个except Exception as e:可以把异常给打印出来。

import os
import paramiko
import configparser

client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())

def connect():
try:
config = configparser.ConfigParser()
config.read('config.conf')
client.connect(
hostname = config.get('ssh','host'),
port = config.getint('ssh','port'),
username = config.get('ssh','username'),
password = config.get('ssh','password'),
timeout = config.getfloat('ssh','timeout')
)
except Exception as e:
print(e)
try:
client.close()
os._exit(1)
except:
pass

connect()
stdin, stdout, stderr = client.exec_command('date')
print(stdout.read().decode())
client.close()

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
import os
import paramiko
import configparser
 
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
 
def connect():
    try:
        config = configparser.ConfigParser()
        config.read('config.conf')
        client.connect(
            hostname = config.get('ssh','host'),
            port = config.getint('ssh','port'),
            username = config.get('ssh','username'),
            password = config.get('ssh','password'),
            timeout = config.getfloat('ssh','timeout')
        )
    except Exception as e:
        print(e)
        try:
            client.close()
            os._exit(1)
        except:
            pass
 
connect()
stdin, stdout, stderr = client.exec_command('date')
print(stdout.read().decode())
client.close()

其实在连接这个地方抛出捕获的时候我们就在这把它给捕获了,并可以处理掉,不然到后面这个exec_command它也是会抛出异常。

接下来我们就对它进行一个封装,如何封装,封装它是一个面向对象的一个特点,就会面向对象方法的一个特点,所以说我们把一些细节给隐藏起来,怎么隐藏呢,就是通过类。

我们可以新建一个ParamikoClient这个类,整体代码如下:

import paramiko
import configparser

class ParamikoClient:
def __init__(self, file):
self.client = paramiko.SSHClient()
self.client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
self.config = configparser.ConfigParser()
self.config.read(file)

def connect(self):
try:
self.client.connect(
hostname = self.config.get('ssh','host'),
port = self.config.getint('ssh','port'),
username = self.config.get('ssh','username'),
password = self.config.get('ssh','password'),
timeout = self.config.getfloat('ssh','timeout')
)
except Exception as e:
print(e)
try:
self.client.close()
except:
pass

def runcmd(self, cmd):
stdin, stdout, stderr = self.client.exec_command(cmd)
return stdout.read().decode()

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 paramiko
import configparser
 
class ParamikoClient:
    def __init__(self, file):
        self.client = paramiko.SSHClient()
        self.client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        self.config = configparser.ConfigParser()
        self.config.read(file)
 
    def connect(self):
        try:
            self.client.connect(
                hostname = self.config.get('ssh','host'),
                port = self.config.getint('ssh','port'),
                username = self.config.get('ssh','username'),
                password = self.config.get('ssh','password'),
                timeout = self.config.getfloat('ssh','timeout')
            )
        except Exception as e:
            print(e)
            try:
                self.client.close()
            except:
                pass
 
    def runcmd(self, cmd):
        stdin, stdout, stderr = self.client.exec_command(cmd)
        return stdout.read().decode()

主要三个方法,第一个方法就是在初始化时把配置文件传进来,第二个方法connect用来连接使用,第三个方法就是用来执行命令的。注意,提供给其他脚本调用的类方法都需要使用return返回而不是print。

这个类做好之后,就可以使用了,可以直接在交互模式下把ParamikoClient类导进来,如下:

>>> from ParamikoClient import ParamikoClient
1
>>> from ParamikoClient import ParamikoClient

然后就可以初始化这个类,并传入配置文件:

>>> client = ParamikoClient('config.conf')
1
>>> client = ParamikoClient('config.conf')

调用它的connect方法来接服务器:

>>> client.connect()
1
>>> client.connect()

然后就可以直接调用runcmd方法来执行命令:

>>> print(client.runcmd('date'))
Mon Oct 23 01:51:00 EDT 2017
1
2
>>> print(client.runcmd('date'))
Mon Oct 23 01:51:00 EDT 2017

我们这样就看到到了这个从它编码,到进行一个更优雅实现的这么一个过程。

其实还有一个更好的做法就是把这个ParamikoClient这个类单独放到一个文件里面,封装性会更好。

Github地址:https://github.com/paramiko/paramiko


如果您觉得本站对你有帮助,那么可以支付宝扫码捐助以帮助本站更好地发展,在此谢过。
喜欢 (3)or分享 (0)

Python网络模块Paramiko基本使用的更多相关文章

  1. python的paramiko源码修改了一下,写了个操作命令的日志审计 bug修改

    python的paramiko源码修改了一下,写了个操作命令的日志审计,但是记录的日志中也将backspace删除键记录成^H这个了,于是改了一下代码,用字符串的特性. 字符串具有列表的特性 > ...

  2. 如何进行服务器的批量管理以及python 的paramiko的模块

    最近对公司的通道机账号进行改造管理,全面的更加深入的理解了公司账号管理的架构.(注:基本上所有的机器上的ssh不能使用,只有部分机器能够使用.为了安全的角度考虑,安装的不是公版的ssh,而都是定制版的 ...

  3. python 多线程 paramiko实现批量命令输入输出

    远程批量执行命令 实现多线程执行 速度快 实现多并发登录 #-*- coding: utf-8 -*- #!/usr/bin/python import paramiko import threadi ...

  4. python的paramiko模块

        paramiko是用python语言写的一个模块,遵循SSH2协议,支持以加密和认证的方式,进行远程服务器的连接.paramiko支持Linux, Solaris, BSD, MacOS X, ...

  5. Python之paramiko模块

    今天我们来了解一下python的paramiko模块 paramiko是python基于SSH用于远程服务器并执行相应的操作. 我们先在windows下安装paramiko 1.cmd下用pip安装p ...

  6. (转)python通过paramiko实现,ssh功能

    python通过paramiko实现,ssh功能 1 import paramiko 2 3 ssh =paramiko.SSHClient()#创建一个SSH连接对象 4 ssh.set_missi ...

  7. 使用python的Paramiko模块登陆SSH

    使用python的Paramiko模块登陆SSH paramiko是用Python语言写的一个模块,遵循SSH2协议,支持以加密和认证的方式,进行远程服务器的连接. python的paramiko模块 ...

  8. 利用python 下paramiko模块无密码登录

    利用python 下paramiko模块无密码登录   上次我个大家介绍了利用paramiko这个模块,可以模拟ssh登陆远程服务器,并且可以返回执行的命令结果,这次给大家介绍下如何利用已经建立的密钥 ...

  9. (转)python的paramiko模块

    python的paramiko模块  原文:http://www.cnblogs.com/breezey/p/6663546.html     paramiko是用python语言写的一个模块,遵循S ...

随机推荐

  1. Ajax笔记-加强版

    AJAX :   Asynchronous JavaScript and XML 异步JavaScript和XML   用javascript异步形式去操作xml 进行数据交互   节省用户操作,时间 ...

  2. zoj 2314 Reactor Cooling (无源汇上下界可行流)

    Reactor Coolinghttp://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1314 Time Limit: 5 Seconds ...

  3. Python学习笔记(三十一)正则表达式

    ---恢复内容开始--- 摘抄自:https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000 ...

  4. CodeForces - 1004B

    Sonya decided to organize an exhibition of flowers. Since the girl likes only roses and lilies, she ...

  5. HDU 2044 Coins

    有一只经过训练的蜜蜂只能爬向右侧相邻的蜂房,不能反向爬行.请编程计算蜜蜂从蜂房a爬到蜂房b的可能路线数. 其中,蜂房的结构如下所示.   Input输入数据的第一行是一个整数N,表示测试实例的个数,然 ...

  6. jQuery domready

    在jQuery里面,我们可以看到两种写法: $(function(){ //todo }) $(document).ready(function(){ //todo }) 这两个方法的效果都是一样的, ...

  7. HBA 介绍

    1.首先介绍一下什么是HBA. 这里所说的HBA,全称FC HBA,也就是Fibre Channel Host Bus Adapter.在FC网络中,主机(如服务器)需要和FC网络.FC存储设备(如S ...

  8. layui实现类似于bootstrap的模态框功能

    以前习惯了bootstrap的模态框,突然换了layui,想的用layui实现类似于bootstrap的模态框功能. 用到了layui的layer模块,例如: <!DOCTYPE html> ...

  9. oracle 归档模式、补充日志

    1.归档模式: Oracle数据库有联机重做日志,这个日志是记录对数据库所做的修改,比如插入,删除,更新数据等,对这些操作都会记录在联机重做日志里.一般数据库至少要有2个联机重做日志组.当一个联机重做 ...

  10. 谷歌PageRank算法

    1. 从Google网页排序到PageRank算法 (1)谷歌网页怎么排序? 先对搜索关键词进行分词,如“技术社区”分词为“技术”和“社区”: 根据建立的倒排索引返回同时包含分词后结果的网页: 将返回 ...