日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

第十三章:Python の 网络编程进阶(二)

發布時間:2024/4/15 python 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 第十三章:Python の 网络编程进阶(二) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

本課主題

  • SQLAlchemy - Core
  • SQLAlchemy - ORM
  • Paramiko?介紹和操作
  • 上下文操作應用
  • 初探堡壘機

?

SQLAlchemy - Core

連接 URL

通過 create_engine 方法創建 MySQL 數據庫的連接,create_engine("url") 接受一個 URL 連接:>>> MySQL-Python: mysql+mysqldb://<user>:<password>@<host>[:<port>]/<dbname>>>> pymysql: mysql+pymysql://<username>:<password>@<host>/<dbname>[?<options>]>>> MySQL-Connector: mysql+mysqlconnector://<user>:<password>@<host>[:<port>]/<dbname>>>> cx_Oracle: oracle+cx_oracle://user:pass@host:port/dbname[?key=value&key=value...]>>> PostgreSQL: postgresql+pg8000://<user>:<password>@<host>/<db>Details: http://docs.sqlalchemy.org/en/latest/dialects/index.html create_engine("url")

用 SQLAlchemy 來創建數據庫表

from datetime import datetime# ------------------------------------------------------------ # Import the datatype # ------------------------------------------------------------ from sqlalchemy import (MetaData, Table, Column, Integer, Numeric, String, Float, Boolean,DateTime, ForeignKey, create_engine ) metadata = MetaData()# ------------------------------------------------------------ # Table Objects # ------------------------------------------------------------ # 創建 cookies 的數據庫表 cookies = Table('cookies', metadata,Column('cookie_id', Integer(), primary_key=True),Column('cookie_name', String(50), index=True), #創建索引Column('cookie_recipe_url', String(255)),Column('cookie_sku', String(55)),Column('quantity', Integer()),Column('unit_cost', Numeric(12,2))# Index('ix_cookies_cookie_name', 'cookie_name') #也可以調用這個方法來創建索引 )# 創建 users 的數據庫表 user = Table('users', metadata,Column('user_id', Integer(), primary_key=True),Column('username', String(15), nullable=False, unique=True),Column('email_address', String(255), nullable=False),Column('phone', String(20), nullable=False),Column('password', String(25), nullable=False),Column('created_on', DateTime(), default=datetime.now),Column('updated_on', DateTime(), default=datetime.now, onupdate=datetime.now)# PrimaryKeyConstraint('user_id', name='user_pk'), #也可以調用這個方法來創建主鍵# UniqueConstraint('username', name='uix_username'), #也可以調用這個方法來創建唯一# CheckConstraint('unit_cost >= 0.00', name='unit_cost_positive') )# 創建 orders 的數據庫表 orders = Table('orders', metadata,Column('order_id', Integer(), primary_key=True),Column('user_id', ForeignKey('users.user_id')),Column('shipped', Boolean(), default=False) )# 創建 line_items 的數據庫表 line_items = Table('line_items', metadata,Column('line_items_id', Integer(), primary_key=True),Column('order_id', ForeignKey('orders.order_id')),Column('cookie_id', ForeignKey('cookies.cookie_id')),Column('quantity', Integer()),Column('extended_cost', Numeric(12,2)) )# ------------------------------------------------------------ # 連接url # ------------------------------------------------------------ engine = create_engine("mysql+pymysql://root@localhost/demo_db", pool_recycle=3600)# ------------------------------------------------------------ # 調用 create_all() 方法來創建所有數據庫表 # 默認該方法不會對已經存在的數據庫表重新創建。 # ------------------------------------------------------------ metadata.create_all(engine) metadata.create_all(engine)

???

?

SQLAlchemy - ORM

這是一個叫?Object Relational Mapping 框架,可以讓我們通過類和對象來操作數據庫,具體功能包括創建表,定義數據類型,新增或者查詢,一般?MySQL 能做的功能,都可以在 SQLALchemy 里實現,我也是用上一章的那個數據模型去介紹如何用 SQLALchemy 的API去操作數據庫。

一對多例子:

從人的角度看:每個人只可以選擇種顏色(一對一);從顏色的角度看:但是一種顏色可以有多個人選擇(一對多)

對多例子

從組的角度看:每個組可以有不同的服務器(一對多);從服務器的角度看:每個服務器也可以屬于不同的組(一對多)

表操作

  • 創建連接
    engine = create_engine('mysql+pymysql://myuser:mypass@192.168.80.128:3306/s13', max_overflow = 5) 創建 MySQL連接
  • 創建表
    Base.metadata.create_all(engine) Base.metadata.create_all( ) #!/usr/bin/env python # -*- coding:utf-8 -*-from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import Column, Integer, String, ForeignKey, UniqueConstraint, Index from sqlalchemy.orm import sessionmaker, relationship from sqlalchemy import create_engineengine = create_engine('mysql+pymysql://myuser:mypass@192.168.80.128:3306/s13', max_overflow = 5) # 創建連接 Base = declarative_base()# Many-to-many class Servers_to_Groups(Base):__tablename__ = 'rel_servers_groups'nid = Column(Integer, nullable=False, primary_key=True)server_id = Column(Integer, ForeignKey('servers.id'))group_id = Column(Integer, ForeignKey('groups.id'))# 在 sqlalchemy 支持創建 relationship,方便查詢groups = relationship('Groups', backref = 'lkp_servers') # 在groups表的內部, sqlalchemy 會多創建一個隱性字段名叫 lkp_serversservers = relationship('Servers', backref = 'lkp_groups') # 在servers表的內部, sqlalchemy 會多創建一個隱性字段名叫 lkp_groupsclass Groups(Base):__tablename__ = 'groups'id = Column(Integer, nullable=False, primary_key=True)name = Column(String(50), unique=True, nullable=False)port = Column(Integer, default=22)class Servers(Base):__tablename__ = 'servers'id = Column(Integer, nullable=False, primary_key=True)name = Column(String(64), unique=True, nullable=False) sqlalchemy創建表(多對多) #!/usr/bin/env python # -*- coding:utf-8 -*-from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import Column, Integer, String, ForeignKey, UniqueConstraint, Index from sqlalchemy.orm import sessionmaker, relationship from sqlalchemy import create_engineengine = create_engine('mysql+pymysql://myuser:mypass@192.168.80.128:3306/s13', max_overflow = 5) # 創建連接 Base = declarative_base()class Users(Base):__tablename__ = 'users'id = Column(Integer, nullable=False, primary_key=True)name = Column(String(32))extra = Column(String(16))__table_args__ = (UniqueConstraint('id','name', name = 'unix_id_name'),Index('ix_id_name','name','extra'))# One-to-many class Favor(Base):__tablename__ = 'favor'nid = Column(Integer, primary_key=True)caption = Column(String(32), default='red', unique=True)#當打印這個類時,會使用以下方法def __repr__(self):return "%s-%s" %(self.nid, self.caption)class Person(Base):__tablename__ = 'person'nid = Column(Integer, primary_key=True)name = Column(String(32), index=True, nullable=True)favor_id = Column(Integer, ForeignKey('favor.nid'))favor = relationship('favor', backref='lkp_person') # 在favor表的內部,sqlalchemy會多創建一個隱性字段名叫lkp_person sqlalchemy創建表(一對多)
  • 刪除表 DROP TABLE
    Base.metadata.drop_all(engine) Base.metadata.drop_all( )
  • 定義自動增量?AUTO INCREMEN/主鍵 PRIMARY KEY
    sid = Column(Integer, primary_key=True, autoincrement=True) autoincrement,primary_key
  • 定義外鍵 FOREIGN KEY
    person_sid = Column(Integer, ForeignKey("dm_person.sid"),nullable=False) ForeignKey( )
  • 定義關系 relationship
    class Favor(Base):__tablename__ = 'favor'nid = Column(Integer, primary_key=True)caption = Column(String(32), default='red', unique=True)#當打印這個類時,會使用以下方法def __repr__(self):return "%s-%s" %(self.nid, self.caption)class Person(Base):__tablename__ = 'person'nid = Column(Integer, primary_key=True)name = Column(String(32), index=True, nullable=True)favor_id = Column(Integer, ForeignKey('favor.nid'))favor = relationship('favor', backref='lkp_person') relationship( )
  • 定義約束?CONSTRAINT
    class Users(Base):__tablename__ = 'users'id = Column(Integer, nullable=False, primary_key=True)name = Column(String(32))extra = Column(String(16))__table_args__ = (UniqueConstraint('id','name', name = 'unix_id_name'),Index('ix_id_name','name','extra')) sqlalchemy中的約束
  • ALTER TABLE
  • WHERE
    # WHERE CLAUSE record = session.query(Users).filter_by(name='janice').all() record = session.query(Users).filter(Users.id > 1, Users.name == 'janice').all() record = session.query(Users).filter(Users.id.between(1,3)).all() record = session.query(Users).filter(Users.id.in_([1,3,4])).all() record = session.query(Users).filter(~Users.id.in_([1,3,4])).all() record = session.query(Users).filter(Users.id.in_(session.query(Users.id).filter_by(name='janice'))).all() session.query( ).filter( )
  • ORDER BY
    record = session.query(Users).order_by(Users.name.desc()).all() record = session.query(Users).order_by(Users.name.desc(), Users.id.asc()).all()for res in record:print(res.name, res.extra)""" ken manager janice engineer alex director """ session.query( ).order_by(User.name.desc())
  • GROUP BY
    record = session.query(func.max(Users.id),func.min(Users.id),func.sum(Users.id) ).group_by(Users.name).having(func.min(Users.id) > 2).all()for res in record:print(res) session.query().group_by()
  • UNION/ UNION ALL
    q1 = session.query(Users.name).filter(Users.id > 2) q2 = session.query(Favor.nid).filter(Favor.nid > 2)# record = q1.union(q2) record = q1.union_all(q2)for res in record.all():print(res) q1.union()/union_all(q2)
  • LIKE
    # record = session.query(Users).filter(Users.name.like('j%')).all() record = session.query(Users).filter(~Users.name.like('j%')).all()for res in record:print(res.name, res.extra) session.query().filter(User.name.like())
  • LIMIT
    record = session.query(Users)[1:2] session.query()[1:2]
  • INSERT
    session.add_all([Favor(caption='red'),Favor(caption='orange'),Favor(caption='yellow'),Favor(caption='green'),Favor(caption='blue'),Favor(caption='purple') ])session.add_all([Person(name='janice',favor_id=4),Person(name='alex',favor_id=1),Person(name='kennith',favor_id=6),Person(name='peter',favor_id=3),Person(name='jennifer',favor_id=2),Person(name='winnie',favor_id=5) ]) session.add()/add_all([])
  • DELETE
    session.query(Users).filter(Users.id > 2).delete() session.query().delete()
  • UPDATE
    session.query(Users).filter(Users.id > 2).update({"name":"updated_kennith"}) session.query(Users).filter(Users.id > 2).update({Users.name: Users.name + "_100"}, synchronize_session=False) session.query(Users).filter(Users.id > 2).update({"id": Users.id + 100}, synchronize_session="evaluate") session.query().update()
  • SELECT
    record = session.query(Users) #可以查看原生 SQL 語句 record = session.query(Users).all() # 返回的是Users object對象 record = session.query(Users.name, Users.extra).all() # 返回的是Users.name 和 Users.extra 的內容,因為Users.name, Users.extra作為參數傳入了 query() record = session.query(Users).filter_by(name='alex').all() # 返回的是一個可迭代的對象 e.g.for res in record; print(res.name) record = session.query(Users).filter_by(name='alex').first() # 返回的是Users.name 和 Users.extra 的內容 session.query().first()/all()
  • INNER JOIN / LEFT OUTER JOIN
    record = session.query(Favor, Person).filter(Person.favor_id==Favor.nid).all() for res in record:print(res[0], res[1].name)record = session.query(Person.name,Favor.caption).join(Favor).all() record = session.query(Person).join(Favor, isouter=True) print(record) session.query().join()/.join(isouter=True)
  • SUM/ MIN/ MAX
    record = session.query(func.max(Users.id),func.min(Users.id),func.sum(Users.id) ).group_by(Users.name).having(func.min(Users.id) > 2).all()for res in record:print(res)""" (3, 3, Decimal('3')) """ SUM/ MIN/ MAX
  • ?

    數據分析例子

    現在我會用我上一章的那個數據模型來回答以下問題,這是一個記錄了每個用戶購買了那些貨品的一張數據表,還有記錄了購買了多少件數和每件貨品的價格是多少。


    第一步是在數據庫上創建以上的表,分別是產品,人和銷售表。產品表記錄了一些產品名稱和產品類型; 人表記錄了購買人的名稱和年齡;銷售表完整的記錄了誰買了什么、買了多少產品和產品的價格是多少、等等...現在會使用 Python 的 SQLAlchemy 去完成所有的工作,而不是用原生 SQL 去做。

  • 第一步:創建產品,人和銷售表的表
    from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import Column, Integer, String, ForeignKey, UniqueConstraint, Index from sqlalchemy.orm import sessionmaker, relationship from sqlalchemy import create_engine# 創建連接 engine = create_engine('mysql+pymysql://myuser:mypass@172.16.201.134:3306/s13?',max_overflow = 5,pool_recycle=3600)Base = declarative_base()class Person(Base):__tablename__ = 'dm_person'sid = Column(Integer, primary_key=True, autoincrement=True)name = Column(String(10), unique=True, nullable=False)age = Column(Integer, nullable=False)class Product(Base):__tablename__ = 'dm_product'sid = Column(Integer, primary_key=True, autoincrement=True)product_name = Column(String(50), unique=True, nullable=False)product_category = Column(String(50), nullable=False)class Sales(Base):__tablename__ = 'fct_sales'sid = Column(Integer, primary_key=True, autoincrement=True)person_sid = Column(Integer, ForeignKey("dm_person.sid"),nullable=False)product_sid = Column(Integer, ForeignKey("dm_product.sid"),nullable=False)unit_price = Column(Integer, nullable=True)qty = Column(Integer, nullable=True)person = relationship("Person","lkp_sales")product = relationship("Product","lkp_sales") 創建表ORM模型
  • 第二步:創建一個 session 來進行數據操作
    Session = sessionmaker(bind=engine) session = Session() # blablabla... session.commit() Session = sessionmaker(bind=engine)
  • 第三步:插入一些測試數據,此時,我會調用剛才學的 session.add_all( )方法
    def data_init():# 創建連接Session = sessionmaker(bind=engine)session = Session()# 初始化插入數據 - Person Table session.add_all([Person(name='janice', age=22),Person(name='alex', age=33),Person(name='ken', age=30),Person(name='peter', age=28),Person(name='david', age=23),Person(name='ziv', age=25),Person(name='ronald', age=21),Person(name='kenny', age=36)])# 初始化插入數據 - Product Table session.add_all([Product(product_name='iPhone 6S', product_category='Electronic'),Product(product_name='iPhone 7', product_category='Electronic'),Product(product_name='XiaoMi 5', product_category='Electronic'),Product(product_name='Samsung Note 7', product_category='Electronic'),Product(product_name='Programming in Python', product_category='Books'),Product(product_name='Python In Action', product_category='Books'),Product(product_name='Shakespeare', product_category='Books'),Product(product_name='Coconut Water', product_category='Foods and Drinks'),Product(product_name='Coffe', product_category='Foods and Drinks'),Product(product_name='Bike', product_category='Automobile'),Product(product_name='Tesla Model X', product_category='Automobile')])# SQL commit session.commit()data_init() session.add( )/ add_all( )函數例子
  • 數據準備好了,現在可以嘗試回答問題啦!

  • 問題一:我想知道這商店有什么產品,可以調用 session.query( ) 去查詢 print("問題一:我想知道這商店有什么產品?") Session = sessionmaker(bind=engine) session = Session()record = session.query(Product.product_name, Product.product_category).all()print("\n答: 這商店有以下產品:") for row in enumerate(record,1):print('{}. {}'.format(row[0],row[1][0]))# record = session.query(Product).all() # for r in enumerate(record, 1): # print('{}. {}'.format(r[0],r[1].product_name)) session.commit()""" 問題一:我想知道這商店有什么產品?答: 這商店有以下產品: 1. iPhone 6S 2. iPhone 7 3. XiaoMi 5 4. Samsung Note 7 5. Programming in Python 6. Python In Action 7. Shakespeare 8. Coconut Water 9. Coffe 10. Bike 11. Tesla Model X """ session.query( )函數例子
  • 問題二:我想知道這商店有什么"電子產品"可以賣 (提示:Electronic)?
    print("問題二:我想知道這商店有什么'電子產品'可以賣") Session = sessionmaker(bind=engine) session = Session()# record = session.query(Product).filter_by(product_category = 'Electronic').all() record = session.query(Product).filter(Product.product_category == 'Electronic').all()print("\n答: 這商店有以下電子產品:") for row in enumerate(record,1):print('{}. {}'.format(row[0],row[1].product_name))session.commit()""" 問題二:我想知道這商店有什么'電子產品'可以賣答: 這商店有以下電子產品: 1. iPhone 6S 2. iPhone 7 3. XiaoMi 5 4. Samsung Note 7 """ session.query( ).filter( )/ filter_by( )函數例子
  • 問題三:我想知道 janice 買了什么東西
    print("問題三:我想知道 janice 買了什么東西") Session = sessionmaker(bind=engine) session = Session()#method1 record = session.query(Product.product_name).filter(Sales.person_sid==Person.sid, Sales.product_sid==Product.sid, Person.name == 'janice').all()print("\n答: janice 買了以下東西:") for row in enumerate(record,1):print('{}. {}'.format(row[0],row[1].product_name))session.commit()""" 問題三:我想知道 janice 買了什么東西答: janice 買了以下東西: 1. Shakespeare 2. Coffe 3. Samsung Note 7 4. Tesla Model X 5. iPhone 7 6. XiaoMi 5 7. Coconut Water 8. Python In Action """ 表關聯和filter( )函數例子
  • 問題四:我想知道 janice 總共花費了多少錢
    print("問題四:我想知道 janice 總共花費了多少錢") Session = sessionmaker(bind=engine) session = Session()from sqlalchemy.sql import funcrecord = session.query(func.sum(Sales.unit_price * Sales.qty) ).filter(Sales.person_sid==Person.sid,Sales.product_sid==Product.sid,Person.name == 'janice').group_by(Person.name).all()print("\n答: janice 總共花費了 ${}".format(record[0][0]))session.commit() """ 問題四:我想知道 janice 總共花費了多少錢 答: janice 總共花費了 $880595""" 表關聯, sum(), group_by()和filter( )函數例子
  • 問題五:我想知道每個用戶總共花費了多少錢,以花費最多的排序
    print("問題五:我想知道每個用戶總共花費了多少錢,以花費最多的排序") Session = sessionmaker(bind=engine) session = Session()from sqlalchemy.sql import funcrecord = session.query(Person.name,func.sum(Sales.unit_price * Sales.qty) ).filter(Sales.person_sid==Person.sid,Sales.product_sid==Product.sid).group_by(Person.name).order_by(func.sum(Sales.unit_price * Sales.qty).desc()).all()for row in enumerate(record,1):print('第{}名: {},總共花費了 ${}元'.format(row[0],row[1][0],row[1][1]))session.commit()""" 問題五:我想知道每個用戶總共花費了多少錢,以花費最多的排序第1名: janice,總共花費了 $880595元 第2名: peter,總共花費了 $820101元 第3名: alex,總共花費了 $97684元 第4名: ken,總共花費了 $97126元 """ 表關聯, sum(), group_by(), order_by()和filter( )函數例子
  • 問題六:我想知道誰買了 Tesla 又買了一個小米手機
    print("問題六:我想知道誰買了 Tesla 又買了一個小米手機") Session = sessionmaker(bind=engine) session = Session()from sqlalchemy import and_, or_, distinctrecord = session.query(distinct(Person.name,)).\filter(Sales.person_sid==Person.sid,Sales.product_sid==Product.sid).\filter(Product.product_name.in_(['Tesla Model X','XiaoMi 5'])).all()print("買了 Tesla 又買了一個小米手機是:") ret = [row[0] for row in record] print(ret)""" 問題六:我想知道誰買了 Tesla 又買了一個小米手機 買了 Tesla 又買了一個小米手機是: ['janice', 'peter', 'ken'] """ 表關聯,in_(), distinct()
  • ?

    Paramiko?介紹和操作

    paramiko模塊,基于SSH用于連接遠程服務器并執行相關操作,先給大家有一個大概的概念,Paramiko 可支持以下兩種登入方法和創建三種不同的對象來完成工作:

  • 創建 SSHClient e.g. paramiko.SSHClient( ) - 用于連接遠程服務器并執行基本命令
    class SSHClient (ClosingContextManager):"""A high-level representation of a session with an SSH server. This classwraps `.Transport`, `.Channel`, and `.SFTPClient` to take care of mostaspects of authenticating and opening channels. A typical use case is::client = SSHClient()client.load_system_host_keys()client.connect('ssh.example.com')stdin, stdout, stderr = client.exec_command('ls -l')You may pass in explicit overrides for authentication and server host keychecking. The default mechanism is to try to use local key files or anSSH agent (if one is running).Instances of this class may be used as context managers... versionadded:: 1.6"""def __init__(self):"""Create a new SSHClient."""self._system_host_keys = HostKeys()self._host_keys = HostKeys()self._host_keys_filename = Noneself._log_channel = Noneself._policy = RejectPolicy()self._transport = Noneself._agent = Nonedef load_system_host_keys(self, filename=None):"""Load host keys from a system (read-only) file. Host keys read withthis method will not be saved back by `save_host_keys`.This method can be called multiple times. Each new set of host keyswill be merged with the existing set (new replacing old if there areconflicts).If ``filename`` is left as ``None``, an attempt will be made to readkeys from the user's local "known hosts" file, as used by OpenSSH,and no exception will be raised if the file can't be read. This isprobably only useful on posix.:param str filename: the filename to read, or ``None``:raises IOError:if a filename was provided and the file could not be read"""if filename is None:# try the user's .ssh key file, and mask exceptionsfilename = os.path.expanduser('~/.ssh/known_hosts')try:self._system_host_keys.load(filename)except IOError:passreturnself._system_host_keys.load(filename)def load_host_keys(self, filename):"""Load host keys from a local host-key file. Host keys read with thismethod will be checked after keys loaded via `load_system_host_keys`,but will be saved back by `save_host_keys` (so they can be modified).The missing host key policy `.AutoAddPolicy` adds keys to this set andsaves them, when connecting to a previously-unknown server.This method can be called multiple times. Each new set of host keyswill be merged with the existing set (new replacing old if there areconflicts). When automatically saving, the last hostname is used.:param str filename: the filename to read:raises IOError: if the filename could not be read"""self._host_keys_filename = filenameself._host_keys.load(filename)def save_host_keys(self, filename):"""Save the host keys back to a file. Only the host keys loaded with`load_host_keys` (plus any added directly) will be saved -- not anyhost keys loaded with `load_system_host_keys`.:param str filename: the filename to save to:raises IOError: if the file could not be written"""# update local host keys from file (in case other SSH clients# have written to the known_hosts file meanwhile.if self._host_keys_filename is not None:self.load_host_keys(self._host_keys_filename)with open(filename, 'w') as f:for hostname, keys in self._host_keys.items():for keytype, key in keys.items():f.write('%s %s %s\n' % (hostname, keytype, key.get_base64()))def get_host_keys(self):"""Get the local `.HostKeys` object. This can be used to examine thelocal host keys or change them.:return: the local host keys as a `.HostKeys` object."""return self._host_keysdef set_log_channel(self, name):"""Set the channel for logging. The default is ``"paramiko.transport"``but it can be set to anything you want.:param str name: new channel name for logging"""self._log_channel = namedef set_missing_host_key_policy(self, policy):"""Set policy to use when connecting to servers without a known host key.Specifically:* A **policy** is an instance of a "policy class", namely some subclassof `.MissingHostKeyPolicy` such as `.RejectPolicy` (the default),`.AutoAddPolicy`, `.WarningPolicy`, or a user-created subclass... note::This method takes class **instances**, not **classes** themselves.Thus it must be called as e.g.``.set_missing_host_key_policy(WarningPolicy())`` and *not*``.set_missing_host_key_policy(WarningPolicy)``.* A host key is **known** when it appears in the client object's cachedhost keys structures (those manipulated by `load_system_host_keys`and/or `load_host_keys`).:param .MissingHostKeyPolicy policy:the policy to use when receiving a host key from apreviously-unknown server"""self._policy = policydef _families_and_addresses(self, hostname, port):"""Yield pairs of address families and addresses to try for connecting.:param str hostname: the server to connect to:param int port: the server port to connect to:returns: Yields an iterable of ``(family, address)`` tuples"""guess = Trueaddrinfos = socket.getaddrinfo(hostname, port, socket.AF_UNSPEC, socket.SOCK_STREAM)for (family, socktype, proto, canonname, sockaddr) in addrinfos:if socktype == socket.SOCK_STREAM:yield family, sockaddrguess = False# some OS like AIX don't indicate SOCK_STREAM support, so just guess. :(# We only do this if we did not get a single result marked as socktype == SOCK_STREAM.if guess:for family, _, _, _, sockaddr in addrinfos:yield family, sockaddrdef connect(self,hostname,port=SSH_PORT,username=None,password=None,pkey=None,key_filename=None,timeout=None,allow_agent=True,look_for_keys=True,compress=False,sock=None,gss_auth=False,gss_kex=False,gss_deleg_creds=True,gss_host=None,banner_timeout=None):"""Connect to an SSH server and authenticate to it. The server's host keyis checked against the system host keys (see `load_system_host_keys`)and any local host keys (`load_host_keys`). If the server's hostnameis not found in either set of host keys, the missing host key policyis used (see `set_missing_host_key_policy`). The default policy isto reject the key and raise an `.SSHException`.Authentication is attempted in the following order of priority:- The ``pkey`` or ``key_filename`` passed in (if any)- Any key we can find through an SSH agent- Any "id_rsa", "id_dsa" or "id_ecdsa" key discoverable in``~/.ssh/``- Plain username/password auth, if a password was givenIf a private key requires a password to unlock it, and a password ispassed in, that password will be used to attempt to unlock the key.:param str hostname: the server to connect to:param int port: the server port to connect to:param str username:the username to authenticate as (defaults to the current localusername):param str password:a password to use for authentication or for unlocking a private key:param .PKey pkey: an optional private key to use for authentication:param str key_filename:the filename, or list of filenames, of optional private key(s) totry for authentication:param float timeout:an optional timeout (in seconds) for the TCP connect:param bool allow_agent:set to False to disable connecting to the SSH agent:param bool look_for_keys:set to False to disable searching for discoverable private keyfiles in ``~/.ssh/``:param bool compress: set to True to turn on compression:param socket sock:an open socket or socket-like object (such as a `.Channel`) to usefor communication to the target host:param bool gss_auth:``True`` if you want to use GSS-API authentication:param bool gss_kex:Perform GSS-API Key Exchange and user authentication:param bool gss_deleg_creds: Delegate GSS-API client credentials or not:param str gss_host:The targets name in the kerberos database. default: hostname:param float banner_timeout: an optional timeout (in seconds) to waitfor the SSH banner to be presented.:raises BadHostKeyException: if the server's host key could not beverified:raises AuthenticationException: if authentication failed:raises SSHException: if there was any other error connecting orestablishing an SSH session:raises socket.error: if a socket error occurred while connecting.. versionchanged:: 1.15Added the ``banner_timeout``, ``gss_auth``, ``gss_kex``,``gss_deleg_creds`` and ``gss_host`` arguments."""if not sock:errors = {}# Try multiple possible address families (e.g. IPv4 vs IPv6)to_try = list(self._families_and_addresses(hostname, port))for af, addr in to_try:try:sock = socket.socket(af, socket.SOCK_STREAM)if timeout is not None:try:sock.settimeout(timeout)except:passretry_on_signal(lambda: sock.connect(addr))# Break out of the loop on successbreakexcept socket.error as e:# Raise anything that isn't a straight up connection error# (such as a resolution error)if e.errno not in (ECONNREFUSED, EHOSTUNREACH):raise# Capture anything else so we know how the run looks once# iteration is complete. Retain info about which attempt# this was.errors[addr] = e# Make sure we explode usefully if no address family attempts# succeeded. We've no way of knowing which error is the "right"# one, so we construct a hybrid exception containing all the real# ones, of a subclass that client code should still be watching for# (socket.error)if len(errors) == len(to_try):raise NoValidConnectionsError(errors)t = self._transport = Transport(sock, gss_kex=gss_kex, gss_deleg_creds=gss_deleg_creds)t.use_compression(compress=compress)if gss_kex and gss_host is None:t.set_gss_host(hostname)elif gss_kex and gss_host is not None:t.set_gss_host(gss_host)else:passif self._log_channel is not None:t.set_log_channel(self._log_channel)if banner_timeout is not None:t.banner_timeout = banner_timeoutt.start_client()ResourceManager.register(self, t)server_key = t.get_remote_server_key()keytype = server_key.get_name()if port == SSH_PORT:server_hostkey_name = hostnameelse:server_hostkey_name = "[%s]:%d" % (hostname, port)# If GSS-API Key Exchange is performed we are not required to check the# host key, because the host is authenticated via GSS-API / SSPI as# well as our client.if not self._transport.use_gss_kex:our_server_key = self._system_host_keys.get(server_hostkey_name,{}).get(keytype, None)if our_server_key is None:our_server_key = self._host_keys.get(server_hostkey_name,{}).get(keytype, None)if our_server_key is None:# will raise exception if the key is rejected; let that fall out self._policy.missing_host_key(self, server_hostkey_name,server_key)# if the callback returns, assume the key is okour_server_key = server_keyif server_key != our_server_key:raise BadHostKeyException(hostname, server_key, our_server_key)if username is None:username = getpass.getuser()if key_filename is None:key_filenames = []elif isinstance(key_filename, string_types):key_filenames = [key_filename]else:key_filenames = key_filenameif gss_host is None:gss_host = hostnameself._auth(username, password, pkey, key_filenames, allow_agent,look_for_keys, gss_auth, gss_kex, gss_deleg_creds, gss_host)def close(self):"""Close this SSHClient and its underlying `.Transport`... warning::Failure to do this may, in some situations, cause your Pythoninterpreter to hang at shutdown (often due to race conditions).It's good practice to `close` your client objects anytime you'redone using them, instead of relying on garbage collection."""if self._transport is None:returnself._transport.close()self._transport = Noneif self._agent is not None:self._agent.close()self._agent = Nonedef exec_command(self, command, bufsize=-1, timeout=None, get_pty=False):"""Execute a command on the SSH server. A new `.Channel` is opened andthe requested command is executed. The command's input and outputstreams are returned as Python ``file``-like objects representingstdin, stdout, and stderr.:param str command: the command to execute:param int bufsize:interpreted the same way as by the built-in ``file()`` function inPython:param int timeout:set command's channel timeout. See `Channel.settimeout`.settimeout:return:the stdin, stdout, and stderr of the executing command, as a3-tuple:raises SSHException: if the server fails to execute the command"""chan = self._transport.open_session(timeout=timeout)if get_pty:chan.get_pty()chan.settimeout(timeout)chan.exec_command(command)stdin = chan.makefile('wb', bufsize)stdout = chan.makefile('r', bufsize)stderr = chan.makefile_stderr('r', bufsize)return stdin, stdout, stderrdef invoke_shell(self, term='vt100', width=80, height=24, width_pixels=0,height_pixels=0):"""Start an interactive shell session on the SSH server. A new `.Channel`is opened and connected to a pseudo-terminal using the requestedterminal type and size.:param str term:the terminal type to emulate (for example, ``"vt100"``):param int width: the width (in characters) of the terminal window:param int height: the height (in characters) of the terminal window:param int width_pixels: the width (in pixels) of the terminal window:param int height_pixels: the height (in pixels) of the terminal window:return: a new `.Channel` connected to the remote shell:raises SSHException: if the server fails to invoke a shell"""chan = self._transport.open_session()chan.get_pty(term, width, height, width_pixels, height_pixels)chan.invoke_shell()return chandef open_sftp(self):"""Open an SFTP session on the SSH server.:return: a new `.SFTPClient` session object"""return self._transport.open_sftp_client()def get_transport(self):"""Return the underlying `.Transport` object for this SSH connection.This can be used to perform lower-level tasks, like opening specifickinds of channels.:return: the `.Transport` for this connection"""return self._transportdef _auth(self, username, password, pkey, key_filenames, allow_agent,look_for_keys, gss_auth, gss_kex, gss_deleg_creds, gss_host):"""Try, in order:- The key passed in, if one was passed in.- Any key we can find through an SSH agent (if allowed).- Any "id_rsa", "id_dsa" or "id_ecdsa" key discoverable in ~/.ssh/(if allowed).- Plain username/password auth, if a password was given.(The password might be needed to unlock a private key, or fortwo-factor authentication [for which it is required].)"""saved_exception = Nonetwo_factor = Falseallowed_types = set()two_factor_types = set(['keyboard-interactive','password'])# If GSS-API support and GSS-PI Key Exchange was performed, we attempt# authentication with gssapi-keyex.if gss_kex and self._transport.gss_kex_used:try:self._transport.auth_gssapi_keyex(username)returnexcept Exception as e:saved_exception = e# Try GSS-API authentication (gssapi-with-mic) only if GSS-API Key# Exchange is not performed, because if we use GSS-API for the key# exchange, there is already a fully established GSS-API context, so# why should we do that again?if gss_auth:try:self._transport.auth_gssapi_with_mic(username, gss_host,gss_deleg_creds)returnexcept Exception as e:saved_exception = eif pkey is not None:try:self._log(DEBUG, 'Trying SSH key %s' % hexlify(pkey.get_fingerprint()))allowed_types = set(self._transport.auth_publickey(username, pkey))two_factor = (allowed_types & two_factor_types)if not two_factor:returnexcept SSHException as e:saved_exception = eif not two_factor:for key_filename in key_filenames:for pkey_class in (RSAKey, DSSKey, ECDSAKey):try:key = pkey_class.from_private_key_file(key_filename, password)self._log(DEBUG, 'Trying key %s from %s' % (hexlify(key.get_fingerprint()), key_filename))allowed_types = set(self._transport.auth_publickey(username, key))two_factor = (allowed_types & two_factor_types)if not two_factor:returnbreakexcept SSHException as e:saved_exception = eif not two_factor and allow_agent:if self._agent is None:self._agent = Agent()for key in self._agent.get_keys():try:self._log(DEBUG, 'Trying SSH agent key %s' % hexlify(key.get_fingerprint()))# for 2-factor auth a successfully auth'd key password will return an allowed 2fac auth methodallowed_types = set(self._transport.auth_publickey(username, key))two_factor = (allowed_types & two_factor_types)if not two_factor:returnbreakexcept SSHException as e:saved_exception = eif not two_factor:keyfiles = []rsa_key = os.path.expanduser('~/.ssh/id_rsa')dsa_key = os.path.expanduser('~/.ssh/id_dsa')ecdsa_key = os.path.expanduser('~/.ssh/id_ecdsa')if os.path.isfile(rsa_key):keyfiles.append((RSAKey, rsa_key))if os.path.isfile(dsa_key):keyfiles.append((DSSKey, dsa_key))if os.path.isfile(ecdsa_key):keyfiles.append((ECDSAKey, ecdsa_key))# look in ~/ssh/ for windows users:rsa_key = os.path.expanduser('~/ssh/id_rsa')dsa_key = os.path.expanduser('~/ssh/id_dsa')ecdsa_key = os.path.expanduser('~/ssh/id_ecdsa')if os.path.isfile(rsa_key):keyfiles.append((RSAKey, rsa_key))if os.path.isfile(dsa_key):keyfiles.append((DSSKey, dsa_key))if os.path.isfile(ecdsa_key):keyfiles.append((ECDSAKey, ecdsa_key))if not look_for_keys:keyfiles = []for pkey_class, filename in keyfiles:try:key = pkey_class.from_private_key_file(filename, password)self._log(DEBUG, 'Trying discovered key %s in %s' % (hexlify(key.get_fingerprint()), filename))# for 2-factor auth a successfully auth'd key will result in ['password']allowed_types = set(self._transport.auth_publickey(username, key))two_factor = (allowed_types & two_factor_types)if not two_factor:returnbreakexcept (SSHException, IOError) as e:saved_exception = eif password is not None:try:self._transport.auth_password(username, password)returnexcept SSHException as e:saved_exception = eelif two_factor:try:self._transport.auth_interactive_dumb(username)returnexcept SSHException as e:saved_exception = e# if we got an auth-failed exception earlier, re-raise itif saved_exception is not None:raise saved_exceptionraise SSHException('No authentication methods available')def _log(self, level, msg):self._transport._log(level, msg) class SSHClient( )源碼
    • 基于用戶名密碼連接
    • 基于公鑰密鑰連接
  • 創建 SFTPClient e.g. paramiko.SFTPClient.from_transport(transport)?- 用于連接遠程服務器并執行上傳下載
    class SFTPClient(BaseSFTP, ClosingContextManager):"""SFTP client object.Used to open an SFTP session across an open SSH `.Transport` and performremote file operations.Instances of this class may be used as context managers."""def __init__(self, sock):"""Create an SFTP client from an existing `.Channel`. The channelshould already have requested the ``"sftp"`` subsystem.An alternate way to create an SFTP client context is by using`from_transport`.:param .Channel sock: an open `.Channel` using the ``"sftp"`` subsystem:raises SSHException: if there's an exception while negotiatingsftp"""BaseSFTP.__init__(self)self.sock = sockself.ultra_debug = Falseself.request_number = 1# lock for request_numberself._lock = threading.Lock()self._cwd = None# request # -> SFTPFileself._expecting = weakref.WeakValueDictionary()if type(sock) is Channel:# override default loggertransport = self.sock.get_transport()self.logger = util.get_logger(transport.get_log_channel() + '.sftp')self.ultra_debug = transport.get_hexdump()try:server_version = self._send_version()except EOFError:raise SSHException('EOF during negotiation')self._log(INFO, 'Opened sftp connection (server version %d)' % server_version)@classmethoddef from_transport(cls, t, window_size=None, max_packet_size=None):"""Create an SFTP client channel from an open `.Transport`.Setting the window and packet sizes might affect the transfer speed.The default settings in the `.Transport` class are the same as inOpenSSH and should work adequately for both files transfers andinteractive sessions.:param .Transport t: an open `.Transport` which is already authenticated:param int window_size:optional window size for the `.SFTPClient` session.:param int max_packet_size:optional max packet size for the `.SFTPClient` session..:return:a new `.SFTPClient` object, referring to an sftp session (channel)across the transport.. versionchanged:: 1.15Added the ``window_size`` and ``max_packet_size`` arguments."""chan = t.open_session(window_size=window_size,max_packet_size=max_packet_size)if chan is None:return Nonechan.invoke_subsystem('sftp')return cls(chan)def _log(self, level, msg, *args):if isinstance(msg, list):for m in msg:self._log(level, m, *args)else:# escape '%' in msg (they could come from file or directory names) before loggingmsg = msg.replace('%','%%')super(SFTPClient, self)._log(level, "[chan %s] " + msg, *([self.sock.get_name()] + list(args)))def close(self):"""Close the SFTP session and its underlying channel... versionadded:: 1.4"""self._log(INFO, 'sftp session closed.')self.sock.close()def get_channel(self):"""Return the underlying `.Channel` object for this SFTP session. Thismight be useful for doing things like setting a timeout on the channel... versionadded:: 1.7.1"""return self.sockdef listdir(self, path='.'):"""Return a list containing the names of the entries in the given ``path``.The list is in arbitrary order. It does not include the specialentries ``'.'`` and ``'..'`` even if they are present in the folder.This method is meant to mirror ``os.listdir`` as closely as possible.For a list of full `.SFTPAttributes` objects, see `listdir_attr`.:param str path: path to list (defaults to ``'.'``)"""return [f.filename for f in self.listdir_attr(path)]def listdir_attr(self, path='.'):"""Return a list containing `.SFTPAttributes` objects corresponding tofiles in the given ``path``. The list is in arbitrary order. It doesnot include the special entries ``'.'`` and ``'..'`` even if they arepresent in the folder.The returned `.SFTPAttributes` objects will each have an additionalfield: ``longname``, which may contain a formatted string of the file'sattributes, in unix format. The content of this string will probablydepend on the SFTP server implementation.:param str path: path to list (defaults to ``'.'``):return: list of `.SFTPAttributes` objects.. versionadded:: 1.2"""path = self._adjust_cwd(path)self._log(DEBUG, 'listdir(%r)' % path)t, msg = self._request(CMD_OPENDIR, path)if t != CMD_HANDLE:raise SFTPError('Expected handle')handle = msg.get_binary()filelist = []while True:try:t, msg = self._request(CMD_READDIR, handle)except EOFError:# done with handlebreakif t != CMD_NAME:raise SFTPError('Expected name response')count = msg.get_int()for i in range(count):filename = msg.get_text()longname = msg.get_text()attr = SFTPAttributes._from_msg(msg, filename, longname)if (filename != '.') and (filename != '..'):filelist.append(attr)self._request(CMD_CLOSE, handle)return filelistdef listdir_iter(self, path='.', read_aheads=50):"""Generator version of `.listdir_attr`.See the API docs for `.listdir_attr` for overall details.This function adds one more kwarg on top of `.listdir_attr`:``read_aheads``, an integer controlling how many``SSH_FXP_READDIR`` requests are made to the server. The default of 50should suffice for most file listings as each request/response cyclemay contain multiple files (dependant on server implementation.).. versionadded:: 1.15"""path = self._adjust_cwd(path)self._log(DEBUG, 'listdir(%r)' % path)t, msg = self._request(CMD_OPENDIR, path)if t != CMD_HANDLE:raise SFTPError('Expected handle')handle = msg.get_string()nums = list()while True:try:# Send out a bunch of readdir requests so that we can read the# responses later on Section 6.7 of the SSH file transfer RFC# explains this# http://filezilla-project.org/specs/draft-ietf-secsh-filexfer-02.txtfor i in range(read_aheads):num = self._async_request(type(None), CMD_READDIR, handle)nums.append(num)# For each of our sent requests# Read and parse the corresponding packets# If we're at the end of our queued requests, then fire off# some more requests# Exit the loop when we've reached the end of the directory# handlefor num in nums:t, pkt_data = self._read_packet()msg = Message(pkt_data)new_num = msg.get_int()if num == new_num:if t == CMD_STATUS:self._convert_status(msg)count = msg.get_int()for i in range(count):filename = msg.get_text()longname = msg.get_text()attr = SFTPAttributes._from_msg(msg, filename, longname)if (filename != '.') and (filename != '..'):yield attr# If we've hit the end of our queued requests, reset nums.nums = list()except EOFError:self._request(CMD_CLOSE, handle)returndef open(self, filename, mode='r', bufsize=-1):"""Open a file on the remote server. The arguments are the same as forPython's built-in `python:file` (aka `python:open`). A file-likeobject is returned, which closely mimics the behavior of a normalPython file object, including the ability to be used as a contextmanager.The mode indicates how the file is to be opened: ``'r'`` for reading,``'w'`` for writing (truncating an existing file), ``'a'`` forappending, ``'r+'`` for reading/writing, ``'w+'`` for reading/writing(truncating an existing file), ``'a+'`` for reading/appending. ThePython ``'b'`` flag is ignored, since SSH treats all files as binary.The ``'U'`` flag is supported in a compatible way.Since 1.5.2, an ``'x'`` flag indicates that the operation should onlysucceed if the file was created and did not previously exist. This hasno direct mapping to Python's file flags, but is commonly known as the``O_EXCL`` flag in posix.The file will be buffered in standard Python style by default, butcan be altered with the ``bufsize`` parameter. ``0`` turns offbuffering, ``1`` uses line buffering, and any number greater than 1(``>1``) uses that specific buffer size.:param str filename: name of the file to open:param str mode: mode (Python-style) to open in:param int bufsize: desired buffering (-1 = default buffer size):return: an `.SFTPFile` object representing the open file:raises IOError: if the file could not be opened."""filename = self._adjust_cwd(filename)self._log(DEBUG, 'open(%r, %r)' % (filename, mode))imode = 0if ('r' in mode) or ('+' in mode):imode |= SFTP_FLAG_READif ('w' in mode) or ('+' in mode) or ('a' in mode):imode |= SFTP_FLAG_WRITEif 'w' in mode:imode |= SFTP_FLAG_CREATE | SFTP_FLAG_TRUNCif 'a' in mode:imode |= SFTP_FLAG_CREATE | SFTP_FLAG_APPENDif 'x' in mode:imode |= SFTP_FLAG_CREATE | SFTP_FLAG_EXCLattrblock = SFTPAttributes()t, msg = self._request(CMD_OPEN, filename, imode, attrblock)if t != CMD_HANDLE:raise SFTPError('Expected handle')handle = msg.get_binary()self._log(DEBUG, 'open(%r, %r) -> %s' % (filename, mode, hexlify(handle)))return SFTPFile(self, handle, mode, bufsize)# Python continues to vacillate about "open" vs "file"...file = opendef remove(self, path):"""Remove the file at the given path. This only works on files; forremoving folders (directories), use `rmdir`.:param str path: path (absolute or relative) of the file to remove:raises IOError: if the path refers to a folder (directory)"""path = self._adjust_cwd(path)self._log(DEBUG, 'remove(%r)' % path)self._request(CMD_REMOVE, path)unlink = removedef rename(self, oldpath, newpath):"""Rename a file or folder from ``oldpath`` to ``newpath``.:param str oldpath: existing name of the file or folder:param str newpath: new name for the file or folder:raises IOError: if ``newpath`` is a folder, or something else goeswrong"""oldpath = self._adjust_cwd(oldpath)newpath = self._adjust_cwd(newpath)self._log(DEBUG, 'rename(%r, %r)' % (oldpath, newpath))self._request(CMD_RENAME, oldpath, newpath)def mkdir(self, path, mode=o777):"""Create a folder (directory) named ``path`` with numeric mode ``mode``.The default mode is 0777 (octal). On some systems, mode is ignored.Where it is used, the current umask value is first masked out.:param str path: name of the folder to create:param int mode: permissions (posix-style) for the newly-created folder"""path = self._adjust_cwd(path)self._log(DEBUG, 'mkdir(%r, %r)' % (path, mode))attr = SFTPAttributes()attr.st_mode = modeself._request(CMD_MKDIR, path, attr)def rmdir(self, path):"""Remove the folder named ``path``.:param str path: name of the folder to remove"""path = self._adjust_cwd(path)self._log(DEBUG, 'rmdir(%r)' % path)self._request(CMD_RMDIR, path)def stat(self, path):"""Retrieve information about a file on the remote system. The returnvalue is an object whose attributes correspond to the attributes ofPython's ``stat`` structure as returned by ``os.stat``, except that itcontains fewer fields. An SFTP server may return as much or as littleinfo as it wants, so the results may vary from server to server.Unlike a Python `python:stat` object, the result may not be accessed asa tuple. This is mostly due to the author's slack factor.The fields supported are: ``st_mode``, ``st_size``, ``st_uid``,``st_gid``, ``st_atime``, and ``st_mtime``.:param str path: the filename to stat:return:an `.SFTPAttributes` object containing attributes about the givenfile"""path = self._adjust_cwd(path)self._log(DEBUG, 'stat(%r)' % path)t, msg = self._request(CMD_STAT, path)if t != CMD_ATTRS:raise SFTPError('Expected attributes')return SFTPAttributes._from_msg(msg)def lstat(self, path):"""Retrieve information about a file on the remote system, withoutfollowing symbolic links (shortcuts). This otherwise behaves exactlythe same as `stat`.:param str path: the filename to stat:return:an `.SFTPAttributes` object containing attributes about the givenfile"""path = self._adjust_cwd(path)self._log(DEBUG, 'lstat(%r)' % path)t, msg = self._request(CMD_LSTAT, path)if t != CMD_ATTRS:raise SFTPError('Expected attributes')return SFTPAttributes._from_msg(msg)def symlink(self, source, dest):"""Create a symbolic link (shortcut) of the ``source`` path at``destination``.:param str source: path of the original file:param str dest: path of the newly created symlink"""dest = self._adjust_cwd(dest)self._log(DEBUG, 'symlink(%r, %r)' % (source, dest))source = bytestring(source)self._request(CMD_SYMLINK, source, dest)def chmod(self, path, mode):"""Change the mode (permissions) of a file. The permissions areunix-style and identical to those used by Python's `os.chmod`function.:param str path: path of the file to change the permissions of:param int mode: new permissions"""path = self._adjust_cwd(path)self._log(DEBUG, 'chmod(%r, %r)' % (path, mode))attr = SFTPAttributes()attr.st_mode = modeself._request(CMD_SETSTAT, path, attr)def chown(self, path, uid, gid):"""Change the owner (``uid``) and group (``gid``) of a file. As withPython's `os.chown` function, you must pass both arguments, so if youonly want to change one, use `stat` first to retrieve the currentowner and group.:param str path: path of the file to change the owner and group of:param int uid: new owner's uid:param int gid: new group id"""path = self._adjust_cwd(path)self._log(DEBUG, 'chown(%r, %r, %r)' % (path, uid, gid))attr = SFTPAttributes()attr.st_uid, attr.st_gid = uid, gidself._request(CMD_SETSTAT, path, attr)def utime(self, path, times):"""Set the access and modified times of the file specified by ``path``. If``times`` is ``None``, then the file's access and modified times are setto the current time. Otherwise, ``times`` must be a 2-tuple of numbers,of the form ``(atime, mtime)``, which is used to set the access andmodified times, respectively. This bizarre API is mimicked from Pythonfor the sake of consistency -- I apologize.:param str path: path of the file to modify:param tuple times:``None`` or a tuple of (access time, modified time) in standardinternet epoch time (seconds since 01 January 1970 GMT)"""path = self._adjust_cwd(path)if times is None:times = (time.time(), time.time())self._log(DEBUG, 'utime(%r, %r)' % (path, times))attr = SFTPAttributes()attr.st_atime, attr.st_mtime = timesself._request(CMD_SETSTAT, path, attr)def truncate(self, path, size):"""Change the size of the file specified by ``path``. This usuallyextends or shrinks the size of the file, just like the `~file.truncate`method on Python file objects.:param str path: path of the file to modify:param size: the new size of the file:type size: int or long"""path = self._adjust_cwd(path)self._log(DEBUG, 'truncate(%r, %r)' % (path, size))attr = SFTPAttributes()attr.st_size = sizeself._request(CMD_SETSTAT, path, attr)def readlink(self, path):"""Return the target of a symbolic link (shortcut). You can use`symlink` to create these. The result may be either an absolute orrelative pathname.:param str path: path of the symbolic link file:return: target path, as a `str`"""path = self._adjust_cwd(path)self._log(DEBUG, 'readlink(%r)' % path)t, msg = self._request(CMD_READLINK, path)if t != CMD_NAME:raise SFTPError('Expected name response')count = msg.get_int()if count == 0:return Noneif count != 1:raise SFTPError('Readlink returned %d results' % count)return _to_unicode(msg.get_string())def normalize(self, path):"""Return the normalized path (on the server) of a given path. Thiscan be used to quickly resolve symbolic links or determine what theserver is considering to be the "current folder" (by passing ``'.'``as ``path``).:param str path: path to be normalized:return: normalized form of the given path (as a `str`):raises IOError: if the path can't be resolved on the server"""path = self._adjust_cwd(path)self._log(DEBUG, 'normalize(%r)' % path)t, msg = self._request(CMD_REALPATH, path)if t != CMD_NAME:raise SFTPError('Expected name response')count = msg.get_int()if count != 1:raise SFTPError('Realpath returned %d results' % count)return msg.get_text()def chdir(self, path=None):"""Change the "current directory" of this SFTP session. Since SFTPdoesn't really have the concept of a current working directory, this isemulated by Paramiko. Once you use this method to set a workingdirectory, all operations on this `.SFTPClient` object will be relativeto that path. You can pass in ``None`` to stop using a current workingdirectory.:param str path: new current working directory:raises IOError: if the requested path doesn't exist on the server.. versionadded:: 1.4"""if path is None:self._cwd = Nonereturnif not stat.S_ISDIR(self.stat(path).st_mode):raise SFTPError(errno.ENOTDIR, "%s: %s" % (os.strerror(errno.ENOTDIR), path))self._cwd = b(self.normalize(path))def getcwd(self):"""Return the "current working directory" for this SFTP session, asemulated by Paramiko. If no directory has been set with `chdir`,this method will return ``None``... versionadded:: 1.4"""# TODO: make class initialize with self._cwd set to self.normalize('.')return self._cwd and u(self._cwd)def _transfer_with_callback(self, reader, writer, file_size, callback):size = 0while True:data = reader.read(32768)writer.write(data)size += len(data)if len(data) == 0:breakif callback is not None:callback(size, file_size)return sizedef putfo(self, fl, remotepath, file_size=0, callback=None, confirm=True):"""Copy the contents of an open file object (``fl``) to the SFTP server as``remotepath``. Any exception raised by operations will be passedthrough.The SFTP operations use pipelining for speed.:param fl: opened file or file-like object to copy:param str remotepath: the destination path on the SFTP server:param int file_size:optional size parameter passed to callback. If none is specified,size defaults to 0:param callable callback:optional callback function (form: ``func(int, int)``) that acceptsthe bytes transferred so far and the total bytes to be transferred(since 1.7.4):param bool confirm:whether to do a stat() on the file afterwards to confirm the filesize (since 1.7.7):return:an `.SFTPAttributes` object containing attributes about the givenfile... versionadded:: 1.10"""with self.file(remotepath, 'wb') as fr:fr.set_pipelined(True)size = self._transfer_with_callback(reader=fl, writer=fr, file_size=file_size, callback=callback)if confirm:s = self.stat(remotepath)if s.st_size != size:raise IOError('size mismatch in put! %d != %d' % (s.st_size, size))else:s = SFTPAttributes()return sdef put(self, localpath, remotepath, callback=None, confirm=True):"""Copy a local file (``localpath``) to the SFTP server as ``remotepath``.Any exception raised by operations will be passed through. Thismethod is primarily provided as a convenience.The SFTP operations use pipelining for speed.:param str localpath: the local file to copy:param str remotepath: the destination path on the SFTP server. Notethat the filename should be included. Only specifying a directorymay result in an error.:param callable callback:optional callback function (form: ``func(int, int)``) that acceptsthe bytes transferred so far and the total bytes to be transferred:param bool confirm:whether to do a stat() on the file afterwards to confirm the filesize:return: an `.SFTPAttributes` object containing attributes about the given file.. versionadded:: 1.4.. versionchanged:: 1.7.4``callback`` and rich attribute return value added... versionchanged:: 1.7.7``confirm`` param added."""file_size = os.stat(localpath).st_sizewith open(localpath, 'rb') as fl:return self.putfo(fl, remotepath, file_size, callback, confirm)def getfo(self, remotepath, fl, callback=None):"""Copy a remote file (``remotepath``) from the SFTP server and write toan open file or file-like object, ``fl``. Any exception raised byoperations will be passed through. This method is primarily providedas a convenience.:param object remotepath: opened file or file-like object to copy to:param str fl:the destination path on the local host or open file object:param callable callback:optional callback function (form: ``func(int, int)``) that acceptsthe bytes transferred so far and the total bytes to be transferred:return: the `number <int>` of bytes written to the opened file object.. versionadded:: 1.10"""file_size = self.stat(remotepath).st_sizewith self.open(remotepath, 'rb') as fr:fr.prefetch(file_size)return self._transfer_with_callback(reader=fr, writer=fl, file_size=file_size, callback=callback)return sizedef get(self, remotepath, localpath, callback=None):"""Copy a remote file (``remotepath``) from the SFTP server to the localhost as ``localpath``. Any exception raised by operations will bepassed through. This method is primarily provided as a convenience.:param str remotepath: the remote file to copy:param str localpath: the destination path on the local host:param callable callback:optional callback function (form: ``func(int, int)``) that acceptsthe bytes transferred so far and the total bytes to be transferred.. versionadded:: 1.4.. versionchanged:: 1.7.4Added the ``callback`` param"""with open(localpath, 'wb') as fl:size = self.getfo(remotepath, fl, callback)s = os.stat(localpath)if s.st_size != size:raise IOError('size mismatch in get! %d != %d' % (s.st_size, size))### internals...def _request(self, t, *arg):num = self._async_request(type(None), t, *arg)return self._read_response(num)def _async_request(self, fileobj, t, *arg):# this method may be called from other threads (prefetch) self._lock.acquire()try:msg = Message()msg.add_int(self.request_number)for item in arg:if isinstance(item, long):msg.add_int64(item)elif isinstance(item, int):msg.add_int(item)elif isinstance(item, (string_types, bytes_types)):msg.add_string(item)elif isinstance(item, SFTPAttributes):item._pack(msg)else:raise Exception('unknown type for %r type %r' % (item, type(item)))num = self.request_numberself._expecting[num] = fileobjself.request_number += 1finally:self._lock.release()self._send_packet(t, msg)return numdef _read_response(self, waitfor=None):while True:try:t, data = self._read_packet()except EOFError as e:raise SSHException('Server connection dropped: %s' % str(e))msg = Message(data)num = msg.get_int()self._lock.acquire()try:if num not in self._expecting:# might be response for a file that was closed before responses came backself._log(DEBUG, 'Unexpected response #%d' % (num,))if waitfor is None:# just doing a single checkbreakcontinuefileobj = self._expecting[num]del self._expecting[num]finally:self._lock.release()if num == waitfor:# synchronousif t == CMD_STATUS:self._convert_status(msg)return t, msgif fileobj is not type(None):fileobj._async_response(t, msg, num)if waitfor is None:# just doing a single checkbreakreturn None, Nonedef _finish_responses(self, fileobj):while fileobj in self._expecting.values():self._read_response()fileobj._check_exception()def _convert_status(self, msg):"""Raises EOFError or IOError on error status; otherwise does nothing."""code = msg.get_int()text = msg.get_text()if code == SFTP_OK:returnelif code == SFTP_EOF:raise EOFError(text)elif code == SFTP_NO_SUCH_FILE:# clever idea from john a. meinel: map the error codes to errnoraise IOError(errno.ENOENT, text)elif code == SFTP_PERMISSION_DENIED:raise IOError(errno.EACCES, text)else:raise IOError(text)def _adjust_cwd(self, path):"""Return an adjusted path if we're emulating a "current workingdirectory" for the server."""path = b(path)if self._cwd is None:return pathif len(path) and path[0:1] == b_slash:# absolute pathreturn pathif self._cwd == b_slash:return self._cwd + pathreturn self._cwd + b_slash + path class?SFTPClient( )源碼
    • 基于用戶名密碼上傳下載
    • 基于公鑰密鑰上傳下載
  • 安裝 paramiko?

    pip3 install paramiko

    操作 paramiko?

    SSHClient

  • SSHClient -?用于連接遠程服務器并執行基本命令?
    import paramikossh = paramiko.SSHClient() ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) ssh.connect(hostname='172.16.201.134', port=22, username='janice', password='janice123') stdin, stdout, stderr = ssh.exec_command('ls -la')results = stdout.read() print(results.decode()) ssh.close() paramiko.SSHClient( )密碼登入 import paramikoprivate_key = paramiko.RSAKey.from_private_key_file('/home/auto/.ssh/id_rsa')ssh = paramiko.SSHClient() ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) ssh.connect(hostname='172.16.201.134', port=22, username='user', pkey=private_key)stdin, stdout, stderr = ssh.exec_command('ls -la')results = stdout.read() print(results.decode()) ssh.close() paramiko.SSHClient( )公鑰密鑰連接
  • 創建 Transport 對象來連接
    import paramikoip_port = ('172.16.201.134',22,) transport = paramiko.Transport(ip_port) transport.connect(username='user',password='user')ssh = paramiko.SSHClient() ssh._transport = transportstdin, stdout, stderr = ssh.exec_command('df') results = stdout.read() # 獲取命令結果print(results.decode()) transport.close() paramiko.Transport(ip_port)密碼登入 import paramikoprivate_key = paramiko.RSAKey.from_private_key_file('/Users/jcchoiling/.ssh/vm.key')ip_port = ('172.16.201.134',22,) transport = paramiko.Transport(ip_port) transport.connect(username='user',pkey=private_key)ssh = paramiko.SSHClient() ssh._transport = transportstdin, stdout, stderr = ssh.exec_command('df') results = stdout.read() # 獲取命令結果print(results.decode()) transport.close() paramiko.Transport(ip_port)公鑰密鑰連接

    ?

  • SFPTClient

  • SFTPClient -?用于連接遠程服務器并執行上傳下載
    第一步:創建 transport 通道 e.g.?paramiko.Transport(ip_port)?連接對象,負責上傳文件到目標服務器端
    第二步:transport 需要連接上服務器端,輸入用戶名和密碼
    第三步:創建 SFTPClient 對象然后把 transport作為參數傳入 e.g.?paramiko.SFTPClient.from_transport(transport)
    第四步:可以調用 sftp.put/ sftp.get 方法來上傳和下載文件
    ? ? ? ??四、一)sftp.put(localfile, remotefile) 從本地上傳到遠端
    ? ? ? ??四、二)sftp.get(remotefile, localfile) 從遠端下載到本地
    第五步:關閉 transport 通道
    import paramiko ip_port = ('172.16.201.134',22,) transport = paramiko.Transport(ip_port) transport.connect(username='user',password='user')sftp = paramiko.SFTPClient.from_transport(transport) sftp.put('/Users/jcchoiling/Desktop/movies.dat','/home/user/m1.dat') sftp.get('/home/user/start.sh','/Users/jcchoiling/Desktop/start.sh')transport.close() paramiko.SFTPClient.from_transport(transport)密碼登入 import paramikoprivate_key = paramiko.RSAKey.from_private_key_file('/Users/jcchoiling/.ssh/vm.key')ip_port = ('172.16.201.134',22,) transport = paramiko.Transport(ip_port) transport.connect(username='user',pkey=private_key)sftp = paramiko.SFTPClient.from_transport(transport) sftp.put('/Users/jcchoiling/Desktop/movies.dat','/home/user/m1.dat') sftp.get('/home/user/start.sh','/Users/jcchoiling/Desktop/start.sh')transport.close() paramiko.SFTPClient.from_transport(transport)公鑰密鑰連接
  • ?

    上下文操作應用

    ?

    ?

    ?

    ?

    ?

    初探堡壘機

    ?

    ?

    ?

    ?

    ?

    本周作業

    作業:開發一個由數據庫管理的主機管理系統,主機分組、分用戶權限管理

  • 所有的用戶操作日志要保留在數據庫中
  • 每個用戶登錄堡壘機后,只需要選擇具體要訪問的設置,就連接上了,不需要再輸入目標機器的訪問密碼
  • 允許用戶對不同的目標設備有不同的訪問權限,例:
  • 對10.0.2.34 有mysql 用戶的權限
  • 對192.168.3.22 有root用戶的權限
  • 對172.33.24.55 沒任何權限
  • 分組管理,即可以對設置進行分組,允許用戶訪問某組機器,但對組里的不同機器依然有不同的訪問權限?
  • 考核題

    試說明你寫這個作業的思路:

  • 首先看到管理主機組,這表明可能會有多于一臺服務器,然后假設我是管理100臺 Hadoop 服務器的管理員。
  • 然后設計數據庫的表結構:
    • 有本地用戶 User
    • 管理組表 Groups
    • 本地用戶和組的關系表 User-Groups
    • 服務器表 Hosts
    • 遠程用戶表 RemoteUsers
    • 管理組表、遠程用戶和服務器的關系表 Hosts-Groups-RemoteUsers
    • 記錄表 Audit Log
  • 然后可以從功能方面思考:
    • 查看用戶信息
    • 創建群組
    • 創建用戶
    • 創建服務器
    • 創建遠程用戶
    • 刪除群組
    • 刪除用戶
    • 刪除服務器
    • 新增用戶到指定群組
    • 新增服務器到指定群組
    • 初始化數據庫
    • 刪除數據庫
    • 遠程連接 
  • 最后是把功能的流程關連在一起,比如說,你會想像當管理員一打開程序,第一步是什么、下一步又會是什么,這樣的思路去設計你程序的流程圖。
    • 用戶登入 (登入需要認證,可以添加登入3次鎖定帳號)
    • 登入后看到功能列表選單
    • 每一個功能用一個函數來表達
    • 當程序遇上非如期的輸入時的處理方法 (Error Handling)
    • 優雅地退出程序 (Exit program)

    [知識點:重點是如果用 Python 操作數據庫,從數據庫中讀寫數據。]

    數據庫表結構:

    ?

    程序運行結果:

    ?

    總結

    第五階段主要是學習了如何用 Python 來實現網絡編程,第一部份是介紹了基本的網絡協議,其中重點是 TCP/IP 協議,學習如何寫服務器端和客戶端的 socket,還數據可以通個 TCP/IP 來輸送和接收數據;第二部份介紹了 Python中的線程、進程和協程。然后還學了線程鎖與進程鎖;學了自定義線程池。第三部份學了消息隊列的概念,分別是 Python 內置的 Queue 功能和 RabbitMQ的功能。具體介紹了 RabbitMQ 的發布和訂閱、主題模式和 RPC 通信。第四部份學了數據庫的操作:分別是 MySQL 中的原生 SQL話句和如何用 Python 的 pymysql 來操作 MySQL 數據庫。在了這個基礎之后,便深入介紹 Python 中的 ORM,當中最具代表性的就是 SQLAlchemy?模塊,學習如何用 Python 調用?SQLAlchemy 中的功能來操作 MySQL數據庫,這是一個很有意思的單元。?

    ?

    ?

    ?

    參考資料?

    銀角大王:1)?MySQL 操作

    金角大王:1)?Python之路,Day10~11 - 那就做個堡壘機吧

         2)?python 之路,Day11 - sqlalchemy ORM

         ? 3)?金角大王教你如何做個堡壘機

    OReilly.Essential.SQLAlchemy

    ?

    轉載于:https://www.cnblogs.com/jcchoiling/p/5991551.html

    總結

    以上是生活随笔為你收集整理的第十三章:Python の 网络编程进阶(二)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    国产黄色成人 | 在线电影日韩 | 97理论电影 | 欧美日韩成人 | 欧美大片aaa| 日韩免费在线一区 | 黄色免费在线视频 | 操操操干干干 | 看毛片的网址 | 国产日韩精品欧美 | 最近中文字幕高清字幕免费mv | 免费成人在线网站 | 玖玖视频网 | 国产中文字幕视频在线观看 | 亚洲成人中文在线 | 国产不卡免费视频 | 日日夜夜干 | 久久99国产综合精品免费 | 蜜臀av性久久久久av蜜臀妖精 | 欧美激情精品久久久久久 | 成人av网站在线播放 | 久久久麻豆精品一区二区 | 欧美日韩国产在线一区 | 狠狠色2019综合网 | 久久精品视频国产 | 日韩1级片| 精品美女在线视频 | 国产一级二级在线观看 | 免费三级黄色 | 久久久国产精品网站 | av在线短片 | 久久久免费精品国产一区二区 | 久久国产精品久久久 | 99免在线观看免费视频高清 | 韩日av在线 | 久久精品电影网 | 精品视频国产一区 | 日本公妇在线观看高清 | 成人黄在线观看 | 亚洲综合在线播放 | 成人在线一区二区三区 | 一级片免费观看视频 | 日本精品久久久久中文字幕 | 亚洲日韩中文字幕在线播放 | 香蕉网在线播放 | 国产精品久久久久三级 | 久久国产高清 | 久久久高清视频 | 三三级黄色片之日韩 | 国产精品免费久久久久久久久久中文 | 91久久奴性调教 | 中文字幕第 | 免费日韩视频 | 在线观看韩日电影免费 | 免费看国产精品 | av成人在线播放 | 亚洲波多野结衣 | 玖玖玖影院 | 一区二区三区韩国免费中文网站 | 91成人免费看片 | 国产亚洲久一区二区 | 天天草天天色 | 国产二区电影 | 久久五月网| 99免费看片 | 日本黄色大片免费 | av性网站| 一二三区在线 | 亚洲一区二区三区毛片 | 999久久国产精品免费观看网站 | 午夜在线国产 | 亚洲日本精品视频 | 人人插人人干 | 天天干天天草天天爽 | 超碰97在线人人 | 中文字幕av一区二区三区四区 | 日日干天天爽 | 综合激情av | 免费av黄色| 色片网站在线观看 | 亚洲爱av | 久久人人干 | 欧美一区二视频在线免费观看 | 在线观看免费av网站 | 又黄又爽又无遮挡免费的网站 | 麻豆国产精品视频 | 日日操日日操 | 日韩中文字幕免费在线播放 | 在线观看911视频 | 亚洲精品资源在线观看 | 天天爱天天操天天干 | 天天草天天干天天射 | 一级性av | www.久久成人| 国产视频在线观看免费 | 丁香九月婷婷 | 免费在线观看亚洲视频 | 热久在线 | 三级av在线播放 | 国产人成看黄久久久久久久久 | 国产中文字幕视频在线观看 | 人人插人人玩 | 久草免费在线观看视频 | www免费视频com━ | 91精品婷婷国产综合久久蝌蚪 | 日韩啪啪小视频 | 久久久免费av | 天天干亚洲 | 亚洲精品乱码久久久一二三 | 日本黄色大片免费 | 国产日韩欧美视频在线观看 | 天天看天天操 | 91c网站色版视频 | 国产美女久久久 | 看毛片网站 | 手机在线观看国产精品 | 成人国产网站 | www激情网| 人人插人人舔 | 久草视频免费播放 | 日本公妇在线观看 | 欧美天天综合 | 日韩精品五月天 | 国产一区二区三区免费在线 | 首页中文字幕 | 色操插| 国产女教师精品久久av | 天天色天天爱天天射综合 | 色激情在线| 国产成人av免费在线观看 | 久草a在线 | 精品xxx | 亚洲精品电影在线 | 国产91精品看黄网站在线观看动漫 | av超碰在线| 国产精品久久久久久电影 | 99r在线播放 | 91完整版在线观看 | 夜夜夜影院 | 香蕉视频4aa| 黄色网址中文字幕 | 国产 亚洲 欧美 在线 | 成人av电影免费 | 一级片视频在线 | 青青网视频 | 国产成人精品在线 | 国产原创91 | 综合天天网 | 日韩亚洲欧美中文字幕 | 999国内精品永久免费视频 | 久久久天堂 | 一级做a视频 | 日韩欧美综合精品 | 91黄色影视 | 国产视频 久久久 | 久久免费av电影 | 在线观看久久久久久 | 亚洲精品乱码久久久久久久久久 | 奇米四色影狠狠爱7777 | 九九免费在线视频 | 毛片激情永久免费 | 一区二区三区电影在线播 | 91网免费看 | 天天操天天操天天操 | 色偷偷97 | av福利网址导航 | 特黄免费av | 在线电影91 | 日本99精品| 99久久影视 | 日韩一区二区三区在线观看 | 在线观看 国产 | 91福利影院在线观看 | 天天综合网~永久入口 | av网站有哪些 | 久久综合精品国产一区二区三区 | 国产中文字幕免费 | 亚洲精品视频观看 | 亚洲男男gaygayxxxgv | 久久国产精品一区二区三区四区 | 精品久久久久久国产 | 91九色视频国产 | 超碰97中文 | 亚洲va在线va天堂va偷拍 | 黄色一级大片在线免费看产 | 亚洲精品黄色 | 国产精品免费看 | 97色国产 | 亚洲综合视频在线 | 国产视频精品久久 | bbbbb女女女女女bbbbb国产 | 亚洲国产字幕 | 精品免费在线视频 | 国产裸体永久免费视频网站 | 在线免费黄网站 | 久久伦理网 | 美女露久久 | 日韩欧美一区二区三区在线观看 | 国产精品毛片一区二区在线看 | 最近免费在线观看 | 国产精品久久久久久吹潮天美传媒 | 亚洲免费av电影 | 国产精品www | 在线精品观看 | www色网站 | 黄色网在线播放 | 9色在线视频 | 99久久久久免费精品国产 | 91av在线播放视频 | 国产高清久久久 | 成人午夜电影网 | 成人av电影免费在线播放 | 99热这里有精品 | 免费黄色网止 | 青青河边草手机免费 | 天天激情天天干 | 久草在线这里只有精品 | 久久久免费精品国产一区二区 | 日韩在线视频观看 | 91丨九色丨蝌蚪丨老版 | 91免费国产在线观看 | 久久狠狠干| 国产在线免费 | 中文字幕在线观看亚洲 | 日韩av三区 | 亚洲国产精彩中文乱码av | 波多野结衣电影一区二区 | 色婷婷激情综合 | 天天综合久久 | 99精品一区二区三区 | 在线av资源 | 国产中文视 | 久久草在线视频国产 | 99精品欧美一区二区三区 | 青青草久草在线 | 91自拍视频在线观看 | 三级av在线免费观看 | 国产成人久 | 国产网红在线观看 | 国产精品一区二区久久久久 | 激情欧美丁香 | 五月婷av | 视频一区二区免费 | 亚洲最大的av网站 | 波多野结衣在线播放视频 | 99精品热视频只有精品10 | 久久久国产精品人人片99精片欧美一 | 日日夜夜天天综合 | 久久永久视频 | 91自拍成人 | www.福利 | 综合网伊人 | 日韩免费小视频 | 久久三级毛片 | 日韩av高清在线观看 | 久久综合久久综合久久 | 免费在线观看不卡av | 日韩欧美视频在线观看免费 | 欧美黑人性猛交 | 97超碰在线视 | 免费观看午夜视频 | 91精品伦理 | 国产三级精品三级在线观看 | 最近中文字幕久久 | 婷婷精品 | 人人干在线观看 | av在线精品 | 欧美九九九 | 色综合久久88色综合天天人守婷 | 九七在线视频 | 精品亚洲欧美无人区乱码 | 国产99久久久国产精品成人免费 | 超碰在线日韩 | 久久人人爽人人爽人人片av软件 | 久久综合色天天久久综合图片 | 亚洲香蕉视频 | 国内外成人免费在线视频 | 欧美日韩性视频在线 | 狠狠色婷婷丁香六月 | 天天插一插 | 青青草国产成人99久久 | 中文国产字幕在线观看 | 国产精品网红直播 | 欧美一区三区四区 | 久久99精品久久久久久秒播蜜臀 | 久久久www成人免费毛片 | 伊人国产在线播放 | 天天视频亚洲 | 欧美不卡视频在线 | 天天干天天拍天天操 | 亚洲黄色在线免费观看 | 99精品热视频 | 国产免费三级在线观看 | 亚洲精品在线观看网站 | 国产专区免费 | 91av在线精品| 国产色影院 | 日韩精品视频免费专区在线播放 | 国产精品白虎 | 日本视频网 | 国产精品com | 毛片基地黄久久久久久天堂 | 综合av在线 | 韩国精品视频在线观看 | 天天色天天搞 | 精品国产欧美一区二区三区不卡 | 国内精品视频在线播放 | 天天爽夜夜爽人人爽曰av | 中文在线 | 久久精视频 | 国产一区二区三区高清播放 | 欧美日本啪啪无遮挡网站 | 在线播放日韩av | 欧美精品在线视频 | 亚洲精品国产区 | 天天操夜夜想 | 午夜国产福利在线 | 欧美俄罗斯性视频 | a在线免费观看视频 | 97超碰在 | 久久久99国产精品免费 | wwwwww黄| av成人免费 | 日韩色区 | 五月婷婷丁香综合 | 日韩av手机在线看 | 丁香花在线观看视频在线 | 免费国产黄线在线观看视频 | 日韩69av| 天天躁天天躁天天躁婷 | 亚洲成人av在线播放 | 中文字幕无吗 | 麻豆国产视频 | 日本久久成人中文字幕电影 | 亚洲欧美乱综合图片区小说区 | 国产91免费在线 | 亚洲久在线 | 免费中文字幕在线观看 | 高清不卡毛片 | а天堂中文最新一区二区三区 | 亚洲在线免费视频 | 综合婷婷丁香 | 免费观看黄色12片一级视频 | 在线看不卡av | 黄色大片网 | 久久免费看av | 亚洲国产中文字幕 | 天天操夜操视频 | 免费观看国产视频 | 成人一区不卡 | 国产精品黄网站在线观看 | 最近最新中文字幕 | 黄色一级网 | 最近中文字幕免费大全 | 91在线精品播放 | av国产在线观看 | 国产中文a | 精品福利片 | 日韩三级中文字幕 | 又黄又爽又无遮挡的视频 | 在线观看的a站 | 精品国产一区二区三区不卡 | 中文字幕二区三区 | 在线v片免费观看视频 | 免费在线观看亚洲视频 | 日韩亚洲在线观看 | 国产精品久99| 欧美日韩三级 | 国产精品久久久久一区二区三区 | 日韩免费中文字幕 | 久久综合五月天婷婷伊人 | 久久天天操 | 天天插狠狠插 | av免费在线播放 | 久久影院亚洲 | 国产精品破处视频 | 久久精品欧美 | 日韩在线观看视频网站 | 一区二区三区在线免费播放 | 国产精品9区 | 毛片一区二区 | 怡红院久久 | 国产精品9999久久久久仙踪林 | 最近中文字幕mv免费高清在线 | 亚洲蜜桃在线 | 国产传媒中文字幕 | 久久精品9| 国产日韩中文在线 | 狠狠躁夜夜a产精品视频 | 精品久久久一区二区 | 狠狠综合| 久久久久国产精品免费网站 | 又黄又网站 | 狠狠躁日日躁狂躁夜夜躁 | 国产这里只有精品 | 草免费视频 | 成人午夜黄色 | 国产亚洲视频在线观看 | 国产91影院 | 国内精品久久久精品电影院 | 97在线看 | 奇米网网址 | 久久免费大片 | 天天干天天干天天 | 中文字幕乱在线伦视频中文字幕乱码在线 | 一区二区不卡高清 | 在线观看一级视频 | 激情文学丁香 | 久久精品久久综合 | 久久成人综合 | 96久久精品 | 九九九九精品九九九九 | 国产精品高 | 首页av在线| 97碰碰精品嫩模在线播放 | 亚洲精品乱码白浆高清久久久久久 | 天天草视频 | 91视频免费网站 | 欧美日韩国产页 | 久久国产色 | 久久涩涩网站 | 久操伊人 | 国产又粗又猛又爽又黄的视频免费 | 精品一二三四五区 | 亚洲欧洲中文日韩久久av乱码 | 色全色在线资源网 | 99久久影院| 91麻豆精品国产自产在线 | 日韩av不卡在线 | 国产精品系列在线播放 | 香蕉视频18| 四虎永久免费网站 | 日本公妇在线观看 | 偷拍精偷拍精品欧洲亚洲网站 | 亚洲成人软件 | 综合色狠狠 | 欧美日韩在线精品 | 日本在线观看一区二区三区 | 久久亚洲综合国产精品99麻豆的功能介绍 | 亚洲精品欧美精品 | 亚洲码国产日韩欧美高潮在线播放 | 亚洲精品综合久久 | 亚洲国产激情 | 91精品网站 | 国产婷婷vvvv激情久 | 婷婷午夜| 99久久一区 | 在线精品视频免费播放 | 精品久久久久久国产 | 国产伦理精品一区二区 | 99精品久久99久久久久 | 五月激情综合婷婷 | 日韩欧美99| 国产亚洲成人精品 | 婷婷六月色 | 久久久久久久网站 | 久久久国产精品电影 | 国产中文字幕第一页 | 在线日韩视频 | 久久久久久综合 | 一区二区三区在线电影 | 国产高清无线码2021 | 精品久久久久一区二区国产 | 日韩精品中文字幕在线播放 | 丁香在线视频 | 天天碰天天操 | 极品美女被弄高潮视频网站 | 色综合久久精品 | 丰满少妇高潮在线观看 | 久久久久久久久久久久久影院 | 午夜精品久久久久久久久久久久 | 欧美一级免费 | 精品超碰 | 99精品视频在线观看 | 欧美日韩一区二区三区不卡 | 精品日本视频 | 人人爽久久涩噜噜噜网站 | 黄色一级在线视频 | 日日干夜夜爱 | 国产精品igao视频网网址 | 天天爱天天插 | 911久久| 日韩av不卡在线观看 | 日韩精品一区二区三区中文字幕 | 亚洲国产中文字幕在线视频综合 | 欧美日韩高清一区二区 | 天堂网一区二区 | 啪啪动态视频 | 夜夜看av | 狠狠色丁香婷婷综合久小说久 | 午夜婷婷在线观看 | 日韩黄色中文字幕 | 一区二区三区免费在线观看视频 | 色视频成人在线观看免 | 日本免费一二三区 | 日韩手机在线观看 | 久久国产精品视频观看 | 成人免费91| 亚洲精品乱码 | 久草在线视频首页 | 国产精品久久久久久久99 | av免费网 | 日韩,中文字幕 | 三级黄色理论片 | www亚洲精品| www色综合 | 国产一区不卡在线 | 国产视频一区在线免费观看 | 国产福利一区二区三区在线观看 | 日韩精品久久一区二区 | 日韩精品中文字幕有码 | 人人讲 | 日韩高清一二三区 | 国产美女精彩久久 | 97在线观看视频国产 | 97在线免费视频 | 黄色一级大片在线免费看国产一 | 成年人视频在线免费 | av一级片网站 | 激情文学综合丁香 | 日韩黄色影院 | 亚洲 欧洲 国产 日本 综合 | 亚洲永久精品在线 | 亚洲精品国产麻豆 | 国产九色91 | 天天操夜夜逼 | 丁香婷婷激情国产高清秒播 | 国产中文字幕在线免费观看 | 亚洲特级毛片 | 精品久久久久久久久久久久 | 激情综合五月天 | 狠狠的日 | 国产又粗又猛又色 | 13日本xxxxxⅹxxx20| 成人精品久久久 | 九九久久久 | 国产精品一区二区三区四 | 日韩av中文字幕在线免费观看 | 伊人五月在线 | 婷婷丁香色 | 日日干天天射 | 日韩激情免费视频 | 国产成人综 | 国内久久视频 | 99久久久国产精品 | 三级黄色大片在线观看 | 免费在线视频一区二区 | 六月色婷婷 | 欧美日韩免费网站 | 欧美激情综合色综合啪啪五月 | 成年人黄色av | 激情亚洲综合在线 | 欧美aaa一级| 麻花豆传媒mv在线观看网站 | a电影在线观看 | 国产精品情侣视频 | 久久电影日韩 | 成人小视频在线播放 | 九九精品久久 | 一区二区三区高清 | 911亚洲精品第一 | 久草网视频在线观看 | 亚洲 中文 欧美 日韩vr 在线 | 日本中文字幕久久 | 在线午夜 | www.久久久.cum | 字幕网av| 国产精品igao视频网网址 | 激情五月***国产精品 | 久草国产在线观看 | 国产精品久久久久久久99 | 免费黄色a网站 | 91综合久久一区二区 | 亚洲精品在线电影 | www夜夜操 | 欧美精品久久久久性色 | 日日夜夜狠狠干 | 免费看黄视频 | 97超碰人人在线 | 精品久久一区二区三区 | 毛片一级免费一级 | 国产999| 日韩免费一区二区三区 | 国产 亚洲 欧美 在线 | 久久久精品国产一区二区 | 97福利视频| 久久国产综合视频 | 麻豆视频免费观看 | 久久久www免费电影网 | 伊人久久一区 | 成人在线一区二区 | 五月婷丁香网 | 91人网站 | 国产在线视频在线观看 | 国产亚洲精品久久久久秋 | 天天插天天狠 | 51久久成人国产精品麻豆 | 福利在线看片 | 天天夜夜狠狠操 | 久久精品99久久久久久2456 | 欧美一二三在线 | 天天综合天天做 | 国产高清专区 | 国产精品11 | 久久久久久久久毛片精品 | 久久人人爽人人爽人人片 | 九九九热 | 成人一区二区三区在线 | 高清在线观看av | 成人国产亚洲 | 成人宗合网 | av电影在线观看 | 国产特级毛片aaaaaa高清 | 欧美综合在线视频 | 日韩在线第一区 | 在线免费视频你懂的 | 免费视频在线观看网站 | 成人黄色在线视频 | 91超在线 | 久久影视中文字幕 | 国产高清视频在线观看 | 蜜桃av人人夜夜澡人人爽 | 亚洲精品美女久久17c | www激情久久 | 欧美成人xxxxx | 五月天高清欧美mv | 日韩免费播放 | 国产91精品久久久久 | 亚洲精品国久久99热 | 亚洲免费成人av电影 | 欧美精品中文在线免费观看 | 久草在线免 | 久久久久久久久久亚洲精品 | 亚洲涩涩网站 | 99精品欧美一区二区三区 | 九九视频在线 | 午夜久久福利 | 视频一区二区国产 | 91人网站 | 最新影院 | 久久精品专区 | 久久久久二区 | 国产日韩视频在线 | 毛片区 | 91精品国产欧美一区二区成人 | 久久成人精品视频 | 国产一区二区精品久久 | 久久免费国产精品 | 国产精品一区二区三区四区在线观看 | 免费黄色av. | 欧美日韩高清国产 | 精品99在线 | 国产日本在线 | 综合网色 | 久久久网站 | 最新真实国产在线视频 | 狠狠狠狠狠狠干 | 色婷婷电影网 | 激情视频网页 | 国产中文字幕免费 | 色偷偷888欧美精品久久久 | 日韩免费电影网站 | 人人爽人人爽人人爽学生一级 | 国产98色在线 | 日韩 | 天天综合网入口 | 人人干免费 | 98涩涩国产露脸精品国产网 | 久久综合狠狠综合 | 在线欧美日韩 | 欧美日韩精品在线观看视频 | 99精品热 | 五月激情视频 | 国内精品视频一区二区三区八戒 | 日韩一区正在播放 | 国产精品视频永久免费播放 | 欧美另类网站 | 99精品视频在线播放观看 | 天堂av网站| 激情久久久久久久久久久久久久久久 | 国产专区免费 | 久久电影国产免费久久电影 | 亚洲九九精品 | 欧美精品第一 | 狠狠色伊人亚洲综合成人 | 2019天天干天天色 | 久久免费视频在线 | 日韩网站在线看片你懂的 | 一区二区中文字幕在线 | 国产黑丝袜在线 | 综合色站| 精品一区在线看 | 五月婷婷在线观看 | 91精品久久久久久久91蜜桃 | 国产精品永久久久久久久久久 | 久草免费在线观看视频 | 午夜色站 | 日韩高清无线码2023 | 免费看污在线观看 | 美女久久久久久久久久 | 中文在线天堂资源 | 欧美一区二区三区不卡 | 中文字幕av一区二区三区四区 | 免费看片网站91 | 麻豆传媒电影在线观看 | 日韩av在线高清 | av在线网站大全 | 日本h视频在线观看 | 一本色道久久综合亚洲二区三区 | 国产日韩精品一区二区三区在线 | 97精品视频在线 | 久久久久久国产精品久久 | 久久免费福利 | 亚洲黄色在线免费观看 | 99久久久久久 | 国产精品福利久久久 | 久草免费资源 | 国产综合91 | 黄色成人av在线 | 91传媒91久久久 | 久久久黄视频 | 在线日本看片免费人成视久网 | 伊人伊成久久人综合网站 | 亚洲有 在线 | 欧美精彩视频在线观看 | 日韩高清在线一区二区三区 | 狠狠色综合网站久久久久久久 | 亚洲视频 一区 | www.97色.com| 中文字幕中文字幕在线一区 | 国产黄在线免费观看 | 永久黄网站色视频免费观看w | 97精品一区二区三区 | 欧美精品亚洲精品 | 亚洲精品国产品国语在线 | 天天干 夜夜操 | 日本中文字幕在线看 | 美女国产在线 | 在线免费精品视频 | 成年人免费av网站 | 国产成人三级一区二区在线观看一 | 麻豆91在线看 | 欧美精品一区二区三区四区在线 | 久久tv视频| 精品久久久久久亚洲综合网 | 色婷婷成人网 | 九九热视频在线播放 | 成年人视频在线观看免费 | 婷婷综合伊人 | 国产精品国产三级国产不产一地 | 九九热在线播放 | 在线a人片免费观看视频 | 国产精品美女久久久久久久 | 在线观看亚洲电影 | 日韩欧美久久 | 一区二区三区在线观看 | 国产人成精品一区二区三 | 18做爰免费视频网站 | 91最新在线观看 | 亚洲精品国偷拍自产在线观看蜜桃 | 成人黄色在线观看视频 | 欧洲激情综合 | 不卡在线一区 | 天天射天天做 | 久草在线精品观看 | 黄色成人av | 美女网站色 | 69视频在线播放 | 精品人人人| www.国产视频 | 在线看v片成人 | 少妇bbw揉bbb欧美| 黄色影院在线免费观看 | 日韩精品一区二区三区第95 | 伊人资源视频在线 | 六月丁香激情综合色啪小说 | 国产在线污 | 人交video另类hd | 日日夜夜操av| 成人免费视频播放 | 国产精品乱码久久久久 | 不卡中文字幕av | 欧美日本一二三 | 毛片www| 精品一区久久 | 国产精品欧美一区二区 | 黄色免费网站下载 | 三级视频日韩 | 偷拍区另类综合在线 | 超碰在线资源 | 人人搞人人爽 | 五月丁色 | 在线视频免费观看 | 国产成人一级电影 | 日本三级香港三级人妇99 | 日本在线视频一区二区三区 | www.福利视频| 中文字幕av影院 | 午夜精品一区二区三区四区 | 久久精品观看 | 精品亚洲成人 | 999精品在线| 国产一区二区在线免费观看 | 日韩理论电影网 | 国产成人精品一区二区三区网站观看 | 国产成人久久精品77777综合 | 亚洲涩涩一区 | 国产精品12345| 免费在线观看毛片网站 | 在线免费观看黄色 | 久久免费毛片视频 | 能在线看的av | 亚洲影院国产 | 人人舔人人舔 | 精品极品在线 | 人人澡av | 久久精品网站免费观看 | www.天天色 | 中文字幕有码在线 | 超碰成人免费电影 | 91中文视频 | 天天操夜| 九七人人干 | 国产精品久久久久一区 | 在线观看一区 | 四虎影视成人永久免费观看亚洲欧美 | 99视频在线观看一区三区 | 精品在线观看一区二区 | 玖玖精品在线 | 91香蕉视频 | 色婷婷久久| 亚洲性少妇性猛交wwww乱大交 | 欧美a性| 成年人免费在线播放 | www.色五月 | 欧美激情一区不卡 | 亚洲综合情 | 色综合久久久久久久久五月 | 久久婷五月 | 亚洲黄色一级大片 | 久久婷婷一区二区三区 | 中文字幕亚洲综合久久五月天色无吗'' | 亚洲欧美视频网站 | 国产亚洲视频中文字幕视频 | 亚洲黄色一级视频 | 91成年人视频 | 欧美一级免费高清 | 丁香亚洲| 国产视频91在线 | 91精品国产福利在线观看 | 国产裸体视频网站 | 国产高清黄 | 国产高清在线观看av | 欧美国产视频在线 | 色先锋av资源中文字幕 | 日韩免费在线观看 | 激情五月激情综合网 | 欧美视频一区二 | 99热在线精品观看 | 天天操天天干天天操天天干 | 91高清免费看 | 黄色国产在线观看 | 五月天网页 | 日本一区二区三区视频在线播放 | 91人人爽久久涩噜噜噜 | 久久久官网 | 日韩欧美视频在线播放 | 六月激情婷婷 | av 一区 二区 久久 | 国产九色视频在线观看 | 亚洲婷婷在线视频 | 中文字幕亚洲五码 | 午夜久久福利视频 | 成人免费电影 | 在线91精品| 97高清免费视频 | 美女免费av | 亚洲午夜久久久综合37日本 | 麻豆视频大全 | 亚洲最新av网站 | 久久久精品国产免费观看一区二区 | 天天操导航 | 2018好看的中文在线观看 | 国产精品mv在线观看 | 国产精品一区二区三区视频免费 | 福利视频一区二区 | 精品一区电影国产 | 手机av在线不卡 | 91精品91 | www激情网 | 99在线观看视频网站 | 精品久久久久久亚洲 | 日本在线视频一区二区三区 | 久久国产精品免费一区二区三区 | www.五月天 | 中文字幕一区二区三区久久 | 免费亚洲成人 | 韩国一区视频 | 精品影院一区二区久久久 | 亚洲欧美日韩不卡 | 五月婷婷一区二区三区 | 精品免费一区二区三区 | 国产成人一区在线 | 黄污网站在线观看 | 国产精品手机在线播放 | 在线观看av片 | 国产999精品久久久久久 | 美女又爽又黄 | 99这里只有久久精品视频 | 久久免费视频3 | 一区二区三区免费在线观看视频 | 国产一区在线播放 | 丁香花在线观看免费完整版视频 | 黄av免费在线观看 | 狠狠撸电影 | 日韩二区在线观看 | 日韩在线免费高清视频 | 91精品国产自产在线观看 | 婷婷日韩 | 黄色一级在线视频 | 婷婷在线播放 | 在线观看免费av片 | 亚洲精品国精品久久99热一 | 色婷婷天天干 | 久久免费在线观看 | 日韩在线一区二区免费 | 婷婷丁香在线 | 2019天天干夜夜操 | 少妇啪啪av入口 | 国产黄色精品在线 | 天天干天天射天天操 | 美女av免费看 | 最近2019好看的中文字幕免费 | 91在线观看视频 | 免费看黄在线看 | 在线色吧| 亚洲精品456在线播放第一页 | 国产视频精选 | 人人精久 | 婷婷深爱五月 | 最近2019中文免费高清视频观看www99 | 深爱激情综合网 | 国产在线播放不卡 | 久草精品国产 | 久久婷亚洲五月一区天天躁 | 中文字幕视频一区二区 | 亚洲黄色软件 | 午夜免费电影院 | 国产精品女主播一区二区三区 | 欧美韩日视频 | 日韩欧美在线中文字幕 | 亚洲一区二区视频 | 日韩欧美视频在线观看免费 | 久久综合福利 | 国产高清不卡一区二区三区 | 久久r精品 | 九九免费在线观看 | 91视频在线看 | 国产女人免费看a级丨片 | 亚洲精品在线观看av | 日韩一区二区免费视频 | 日韩福利在线观看 | 精品久久久久一区二区国产 | 五月婷婷视频在线 | 欧美精品免费在线观看 | 亚洲国产手机在线 | 少妇av网 | 六月激情丁香 | 久久人91精品久久久久久不卡 | 99久久99久久精品国产片果冰 | 奇米影视8888在线观看大全免费 | 久久国产网 | 天天天干天天射天天天操 | 美女一级毛片视频 | 精品成人a区在线观看 | 日韩av手机在线看 | 伊人成人精品 | 免费观看91视频大全 | 91伊人久久大香线蕉蜜芽人口 | 久久国产精品免费看 | 日韩一三区| 国产精品一区免费看8c0m | 日本一区二区三区免费看 | 久久国产精品免费观看 | 日韩精品综合在线 | 日日爱999| 中文av资源站 | 人人射人人澡 | 国产精品视频不卡 | 国产精品免费在线播放 | 国产精品福利在线观看 | 亚洲精品mv在线观看 | 久久综合婷婷综合 | 日韩av免费在线看 | 日韩簧片在线观看 | 狠狠色狠狠色综合日日92 | 国产一区二区不卡视频 | 97视频资源 | 伊人狠狠操 |