• 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)
    
  • 相关阅读:
    UVALive 6909 Kevin's Problem 数学排列组合
    UVALive 6908 Electric Bike dp
    UVALive 6907 Body Building tarjan
    UVALive 6906 Cluster Analysis 并查集
    八月微博
    hdu 5784 How Many Triangles 计算几何,平面有多少个锐角三角形
    hdu 5792 World is Exploding 树状数组
    hdu 5791 Two dp
    hdu 5787 K-wolf Number 数位dp
    hdu 5783 Divide the Sequence 贪心
  • 原文地址:https://www.cnblogs.com/baolin2200/p/6668767.html
Copyright © 2020-2023  润新知