012-Python-paramiko和IO多路复用

1.IO 多路复用

1.监听多个socket变化
2.socket服务端
IO多路复用+socket 来实现web服务器:

  • a.服务端优先运行
  • b.浏览器:http://.......com
    浏览器连接服务器就是socket + send("http协议")
  • c.服务端获取客户端发来的url,根据url不同响应数据
  • d.断开连接

产出:

  • a.浏览器发送数据,需要按照指定规则
  • b.监听多个socket对象
  • c.web框架开发者,业务开发者
  • d.模块独立化
#! /usr/bin/env python
# -*- coding: utf-8 -*-
# Date: 2017/3/27

import select
import socket

s1 = socket.socket()
s1.setblocking(0)
s1.bind(("127.0.0.1", 8888,))
s1.listen(5)

inputs = [s1, ]
while True:
    r_list, w_list, e_list = select.select(inputs, [], [], 0.5)

    for client in r_list:
        if client == s1:
            conn, addr = client.accept()
            conn.setblocking(0)
            inputs.append(conn)
        else:
            data = bytes()
            while True:
                try:
                    chunk = client.recv(1024)

                except Exception as e:
                    chunk = None
                if not chunk:
                    break
                data += chunk

            data_str = data.decode()

            '''print(data_str)
            客户端请求过来的数据原型
            GET /login.html HTTP/1.1
            Host: 127.0.0.1:8888
            Connection: keep-alive
            Cache-Control: max-age=0
            Upgrade-Insecure-Requests: 1
            User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36
            Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
            Accept-Encoding: gzip, deflate, sdch, br
            Accept-Language: zh-CN,zh;q=0.8
            '''
            header, body = data_str.split("

", 1)     # 找到第一个

 将请求进行分割;上半部为请求头,下半部为请求体
            head_list = header.split("
")                 # 将“请求头”进行分割为一行行的请求行数据;

            '''print(head_list)
            通过“

”切分过后的请求头数据
            ['GET /login.html HTTP/1.1', 'Host: 127.0.0.1:8888', 'Connection: keep-alive', 'Cache-Control: max-age=0', 
            'Upgrade-Insecure-Requests: 1', 
            'User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36', 
            'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8', 'Accept-Encoding: gzip,
             deflate, sdch, br', 'Accept-Language: zh-CN,zh;q=0.8']
            '''

            head_dict = {}                                   # 将请求头数据 切分为字典格式head_dict

            for line in head_list:
                value = line.split(":", 1)                   # 将请求头,按照第一个“:”进行分割
                if len(value) == 2:                          # 如果分割为两份
                    k, v = value                             # 第一份设置为 k ,第二份为 v
                    head_dict[k] = v                         # 将第一段的k,设置值为 v
                else:                    # 处理请求头的第一行 "GET /login.html HTTP/1.1" 按照空格切分;
                    head_dict["get"], head_dict["url"], head_dict["HTTP"] = line.split(" ")   # 将切分的3部分分别赋值;

            '''print(head_dict)
            切分后的请求头,字典格式 head_dict
            {'Accept-Encoding': ' gzip, deflate, sdch, br', 
            'Accept': ' text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8', 
            'Upgrade-Insecure-Requests': ' 1', 
            'url': '/login.html', 
            'Host': ' 127.0.0.1:8888', 
            'Cache-Control': ' max-age=0', 
            'Connection': ' keep-alive', 
            'get': 'GET', 
            'User-Agent': ' Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36', 
            'HTTP': 'HTTP/1.1', 
            'Accept-Language': ' zh-CN,zh;q=0.8'}
            '''

3.socket 客户端(爬虫)
利用一个线程,同时发送n个请求实现(异步非堵塞模块)

a.循环列表,为每一个URL生成一个Socket对象
b.每一个socket对象,向远程发送链接请求

  • connect: 会堵塞
    c.如果连接上:
  • 发送数据时,需要遵循HTTP的格式;
    d.获取相应内容
    e.关闭

注意:可读可写的状态

产出:
a.setblocking(0) # 以前夯住的地方都会报错
b.select 监听其他对象,需要有个 def fileno(self): 函数
c.gevent, twisted, asycio ---> 单线程并发发送http请求;


import socket
import select


class Foo:
    def __init__(self, s1, callback, url ,host):
        self.s1 = s1
        self.callback = callback
        self.url = url
        self.host = host

    def fileno(self):
        return self.s1.fileno()


class NbIO:
    def __init__(self):
        self.fds = []
        self.connections = []

    def connect(self, url_list):
        for item in url_list:
            conn = socket.socket()
            conn.setblocking(0)            # 表示连接不堵塞,不等待服务端返回数据
            try:
                conn.connect((item["host"], 80))     # 客户端连接 服务端 connect
            except BlockingIOError as e:
                pass
            obj = Foo(conn, item["callback"], item["url"], item["host"])
            self.fds.append(obj)
            self.connections.append(obj)

    def send(self):
        while True:
            try:
                if len(self.fds) == 0:
                    return
                r_list, w_list, e_list = select.select(self.fds, self.connections, [], 0.5)
                if len(self.fds) == 0:
                    break
                for obj in r_list:
                    # 有数据响应回来
                    conn = obj.s1

                    data = bytes()
                    while True:
                        try:
                            d = conn.recv(1024)
                            data += d
                        except BlockingIOError as e:
                            d = None
                        if not d:
                            break
                    # print(data.decode())
                    obj.callback(data)
                    self.fds.remove(obj)

                for obj in w_list:
                    # 已经连接到远程
                    conn = obj.s1

                    template = "GET %s HTTP/1.1
Host: %s

" % (obj.url, obj.host, )
                    conn.sendall(template.encode())

                    # print(conn)
                    self.connections.remove(obj)
            except OSError as e:
                pass


def f1(data):
    print(data.decode())


def f2(data):
    print(data)

url_list = [
    {'host':"www.baidu.com",'url': '/','callback':f1 }, # socket
    {'host':"www.bing.com",'url': '/','callback':f2 },
    {'host':"www.cnblogs.com",'url': '/wupeiqi','callback':f1 },
]

obj = NbIO()
obj.connect(url_list)
obj.send()

2.Paramiko模块,按照SSH协议连接数据以及发送数据;

1.可以通过python代码,实现对远程服务器操作;
2.功能:

  • a.使用用户名密码:命令,文件
  • b.使用用户名秘钥:命令,文件
  • c.执行创建session

2.1使用基于用户名密码的连接:

1.通过SSH Client方式连接:

import paramiko

ssh = paramiko.SSHClient()            # 创建SSh对象
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())     # 允许连接不在know_hosts文件中的主机
ssh.connect(hostname="192.168.56.11", port=22, username="root", password="123456")      # 创建连接
stdin, stdout, stderr = ssh.exec_command("df -h")             # 执行命令
result = stdout.read()               # 获取命令结果

print(result.decode())               # 打印获取的命令结果
ssh.close()                          # 关闭连接

2.通过SSHClient 封装 Transport方式连接

import paramiko

transport = paramiko.Transport(('192.168.56.11', 22))
transport.connect(username='root', password='123456')

ssh = paramiko.SSHClient()
ssh._transport = transport

stdin, stdout, stderr = ssh.exec_command('df -h')

result = stdout.read()
print(result.decode())

ssh.close()

以上输出:

文件系统        容量  已用  可用 已用% 挂载点
/dev/sda3        48G   13G   36G   26% /
devtmpfs        903M     0  903M    0% /dev
tmpfs           912M     0  912M    0% /dev/shm
tmpfs           912M   33M  880M    4% /run
tmpfs           912M     0  912M    0% /sys/fs/cgroup
/dev/sda1       197M  182M   15M   93% /boot
tmpfs           183M     0  183M    0% /run/user/0

3.基于私钥字符串进行连接

import paramiko

private_key = paramiko.RSAKey.from_private_key_file(r'C:Usersadmin.sshid_rsa')

transport = paramiko.Transport(('192.8.21.100',22))
transport.connect(username='root', pkey=private_key)

ssh = paramiko.SSHClient()
ssh._transport = transport
while True:
    cmd = input(">>:")
    if not cmd:continue
    if cmd == "exit":break
    stdin, stdout, stderr = ssh.exec_command(cmd)

    stderrad = stderr.read()
    result=stdout.read()
    print(result.decode('utf-8'),stderrad.decode("utf-8"))

transport.close()

2.2SFTPClient基于用户名密码上传下载

1.用于连接远程服务器并执行上传下载

import paramiko

transport = paramiko.Transport(('192.168.56.11', 22))
transport.connect(username='root', password='123456')

sftp = paramiko.SFTPClient.from_transport(transport)   # 创建sftp连接

# sftp.put('/tmp/location.py', '/tmp/test.py')    # 将location.py 上传至服务器 /tmp/test.py
sftp.get('a.py', 'a.py')                          # 将远程家目录下的a.py 下载到本地当前目录 a.py
transport.close()

2.通过paramiko封装 Transport方式进行模块化封装

import paramiko

class SshHelp:

    def __init__(self, host, port, username, pwd):
        self.host = host
        self.port = port
        self.username = username
        self.pwd = pwd
        self.transport = None


    def connect(self):
        transport = paramiko.Transport((self.host, self.port, ))
        transport.connect(username=self.username, password=self.pwd)
        self.transport = transport

    def upload(self, yuan, local):
        sftp = paramiko.SFTPClient.from_transport(self.transport)
        sftp.get(yuan, local)

    def cmd(self, shell):
        ssh = paramiko.SSHClient()
        ssh._transport = self.transport

        stdin, stdout, stderr = ssh.exec_command(shell)
        result = stdout.read()
        print(result.decode())

    def close(self):
        self.transport.close()

if __name__ == '__main__':

    obj = SshHelp("192.168.56.11", 22, "root", "123456")
    obj.connect()
    obj.cmd("df -h")

    obj.upload("a.py", "a.py")

    obj.close()

3.MySQL的操作连接

1.什么是MySQL:
服务端:
a.socket服务端运行,监听,IP和端口
b.获取客户端发送的数据:select inset...
c.解析
d.去文件中操作

客户端:
a.socket客户端:基于各种语言的客户端
b.验证
c.发送命令(SQL语句)

3.1表的操作:

1.创建一个表tb1:

not null:        表示不能为空;   
auto_increment: 表示为自增(一个表只能有一个自增的列)   
primary key:    主键(是一种索引,查询速度快,有约束的功能表示这一列不能为空、不能重复)   
default:         表示为默认值;在为空时设置一个默认值;   
create table tb1(
    -> id int not null auto_increment primary key,
    -> name char(20) null,
    -> age int not null)engine=innodb default charset utf8;

2.单外键,一个字符串+约束foreign key;

constraint:    约束、关键字   
fk_cc:        名字   
foreign key:  关键字   
(deparment_id): 本(自)表中的字段deparment_id   
references:   关键字   
deparment(id):  来自于deparment表里的id列      
create table deparment(
    id int not null auto_increment primary key,
    title char(32) null
)

create table person(
    id int not null auto_increment primary key,
    username char(32) null ,
    age int not null,
    deparment_id int not null,
    constraint fk_cc foreign key (deparment_id) references deparment(id)
)

3.多项的外键,一个表对多个表的外键

create table deparment(
    id int not null auto_increment primary key,
    title char(32) null
)

create table host(
    id int not null auto_increment primary key,
    ip char(32) null,
    port char(32) null
)

create table de_2_host(
    id int not null auto_increment primary key,
    did int not null,
    hid int not null,
    constraint fk_did_deparment foreign key (did) references deparment(id),
    constraint fk_hid_host      foreign key (hid) references host(id)
)

4.连表操作,查询a表关联b表,其中a表里的deparment_id和b表里的id相等:

SELECT * FROM a表 LEFT JOIN b表 ON a表.deparment_id = b表.id;

3.2使用pymysql实现连接数据库:

import pymysql

conn = pymysql.connect(host="192.168.56.11", port=3306, user="baolin", passwd="123456", db="python16")   # 创建连接

# cursor = conn.cursor()                                   # 创建游标(默认为元组形式)
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)    # 创建游标(会依照字典的格式展现)

# 执行sql时不要使用字符串拼接(以免SQL注入)
effect_row = cursor.execute("SELECT id,name,age FROM tb1 WHERE id > %s", (2,))     # 执行SQL,并返回受影响行数;
# effect_row = cursor.executemany("insert into tb1(name,age)VALUES(%s,%s)", [("xiaoliu", 17), ("tianpeng", 23),])

'''不可用:
username = inpus(>>>:)
pwd = inpus(>>>:)
sql = "select * from tb1 username = %s and pwd = %s" %(username,username)
effect_row = cursor.execute(sql)
如果用户输入的用户:root or 1 == 1 --
得到的语句为:(mysql中--为注释)一下语句就会永远成立
select * from tb1 username = root or 1 == 1 -- and pwd = %s"
'''
# ret = cursor.fetchone()         # 获取第一条数据
# ret = cursor.fetchmany(3)       # 获取内容的前三行
ret = cursor.fetchall()           # 获取所有数据
conn.commit()        # 提交操作
print(ret)
cursor.close()       # 关闭游标
conn.close()         # 关闭连接

new_id = cursor.lastrowid       # 涉及到插入时,求出最后插入那条数据的自增ID
print(new_id)
原文地址:https://www.cnblogs.com/baolin2200/p/6668767.html