#!/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.用户登陆堡垒机后
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-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端口),远程服务器使用公钥随机加密一段数据发送到客户端,客户端使用本地私钥解密,解密完成后将数据发送到服务端,服务端对解密数据进行比对,若匹配成功,则公钥与私钥配对成功,即远程登录成功。
参考:***cnblogs.com/wupeiqi/articles/4356675.html
一个应用程序里面可以有多个进程,一个进程里面可以有多个线程。
全局解释器锁
在程序运行过程中,同一时间,一个进程里面只能有一个线程通过全局解释器锁进入cpu执行。
多进程与多线程的选择
计算密集型程序需要消耗大量cpu资源,故选择多进程模式;IO密集型程序选择多线程模式。
进程的开销通常比线程昂贵,因为线程自动共享内存地址空间和文件描述符,这意味着,创建进程比创建线程会花费更多。
在执行一些sleep/read/write/recv/send等会导致阻塞的函数时,当前线程会主动放弃GIL,然后调用相应的系统API,完成后再重新申请GIL.因此,GIL也并不是导致python的多线程完全没用。在一些IO等待的场合,python的多线程还是发挥了作用,当然如果多线程都是用于CPU密集的代码,那多线程的执行效率明显会比单线程的低。
线程是共享内存的,线程由进程管理,所有线程共享主线程的内存空间;进程的内存空间是互相独立,没有交集的。
#!/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模块
线程创建不宜过多也不宜过少,恰当最好。线程过少时,执行效率低;线程过多时会导致上下文切换频繁,造成大量资源浪费。
#!/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()'递归锁可以解决.
#!/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()