python&&ftp上传和多线程开发&&学习笔记

python&&ftp上传和多线程开发&&学习笔记

    • FTP文件上传
      • FTP文件上传示例
      • 堡垒机程序示例
      • SSH密码账号远程登录服务器示例
      • SSH密钥远程登录服务器示例
      • SSH上传和下载文件
    • 线程与进程简介
      • 应用程序、进程、线程的关系
      • 简单创建线程示例1
      • 多线程开发的方法
      • 多线程之方法应用示例
      • 多线程之自定义线程类示例
      • 多线程之生产者与消费者模型示例一
      • 函数式编程实现生产者与消费者模型
      • 多线程开发之线程锁
      • 多线程开发之event事件

FTP文件上传

FTP文件上传示例

示例框架
python&&ftp上传和多线程开发&&学习笔记_第1张图片
server.py(运行异常,仅参考)

#!/usr/bin/env python
#coding:utf-8
#导入模块socketserver,利用多线程实现多个用户同时上传下载文件
import socketserver
import os 
from test.test_decimal import file

class myServer(socketserver.BaseRequestHandler):
    def handle(self):
        #定义文件存放根路径
        basePath = 'D:/backupAll\eclipseRoot\temp'
        clientObj = self.request
        print('连接成功...')
        while True:
            #获取发送头信息
            preData = clientObj.recv(1024)
            preDataToStr = str(preData, encoding = "utf8")
            print(preDataToStr)
            cmd,fileName,fileSize = preDataToStr.split('|')
            recvSize = 0
            #拼接路径
            fileDir = os.path.join(basePath,fileName)
            f = file(fileDir,'wb')
            Flag = True
            while Flag:
                if int(fileSize) > recvSize:
                    data = clientObj.recv(1024)
                    recvSize += len(data)
                else:
                    recvSize = 0
                    FLag = False
                #数据由内存写入硬盘
                f.write(data)
            print('上传完毕')
                
instance = socketserver.ThreadingTCPServer(('127.0.0.1',9999),myServer)
instance.serve_forever()
             

client.py

#!/usr/bin/env python
#coding:utf-8
#由于文件的发送传输需要经过缓冲区,缓冲区大小固定(一般为8096),所以在实现对文件的发送传输时需要将文件切割成固定大小发送。
#导入模块

from pip._vendor.distlib.compat import raw_input
from test.test_decimal import file
import  socket
import os



#定义变量
ipAddress = ("127.0.0.1",9999)
socketObj = socket.socket()
socketObj.connect(ipAddress)
#创造重复循环
while True:
    #接收"文件操作命令(上传(put)、下载(get))|文件路径"
    input = raw_input('path:')
    #分离存放文件操作命令(上传、下载)和文件路径
    cmd,path = input.split('|')
    #定义文件名称
    fileName = os.path.basename(path)
    #定义文件大小
    fileSize = os.stat(path).st_size
    strOne = cmd+"|"+fileName+"|"+str(fileSize)
    strToBit = strOne.encode(encoding='utf_8', errors='strict')
    #发送消息到
    socketObj.send(strToBit)
    #文件发送进度
    sendSize = 0
    f = file(path,'rb')
    Flag = True
    while Flag:
        #如果文件发送剩余大小不足1024,则读取发送剩余大小数据并结束重复循环
        if sendSize + 1024 > fileSize:
            data = f.read(fileSize - sendSize)
            Flag = False
        #否则,读取发送固定大小文件数据并记录w文件发送进度
        else:
            data = f.read(1024)
            sendSize +=1024
        f.close()
socketObj.close()

堡垒机程序示例

需求:记录用户在服务器的所有操作
1.需要一台主机当做堡垒机
2.所有用户只能登陆堡垒机
3.登陆堡垒机后,可以远程服务器进行操作
4.记录用户的所有操作
过程:登陆堡垒机》选择服务器》操作服务器:记录操作
实现过程
1.创建堡垒机用户


2.用户登陆堡垒机后

SSH密码账号远程登录服务器示例

sshDemo.py

#!/usr/bin/env python
#coding:utf-8
#导入模块
import paramiko
#实例化
ssh = paramiko.SSHClient()
#应对第一个远程登录的用户签名(yes or no),该行代码默认填写yes。
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
#远程登录账号,密码
ssh.connect('192.168.1.223',22,'root','yibotong')
#设置需要使用Linux命令并捕捉命令返回结果(输入,输出,错误)
stdin,stdout,stderr = ssh.exec_command('df')
#打印结果
print(stdout.read())
ssh.close();

SSH密钥远程登录服务器示例

服务器操作生成密钥操作

#ssh命令产生密钥对
ssh-keygen -t rsa
#将本地公钥复制到远程服务器内部(/root/.ssh/id_rsa.pub)
ssh-copy-id [email protected]

python密钥登录

#!/usr/bin/env python
#coding:utf-8
#导入模块
import paramiko
#定义私钥文件位置
private_key_path = '/home/auto/.ssh/id_rsa'
#取出私钥
key = paramiko.RSAKey.from_private_key_file(private_key_path)
#实例化
ssh = paramiko.SSHClient()
#应对第一个远程登录的用户签名(yes or no),该行代码默认填写yes。
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
#远程登录账号
ssh.connect('192.168.1.223',22,username='root',pkey=key)
#设置需要使用Linux命令并捕捉命令返回结果(输入,输出,错误)
stdin,stdout,stderr = ssh.exec_command('df')
#打印结果
print(stdout.read())
ssh.close();

rsa公钥与私钥的区别
私钥是自己用的,用于解密;公钥用于加密。
rsa公钥与私钥工作原理
远程登录时,客户端使用tcp协议发送连接请求(欲连接ssh端口),远程服务器使用公钥随机加密一段数据发送到客户端,客户端使用本地私钥解密,解密完成后将数据发送到服务端,服务端对解密数据进行比对,若匹配成功,则公钥与私钥配对成功,即远程登录成功。

SSH上传和下载文件

参考:***cnblogs.com/wupeiqi/articles/4356675.html


线程与进程简介

应用程序、进程、线程的关系

一个应用程序里面可以有多个进程,一个进程里面可以有多个线程。
全局解释器锁
在程序运行过程中,同一时间,一个进程里面只能有一个线程通过全局解释器锁进入cpu执行。
多进程与多线程的选择
计算密集型程序需要消耗大量cpu资源,故选择多进程模式;IO密集型程序选择多线程模式。
进程的开销通常比线程昂贵,因为线程自动共享内存地址空间和文件描述符,这意味着,创建进程比创建线程会花费更多。
在执行一些sleep/read/write/recv/send等会导致阻塞的函数时,当前线程会主动放弃GIL,然后调用相应的系统API,完成后再重新申请GIL.因此,GIL也并不是导致python的多线程完全没用。在一些IO等待的场合,python的多线程还是发挥了作用,当然如果多线程都是用于CPU密集的代码,那多线程的执行效率明显会比单线程的低。

线程是共享内存的,线程由进程管理,所有线程共享主线程的内存空间;进程的内存空间是互相独立,没有交集的。

简单创建线程示例1

#!/usr/bin/env python
#coding:utf-8
#导入threading模块下的Thread类
from threading import Thread
#定义方法
def funcOne(arg):
    print(arg) 

print('before start thread')
#实例化Thread类形成对象,相当于创建了一个线程.
#使用target参数在定义的方法(函数)与线程之间建立联系
#线程对象 = Thread(target=函数名,args(参数)=(1(仅需一个参数故此处写一),))
threadOne = Thread(target=funcOne,args=(1,))
#1后面为什么加逗号?因为当遇到字典、列表、元组时,其与方法、函数在调用时操作类似,故容易因为区分错误而报错,后面加逗号,可以说明这是一个序列,以此作为区分。

#在运行对象时,并不一定马上执行,按系统调度规则被轮训到时执行
threadOne.start()
print('after start thread')

多线程开发的方法

threading.Thread模块

  • start
  • getName()
  • setName():更改线程名称
  • isDaemon()
  • setDaemon()
  • join(timeout)
  • run

线程创建不宜过多也不宜过少,恰当最好。线程过少时,执行效率低;线程过多时会导致上下文切换频繁,造成大量资源浪费。

多线程之方法应用示例

#!/usr/bin/env python
#coding:utf-8
#导入threading模块下的Thread类
from threading import Thread
import time
#定义方法
def funcOne(arg):
    print(arg) 
    
def funcTwo(arg,v):
    for item in range(100):
        print(item)
        time.sleep(1)

print('before start thread')
#实例化Thread类形成对象,相当于创建了一个线程.
#使用target参数在定义的方法(函数)与线程之间建立联系
#线程对象 = Thread(target=函数名,args=(参数1,))
threadOne = Thread(target=funcOne,args=('参数1',))
threadTwo = Thread(target=funcTwo,args=('参数1','参数2'))
#1后面为什么加逗号?因为当遇到字典、列表、元组时,其与方法、函数在调用时操作类似,故容易因为区分错误而报错,后面加逗号,可以说明这是一个序列,以此作为区分。

#在程序运行时,当主线程已经执行结束,而子线程执行缓慢仍未结束时,主线程需要等待子线程执行结束才终止程序运行。
#输出当前daemon状态,默认False
print(threadTwo.isDaemon())
#设置daemon状态,此时不再遍历100之内的数字。
#通过设置daemon状态,可以让子线程随主线程的执行结束而结束,主线程不再等待子线程(threadOne和threadTwo)执行结束。
threadOne.setDaemon(True)
threadTwo.setDaemon(True)

#在运行对象时,并不一定马上执行,按系统调度规则被轮训到时执行
threadOne.start()
threadTwo.start()
#每个线程被创建时都拥有一个名字,使用'getName'方法输出线程的名字如下
print(threadOne.getName())
print(threadTwo.getName())
##Thread-1

print('after start thread')

多线程之自定义线程类示例

#!/usr/bin/env python
#coding:utf-8
#导入模块
from threading import Thread
import time

#自定义一个线程类myThreadClass继承父类Thread
#实质是在原有Thread类的基础上增加自己的功能形成自定义的线程类
class myThreadClass(Thread):
    #重写run方法,因为父类Thread拥有run方法,此处为重写。
    def run(self):
        time.sleep(10)
        print('run方法创建了一个线程,我等了10s才现身')
        try:
            if self._target:
                self._target(*self._args, **self._kwargs)
        finally:
            # Avoid a refcycle if the thread is running a function with
            # an argument that has a member that points to the thread.
            del self._target, self._args, self._kwargs
        
def funcThree():
    print('funcThree')
#执行myThreadClass类从Thread类继承的构造函数
threadThree = myThreadClass(target=funcThree)
threadThree.start()
print('主线程已经执行完毕')

多线程之生产者与消费者模型示例一

producer.py(非正常)

#!/usr/bin/env python
#coding:utf-8
#导入模块
from threading import Thread
import time
#导入队列模块的队列类
from queue import Queue
#定义生产者类,向队列存放数据
class producer(Thread):
    #重写父类的构造函数__init__
    def __init__(self,name,queue):
        #name:生产者的名字
        #queue:存放数据的容器
        self.__Name = name
        self.__Queue = queue
        #或Thread.__init__(self)
        super(producer,self).__init__()
        
    
    #重写父类的run函数
    def run(self):
        while True:
            #判断队列是否已满
            if self.__Queue.full():
                #满则等待1秒
                time.sleep(1)
            else:
                #未满则向队列加入数据
                self.__Queue.put('someData')
                print('%s 向队列中放置了一个数据' %(self.__Name,))
                time.sleep(1)
        Thread.run(self)
        
#定义消费者类 , 从队列取出数据  
class consumer(Thread):
    #重写父类的构造函数__init__
    def __init__(self,name,queue):
        #name:生产者的名字
        #queue:存放数据的容器
        self.__Name = name
        self.__Queue = queue
        Thread.__init__(self)
        
    def run(self):
        #判断队列是否已空
        if self.__Queue.empty():
            #空则等待1秒
            time.sleep(1)
        else:
            #未空则从队列拿出一个数据
            self.__Queue.get()
            print('%s 从队列中取走了一个数据' %(self.__Name,))
            time.sleep(1)
        Thread.run(self)
        
#创建队列对象并设置队列最大为10。
#队列特性:先进先出,线程安全的
queueObj = Queue(maxsize=100)    
#使用xxx对数据结构(序列、列表等)上锁,同一时间仅允许一个线程对上锁的数据结构进行操作。
#向队列存放数据
queueObj.put('1')
#查看队列内容
print(queueObj.queue)
#使用queueObj.empty()判断队列时候为空
print(queueObj.empty())
#从队列取出数据
print(queueObj.get())
print(queueObj.queue)
print(queueObj.empty())

#使用队列类创建一个仓库对象queueObjTwo
queueObjTwo = Queue(maxsize=100)
#使用生产者类创建生产者对象。因为本质上是继承了线程类Thread,所以可以认为创建的生产者对象就等同于创建的新的线程
#创建三个生产者
producerOne = producer('producerYiHao',queueObjTwo)
producerOne.start()
producerTwo = producer('producerErHao',queueObjTwo)
producerTwo.start()
producerThree = producer('producerSanHao',queueObjTwo)
producerThree.start()
print(queueObjTwo.queue)
#使用消费者类创建消费者对象。因为本质上是继承了线程类Thread,所以可以认为创建的消费者对象就等同于创建的新的线程
#创建二十个消费者
for item in range(20):
    name = 'consumer%d' %(item,)
    name = consumer(name,queueObjTwo)
    name.start()
    
consumerOne = consumer('consumerYiHao',queueObjTwo)
consumerOne.start()
print(queueObjTwo.queue)

消费者生产者模型优点
解耦:令一个程序的各个部分之间关联性降到最低。

函数式编程实现生产者与消费者模型

producerDemoTwo.py

#!/usr/bin/env python
#coding:utf-8
import threading
import time
import queue
import random

def producer(name,que):
    while True:
        if que.qsize() < 3:
            que.put('baozi')
            print('%s make a baozi...' %name)
        else:
            print('有三个包子,吃了在做')
        #随机等待一到五秒
        time.sleep(random.randrange(5))
    
def consumer(name,que):
    while True: 
        #使用try捕捉错误异常,若队列为空,则打印异常输出,此时consumer线程不再中断。没有捕捉错误异常且队列为空时,consumer线程抛出异常并中断
        try:
            #使用'que.get()'时,若队列中无数据,则阻塞;使用'que.get_nowait()'时,若队列中无数据,则抛出异常
            que.get_nowait()
            print('%s eat a baozi' %name)
            #随机等待一到三秒
        except Exception:
            print(u'baozi 吃光了')
        time.sleep(random.randrange(5))
        

q =queue.Queue()
p1 = threading.Thread(target=producer,args=['chef1',q])
p2 = threading.Thread(target=producer,args=['chef2',q])
p1.start()
p2.start()
c1 = threading.Thread(target=consumer,args=['consu1',q])
c2 = threading.Thread(target=consumer,args=['consu2',q])
c1.start()
c2.start()

多线程开发之线程锁

线程锁中的threading.Lock和threading.Rlock

线程安全:
因为多个线程之间共享一份内存数据,为了防止出现多个线程同时修改一份内存数据的情况,需要使用线程锁。
定义递归锁对象,可以在锁内继续加锁而不会出现阻塞现象。
lock = threading.RLock()
定义线程锁对象,同时允许有四个线程对同一份数据进行操作。
lock = threading.BoundedSemaphore(4)

#!/usr/bin/env python
#coding:utf-8
import threading
import time
#定义全局变量num,多线程同时启动时,共享内存数据全局变量num
num = 0
#定义函数
def run(n):
    #声明变量num为全局变量
    time.sleep(1)
    global num
    #获取锁,当前线程独占对该数据的操作
    #锁的位置应当仅放置于对数据操作的代码段外面。该代码段将变成串行线程。
    lock.acquire()
    num += 1 
    print(num)
    lock.release()
    
#run('dd')
#定义线程锁对象
lock = threading.Lock()
#定义递归锁对象,可以在锁内继续加锁而不会出现阻塞现象。
#lock = threading.RLock()
#定义线程锁对象,同时允许有四个线程对同一份数据进行操作。
#lock = threading.BoundedSemaphore(4)

#生成十个线程
for i in range(100):
    t = threading.Thread(target=run,args=(i,))
    t.start()
#此时由于多个线程同时执行函数run修改全局变量num,num的值容易出现异常。
#锁内加锁,程序会出现阻塞(死锁)现象。出现该问题时,使用'lock = threading.RLock()'递归锁可以解决.

多线程开发之event事件

#!/usr/bin/env python
#coding:utf-8
import threading
import time
#实现两个线程之间通过event事件来进行交互。
#定义生产者
def producer():
    print(u'等人来买包子')
    #等待事件,阻塞状态
    event.wait()
    #使用'isSet'判断事件状态(是否为true).此时不存在阻塞状态
    #print(event.isSet())
    #清空事件时间状态
    event.clear()
    print(u'刚刚有个抠脚大汉来买包子了')
    print(u'dang dang dang ,开工做包子啦')
    #三秒过后
    time.sleep(10)
    print(u'啦啦啦,包子出锅啦')
    
    event.set()
    print(u'歪,妖妖灵吗,包子好了,趁热买吧')
    
#定义消费者
def consumer():
    print(u'俺去买包子')
    #设置标志,触发事件
    event.set()
    print(u'(顾客)俺刚刚跟厨师说做俩包子,俺要买')
    time.sleep(3)
    while True:
        if event.isSet():
            print('看表:时间到了')
            break
        else:
            print('等待中,肚子咕咕叫')
            time.sleep(1)
    
    event.wait()
    print(u'俺收到通知,:您的包子出锅啦,赶紧趁热去买吧')
#定义事件触发,消费者触发事件去生产者那边买包子
event = threading.Event()
p1 = threading.Thread(target=producer)
p2 = threading.Thread(target=consumer)
p1.start()
p2.start()

你可能感兴趣的:(python)