zoukankan      html  css  js  c++  java
  • 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)
    
  • 相关阅读:
    《C++ 并发编程》- 第1章 你好,C++的并发世界
    30分钟,让你成为一个更好的程序员
    程序员技术练级攻略
    谈新技术学习方法-如何学习一门新技术新编程语言
    计算机科学中最重要的32个算法
    程序员学习能力提升三要素
    一位在MIT教数学的老师总结了十条经验
    学习算法之路
    十个顶级的C语言资源助你成为优秀的程序员
    Linux中LoadAverage分析
  • 原文地址:https://www.cnblogs.com/baolin2200/p/6668767.html
Copyright © 2011-2022 走看看