python&&ftp上传和多线程开发&&学习笔记
- FTP文件上传
- FTP文件上传示例
- 堡垒机程序示例
- SSH密码账号远程登录服务器示例
- SSH密钥远程登录服务器示例
- SSH上传和下载文件
- 线程与进程简介
- 应用程序、进程、线程的关系
- 简单创建线程示例1
- 多线程开发的方法
- 多线程之方法应用示例
- 多线程之自定义线程类示例
- 多线程之生产者与消费者模型示例一
- 函数式编程实现生产者与消费者模型
- 多线程开发之线程锁
- 多线程开发之event事件
FTP文件上传
FTP文件上传示例
#!/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 root@192.168.1.139
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
(
)