一、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这个相互之间有什么特点呢?

三、Paramiko vs SSH Shell

我们或多或少都应该使用过ssh连接到远端服务器执行命令,因为ssh默认是系统自带的,所以使用非常起来也非常简单。但是paramiko呢,它是一个更高层次的封装,可以实现更复杂的命令。一个实际工作中遇到的问题就是,面对自动化运维,面对若干台机器,还去用ssh执行命令就显得有点不是那么灵活了,功能单薄,且数据格式化和处理显得有点弱。但paramiko是基于Python的,它明显是一个更好的选择,paramiko有很好的扩展性,再配合Python各种系统模块,功能实现上可以非常快速。

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

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

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

1. 新建paramiko.SSHClient

>>> import paramiko

>>> client = paramiko.SSHClient()

1

2

>>>importparamiko

>>>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())

SunOct2223:24:06EDT2017

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

>>> for i in stdout:

... print(i, end='')

...

Sun Oct 22 23:27:01 EDT 2017

1

2

3

4

>>>foriinstdout:

...print(i,end='')

...

SunOct2223:27:01EDT2017

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

也可以选择输出到屏幕,如下:

while True:

line = stdout.readline()

if len(line) == 0:

break

sys.stdout.write(line)

sys.stdout.flush()

1

2

3

4

5

6

whileTrue:

line=stdout.readline()

iflen(line)==0:

break

sys.stdout.write(line)

sys.stdout.flush()

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

>>>importparamiko

>>>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())

SunOct2223:52:56EDT2017

>>>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')

>>>foriinfiles:

...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

>>>importconfigparser

>>>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

importparamiko

importconfigparser

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

importos

importparamiko

importconfigparser

client=paramiko.SSHClient()

client.set_missing_host_key_policy(paramiko.AutoAddPolicy())

defconnect():

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')

)

exceptExceptionase:

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

importparamiko

importconfigparser

classParamikoClient:

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)

defconnect(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')

)

exceptExceptionase:

print(e)

try:

self.client.close()

except:

pass

defruncmd(self,cmd):

stdin,stdout,stderr=self.client.exec_command(cmd)

returnstdout.read().decode()

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

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

>>> from ParamikoClient import ParamikoClient

1

>>>fromParamikoClientimportParamikoClient

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

>>> 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'))

MonOct2301:51:00EDT2017

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

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

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

如果您觉得本站对你有帮助,那么可以支付宝扫码捐助以帮助本站更好地发展,在此谢过。

python paramiko_Python Paramiko基本使用相关推荐

  1. python paramiko_Python Paramiko模块的使用实际案例

    本文研究的主要是Python Paramiko模块的使用的实例,具体如下. Windows下有很多非常好的SSH客户端,比如Putty.在python的世界里,你可以使用原始套接字和一些加密函数创建自 ...

  2. python paramiko_python paramiko

    paramiko 遵循SSH2协议,支持以加密和认证的方式,进行远程服务器的连接,可以实现远程文件的上传,下载或通过ssh远程执行命令. 一.安装 root@ubuntu:~/paramiko#pip ...

  3. python paramiko_python paramiko的使用介绍

    一: 使用paramiko #设置ssh连接的远程主机地址和端口 t=paramiko.Transport((ip,port)) #设置登录名和密码 t.connect(username=userna ...

  4. 利用python模块paramiko在CentOS 6.3 64上搭建SFTP环境

    用python实现远程登陆主机执行命令或通过sftp上传下载文件,有个很好的模块paramiko模块来演示这些功能,使用起来很方便 CentOS 6.x上的python版本默认是2.6的,为了平台兼容 ...

  5. python paramiko使用_使用python的paramiko模块实现ssh与scp功能

    #1. 介绍 这篇文章简单地介绍了python的paramiko模块的用法,paramiko实现了SSH协议,能够方便地与远程计算机交互.简单的说,就是你在terminal下执行的如下语句,现在可以通 ...

  6. python ssh登陆模块_使用python的Paramiko模块登陆SSH

    paramiko是用Python语言写的一个模块,遵循SSH2协议,支持以加密和认证的方式,进行远程服务器的连接. python的paramiko模块可以方便的实现ssh登录,并执行命令. 1. pa ...

  7. 【Python】Paramiko模块在Windows10中import ssl报错的处理方法

    上一篇文章[Python]Paramiko模块实现Linux服务器远程文件操作 介绍了如何通过Paramiko进行 sftp的操作,但最近遇到一个问题,换上家里的windows10电脑后,执行脚本时发 ...

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

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

  9. 【python】-- paramiko、跳板机(堡垒机)

    paramiko Python的paramiko模块,该模块用于连接远程服务器并执行相关命令,常用于作批量管理使用 一.下载: pip3 install paramiko 源码:查看 二.parami ...

最新文章

  1. 《分布式系统:概念与设计》一1.6 实例研究:万维网
  2. Xamarin Anroid App访问网站失败
  3. 一般地,我们将计算机指令的集合称为,简述公共关系人员培养的原则。
  4. asp.net中将数据库绑定到DataList控件的实现方法与实例代码
  5. RNN和LSTM、GRU的简单理解
  6. 变换上三角矩阵_关于马尔可夫矩阵的一些个人研究成果、思考过程及相关解释...
  7. CentOs搭建svn
  8. SCPPO(二十一):系统统一身份认证的改造之路(续)
  9. js 禁用和解除禁用按钮_js禁用button,js 将某个按钮禁用5秒钟
  10. cpu(s)和%CPU的的区别
  11. 全网首发:修改完善FreeSwitch的Banner功能
  12. clousx6机器人怎么导入词库_clousx6
  13. 高效获得准确的中国地图数据并进行可视化
  14. matlab对两组数据画图,matlab两列数据画图
  15. 6个html5手机游戏源码,html5逗你玩手机游戏源码
  16. 两款超级好用的PDF工具PDF Shaper,pdfFactory FinePrint虚拟打印机绿色单文件版
  17. 中国动漫及计算机专业好的大学排名,全国大学动画专业排名
  18. ionic html5 上传图片,ionic文件选择与ionic文件上传
  19. xp系统开启wlan服务器,XP系统笔记本怎么设置无线网络?
  20. 魔百和CM311-1a YST线刷精简固件(可救砖)

热门文章

  1. 是什么动词_动词后面跟什么词?答案笑喷...
  2. mysql 两列计数_MySQL在两列上计算唯一值,并为每列连接这些计数
  3. 赠书|大厂面试喜欢考算法,该怎么破?
  4. 皮一皮:流散国外的珍宝。。。
  5. 皮一皮:叛徒可耻!!!
  6. 皮一皮:当你在上海地铁里被夹住后...
  7. 字节跳动《算法中文手册》完整版 PDF 开放下载!
  8. 如何实现一个可复用的分布式事务消息架构方案?
  9. 这些好用的网站,看看你都收藏了没!
  10. 为什么分库分表后不建议跨分片查询