在之前博客C/S架构的网络编程中,IO多路复用是将多个IO操作复用到1个服务端进程中进行处理,即无论有多少个客户端进行连接请求,服务端始终只有1个进程对客户端进行响应,这样的好处是节省了系统开销(select不适合单个客户端长会话操作,这样其它客户端连接请求就会一直等待,poll/epoll对select进行了改进)。下面介绍结合了IO多路复用和多进程(多线程)的SocketServer模块。

1 SocketServer模块

SocketServer内部使用IO多路复用以及“多线程”和“多进程” ,从而实现并发处理多个客户端请求的Socket服务端。即:每个客户端请求连接到服务器时,Socket服务端都会创建一个“线程”或者“进程”专门负责处理当前客户端的所有请求。

SocketServer与select/poll/epoll的本质区别:客户端第1次连接时,服务端就为该客户端创建一个线程或进程,此后服务端就利用此线程或进程与客户端进行通信,后续的数据传输几乎不要server端的直接参与。如果服务端创建的是进程,那么client1和client2同时向server端传输数据时是互不影响的;如果服务端创建的是线程(python中多线程,在同一时间只有一个线程在运行,底层会自动进行上下文切换,即python中不存在真正的多线程),那么client1和client2交替上传数据。

知识回顾: python中的多线程,有一个GIL(全局解释器锁)限制在同一时刻只有1个线程在运行,底层自动进行上下文切换,保证多个线程轮流运行(cpu切片),也就是python中不存在真正的多线程问题,伪多线程,实际多个线程不能真正实现并发处理。

中间处理过程如图所示

        1.1 ThreadingTCPServer

ThreadingTCPServer实现的Soket服务器内部会为每个client创建一个 “线程”,该线程用来和客户端进行交互。

1、ThreadingTCPServer基础

使用ThreadingTCPServer要求:

(1)创建一个继承自SocketServer.BaseRequestHandler的类

(2)类中必须定义一个名称为 handle 的方法

(3)启动ThreadingTCPServer

 #!/usr/bin/env python
# -*- coding:utf-8 -*- import SocketServer class MyServer(SocketServer.BaseRequestHandler): def handle(self):
# print self.request,self.client_address,self.server
conn = self.request
conn.sendall('欢迎致电 10086,请输入1xxx,0转人工服务.')
Flag = True
while Flag:
data = conn.recv(1024)
if data == 'exit':
Flag = False
elif data == '':
conn.sendall('通过可能会被录音.balabala一大推')
else:
conn.sendall('请重新输入.') if __name__ == '__main__':
server = SocketServer.ThreadingTCPServer(('127.0.0.1',8009),MyServer)
server.serve_forever()

SocketServer实现的服务端

 #!/usr/bin/env python
# -*- coding:utf-8 -*- import socket ip_port = ('127.0.0.1',8009)
sk = socket.socket()
sk.connect(ip_port)
sk.settimeout(5) while True:
data = sk.recv(1024)
print 'receive:',data
inp = raw_input('please input:')
sk.sendall(inp)
if inp == 'exit':
break sk.close()

客户端

2、ThreadingTCPServer源码剖析

ThreadingTCPServer的类图关系如下:

注:实际上在类的继承时,子类会继承父类的方法,所以我们在分析类的继承关系时,直接把父类的方法放到子类中,这样就直观些,在python中还有1点要注意的是子类到底是继承哪个父类的方法,因为python中存在多继承。

    内部调用流程为

启动服务端程序
1、执行TCPServer.__init__ 方法,创建服务端Socket对象并绑定IP和端口
2、执行BaseServer.__init__ 方法,将自定义的继承自SocketServer.BaseRequestHandler的类MyRequestHandle赋值给self.RequestHandlerClass
3、执行BaseServer.server_forever方法,While 循环一直监听是否有客户端请求到达 ...

当客户端连接到达服务器
4、执行ThreadingMixIn.process_request方法,创建一个“线程”用来处理请求
5、执行ThreadingMixIn.process_request_thread方法
6、执行BaseServer.finish_request方法,执行self.RequestHandlerClass(),即执行自定义MyRequestHandler的构造方法
  (自动调用基类BaseRequestHandler的构造方法,在该构造方法中又会调用MyRequestHandler的handle方法)

ThreadingTCPServer相关源码

 class BaseServer:

     """Base class for server classes.

     Methods for the caller:

     - __init__(server_address, RequestHandlerClass)
- serve_forever(poll_interval=0.5)
- shutdown()
- handle_request() # if you do not use serve_forever()
- fileno() -> int # for select() Methods that may be overridden: - server_bind()
- server_activate()
- get_request() -> request, client_address
- handle_timeout()
- verify_request(request, client_address)
- server_close()
- process_request(request, client_address)
- shutdown_request(request)
- close_request(request)
- handle_error() Methods for derived classes: - finish_request(request, client_address) Class variables that may be overridden by derived classes or
instances: - timeout
- address_family
- socket_type
- allow_reuse_address Instance variables: - RequestHandlerClass
- socket """ timeout = None def __init__(self, server_address, RequestHandlerClass):
"""Constructor. May be extended, do not override."""
self.server_address = server_address
self.RequestHandlerClass = RequestHandlerClass
self.__is_shut_down = threading.Event()
self.__shutdown_request = False def server_activate(self):
"""Called by constructor to activate the server. May be overridden. """
pass def serve_forever(self, poll_interval=0.5):
"""Handle one request at a time until shutdown. Polls for shutdown every poll_interval seconds. Ignores
self.timeout. If you need to do periodic tasks, do them in
another thread.
"""
self.__is_shut_down.clear()
try:
while not self.__shutdown_request:
# XXX: Consider using another file descriptor or
# connecting to the socket to wake this up instead of
# polling. Polling reduces our responsiveness to a
# shutdown request and wastes cpu at all other times.
r, w, e = _eintr_retry(select.select, [self], [], [],
poll_interval)
if self in r:
self._handle_request_noblock()
finally:
self.__shutdown_request = False
self.__is_shut_down.set() def shutdown(self):
"""Stops the serve_forever loop. Blocks until the loop has finished. This must be called while
serve_forever() is running in another thread, or it will
deadlock.
"""
self.__shutdown_request = True
self.__is_shut_down.wait() # The distinction between handling, getting, processing and
# finishing a request is fairly arbitrary. Remember:
#
# - handle_request() is the top-level call. It calls
# select, get_request(), verify_request() and process_request()
# - get_request() is different for stream or datagram sockets
# - process_request() is the place that may fork a new process
# or create a new thread to finish the request
# - finish_request() instantiates the request handler class;
# this constructor will handle the request all by itself def handle_request(self):
"""Handle one request, possibly blocking. Respects self.timeout.
"""
# Support people who used socket.settimeout() to escape
# handle_request before self.timeout was available.
timeout = self.socket.gettimeout()
if timeout is None:
timeout = self.timeout
elif self.timeout is not None:
timeout = min(timeout, self.timeout)
fd_sets = _eintr_retry(select.select, [self], [], [], timeout)
if not fd_sets[0]:
self.handle_timeout()
return
self._handle_request_noblock() def _handle_request_noblock(self):
"""Handle one request, without blocking. I assume that select.select has returned that the socket is
readable before this function was called, so there should be
no risk of blocking in get_request().
"""
try:
request, client_address = self.get_request()
except socket.error:
return
if self.verify_request(request, client_address):
try:
self.process_request(request, client_address)
except:
self.handle_error(request, client_address)
self.shutdown_request(request) def handle_timeout(self):
"""Called if no new request arrives within self.timeout. Overridden by ForkingMixIn.
"""
pass def verify_request(self, request, client_address):
"""Verify the request. May be overridden. Return True if we should proceed with this request. """
return True def process_request(self, request, client_address):
"""Call finish_request. Overridden by ForkingMixIn and ThreadingMixIn. """
self.finish_request(request, client_address)
self.shutdown_request(request) def server_close(self):
"""Called to clean-up the server. May be overridden. """
pass def finish_request(self, request, client_address):
"""Finish one request by instantiating RequestHandlerClass."""
self.RequestHandlerClass(request, client_address, self) def shutdown_request(self, request):
"""Called to shutdown and close an individual request."""
self.close_request(request) def close_request(self, request):
"""Called to clean up an individual request."""
pass def handle_error(self, request, client_address):
"""Handle an error gracefully. May be overridden. The default is to print a traceback and continue. """
print '-'*40
print 'Exception happened during processing of request from',
print client_address
import traceback
traceback.print_exc() # XXX But this goes to stderr!
print '-'*40

BaseServer

 class TCPServer(BaseServer):

     """Base class for various socket-based server classes.

     Defaults to synchronous IP stream (i.e., TCP).

     Methods for the caller:

     - __init__(server_address, RequestHandlerClass, bind_and_activate=True)
- serve_forever(poll_interval=0.5)
- shutdown()
- handle_request() # if you don't use serve_forever()
- fileno() -> int # for select() Methods that may be overridden: - server_bind()
- server_activate()
- get_request() -> request, client_address
- handle_timeout()
- verify_request(request, client_address)
- process_request(request, client_address)
- shutdown_request(request)
- close_request(request)
- handle_error() Methods for derived classes: - finish_request(request, client_address) Class variables that may be overridden by derived classes or
instances: - timeout
- address_family
- socket_type
- request_queue_size (only for stream sockets)
- allow_reuse_address Instance variables: - server_address
- RequestHandlerClass
- socket """ address_family = socket.AF_INET socket_type = socket.SOCK_STREAM request_queue_size = 5 allow_reuse_address = False def __init__(self, server_address, RequestHandlerClass, bind_and_activate=True):
"""Constructor. May be extended, do not override."""
BaseServer.__init__(self, server_address, RequestHandlerClass)
self.socket = socket.socket(self.address_family,
self.socket_type)
if bind_and_activate:
try:
self.server_bind()
self.server_activate()
except:
self.server_close()
raise def server_bind(self):
"""Called by constructor to bind the socket. May be overridden. """
if self.allow_reuse_address:
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.socket.bind(self.server_address)
self.server_address = self.socket.getsockname() def server_activate(self):
"""Called by constructor to activate the server. May be overridden. """
self.socket.listen(self.request_queue_size) def server_close(self):
"""Called to clean-up the server. May be overridden. """
self.socket.close() def fileno(self):
"""Return socket file number. Interface required by select(). """
return self.socket.fileno() def get_request(self):
"""Get the request and client address from the socket. May be overridden. """
return self.socket.accept() def shutdown_request(self, request):
"""Called to shutdown and close an individual request."""
try:
#explicitly shutdown. socket.close() merely releases
#the socket and waits for GC to perform the actual close.
request.shutdown(socket.SHUT_WR)
except socket.error:
pass #some platforms may raise ENOTCONN here
self.close_request(request) def close_request(self, request):
"""Called to clean up an individual request."""
request.close()

TCPServer

 class ThreadingMixIn:
"""Mix-in class to handle each request in a new thread.""" # Decides how threads will act upon termination of the
# main process
daemon_threads = False def process_request_thread(self, request, client_address):
"""Same as in BaseServer but as a thread. In addition, exception handling is done here. """
try:
self.finish_request(request, client_address)
self.shutdown_request(request)
except:
self.handle_error(request, client_address)
self.shutdown_request(request) def process_request(self, request, client_address):
"""Start a new thread to process the request."""
t = threading.Thread(target = self.process_request_thread,
args = (request, client_address))
t.daemon = self.daemon_threads
t.start() 复制代码

ThreadingMixIn

 class ThreadingTCPServer(ThreadingMixIn, TCPServer):
pass

ThreadingTCPServer

RequestHandler相关源码

 class BaseRequestHandler:

     """Base class for request handler classes.

     This class is instantiated for each request to be handled.  The
constructor sets the instance variables request, client_address
and server, and then calls the handle() method. To implement a
specific service, all you need to do is to derive a class which
defines a handle() method. The handle() method can find the request as self.request, the
client address as self.client_address, and the server (in case it
needs access to per-server information) as self.server. Since a
separate instance is created for each request, the handle() method
can define arbitrary other instance variariables. """ def __init__(self, request, client_address, server):
self.request = request
self.client_address = client_address
self.server = server
self.setup()
try:
self.handle()
finally:
self.finish() def setup(self):
pass def handle(self):
pass def finish(self):
pass

SocketServer.BaseRequestHandler

源码精简

 import socket
import threading
import select def process(request, client_address):
print request,client_address
conn = request
conn.sendall('欢迎致电 10086,请输入1xxx,0转人工服务.')
flag = True
while flag:
data = conn.recv(1024)
if data == 'exit':
flag = False
elif data == '':
conn.sendall('通过可能会被录音.balabala一大推')
else:
conn.sendall('请重新输入.') sk = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sk.bind(('127.0.0.1',8002))
sk.listen(5) while True:
r, w, e = select.select([sk,],[],[],1)
print 'looping'
if sk in r:
print 'get request'
request, client_address = sk.accept()
t = threading.Thread(target=process, args=(request, client_address))
t.daemon = False
t.start() sk.close()

模拟SocketServer代码

从精简代码可以看出,SocketServer的ThreadingTCPServer之所以可以同时处理请求得益于selectThreading两个东西,其实本质上就是在服务器端为每一个客户端创建一个线程,用于后续的数据处理,当前线程用来处理对应客户端的请求,所以可以支持同时n个客户端链接(长连接)。

1.2 ForkingTCPServer

ForkingTCPServer与ThreadingTCPServer的使用和执行流程基本一致,只不过在内部分别为请求者建立“进程”和“线程”。

基本使用:

 #!/usr/bin/env python
# -*- coding:utf-8 -*- import SocketServer class MyServer(SocketServer.BaseRequestHandler): def handle(self):
# print self.request,self.client_address,self.server
conn = self.request
conn.sendall('欢迎致电 10086,请输入1xxx,0转人工服务.')
Flag = True
while Flag:
data = conn.recv(1024)
if data == 'exit':
Flag = False
elif data == '':
conn.sendall('通过可能会被录音.balabala一大推')
else:
conn.sendall('请重新输入.') if __name__ == '__main__':
server = SocketServer.ForkingTCPServer(('127.0.0.1',8009),MyServer)
server.serve_forever()

服务端

 #!/usr/bin/env python
# -*- coding:utf-8 -*- import socket ip_port = ('127.0.0.1',8009)
sk = socket.socket()
sk.connect(ip_port)
sk.settimeout(5) while True:
data = sk.recv(1024)
print 'receive:',data
inp = raw_input('please input:')
sk.sendall(inp)
if inp == 'exit':
break sk.close()

客户端

以上ForkingTCPServer只是将 ThreadingTCPServer 实例中的代码:

server = SocketServer.ThreadingTCPServer(('127.0.0.1',8009),MyRequestHandler)
变更为:
server = SocketServer.ForkingTCPServer(('127.0.0.1',8009),MyRequestHandler)

SocketServer的ThreadingTCPServer之所以可以同时处理请求得益于selectos.fork两个东西,其实本质上就是在服务器端为每一个客户端创建一个进程,用于后续数据处理,当前新创建的进程用来处理对应客户端的请求,所以,可以支持同时n个客户端链接(长连接)。

源码剖析参考 ThreadingTCPServer

2 Twisted模块

使用传统的BIO(Blocking IO/阻塞IO)进行网络编程时,进行网络IO读写时都会阻塞当前线程,如果实现一个TCP服务器,都需要对每个客户端连接开启一个线程,而很多线程可能都在傻傻的阻塞住等待读写数据,系统资源消耗大。

Twisted是用Python实现的基于事件驱动的网络引擎框架,功能非常丰富,基本包括了常用的网络组件,例如:网络协议、线程、数据库管理、网络操作、电子邮件等。

编程框架,即别人预先定义好的一个框架(一个项目),如.net某个web框架有25个class,从BeginRequest依次执行类里的process方法。程序员自定义一个类添加到框架里,应用程序则从上到下运行,就会执行自定义代码。框架只知道这个类的列表,不关心具体内容,从上到下执行,类似于一个执行链,C#里叫委托链。也就是把代码类放到这个列表中,委托这个框架替你执行。

事件驱动(not event),把自定义代码注册到框架中,框架代替你执行。或者框架提供几个接口,让你插入数据(python无接口概念,只有事件驱动)。委托不能为空,事件可以为空。通俗来讲,所谓事件驱动,就是说程序就像是一个报警器(reactor),时刻等待着外部事件(event),诸如有人入侵等,一旦有事件发生,程序就会触发一些特定的操作(callback),注入拨打报警电话等。

简而言之,事件驱动分为二个部分:第一,注册事件;第二,触发事件。

自定义事件驱动框架如下:

 #!/usr/bin/env python
# -*- coding:utf-8 -*- #event_drive.py event_list = [] def run():
for event in event_list:
obj = event()
obj.execute() class BaseHandler(object):
"""
用户必须继承该类,从而规范所有类的方法(类似于接口的功能)
"""
def execute(self):
raise Exception('you must overwrite execute')

自定义事件驱动框架代码

程序员使用该自定义事件驱动框架

 #!/usr/bin/env python
# -*- coding:utf-8 -*- from source import event_drive class MyHandler(event_drive.BaseHandler): def execute(self):
print 'event-drive execute MyHandler' event_drive.event_list.append(MyHandler)
event_drive.run()

程序员使用该框架代码

执行过程:
1 导入自定义框架event_drive
2 自定义类MyClass,这个类必须继承event_drive中的BaseHandler类
3 MyClass类中重载execute方法
4 注册事件到框架的委托链,把自定义的类MyClass加入到事件列表event_list中(下面的Twisted框架是创建对象后改一个字段为类名也是同样的目的)
5 执行run方法

事件驱动只不过是框架规定了执行顺序,程序员在使用框架时,可以向原执行顺序中注册“事件”,从而在框架执行时可以出发已注册 的“事件”。

基于事件驱动Twisted模块的Socket

   (1)由于twisted是第三方模块,默认没有安装,需要先安装 

cd Twisted-15.5.0
python setup.py build   #编译
python setup.py install #安装
上述安装方法适用于windows和linux的命令行安装,实际上也可以直接执行python setup.py install
注意:twisted依赖于zope和win32api模块,需要先安装依赖。

  (2)实例

 #!/usr/bin/env python
# -*- coding:utf-8 -*- from twisted.internet import protocol
from twisted.internet import reactor class Echo(protocol.Protocol): #继承protocol.py中的Protocol类
def dataReceived(self, data):
self.transport.write(data) #将收到的内容直接发送回去 def main():
factory = protocol.ServerFactory() #实例化
factory.protocol = Echo #将自定义类传给对象 reactor.listenTCP(8000,factory) #将端口和实例化对象作为参数传给reactor
reactor.run() if __name__ == '__main__':
main()

服务端

 import socket

 ip_port=('127.0.0.1',8000)
sk=socket.socket()
sk.connect(ip_port)
sk.settimeout(5) while True:
inp=raw_input("please input:")
sk.sendall(inp)
print sk.recv(1024) sk.close()

客户端

   源码类图关系

     实例执行流程

运行服务端程序
    创建Protocol的派生类Echo
    创建ServerFactory对象,并将Echo类封装到其protocol字段中
    执行reactor的listenTCP方法,内部使用tcp.Port创建socket server对象,并将该对象添加到了reactor的set类型的字段_read 中
    执行reactor的run方法,内部执行while循环,并通过select来监视_read中文件描述符是否有变化,循环中...

客户端请求到达
    执行reactor的_doReadOrWrite方法,其内部通过反射调用tcp.Port类的doRead方法,内部accept客户端连接并创建Server对象实例(用于封装客户端socket信息)和创建Echo对象实例(用于处理请求),然后调用Echo对象实例的makeConnection方法,创建连接。
    执行tcp.Server类的doRead方法,读取数据,
    执行tcp.Server类的_dataReceived方法,如果读取数据内容为空(关闭链接),否则,出发Echo的dataReceived方法
    执行Echo的dataReceived方法

    从源码可以看出,上述实例本质上使用了事件驱动的方法 和 IO多路复用的机制来进行Socket的处理。

    Pycharm debug模式调试调用关系

    Twisted优点:

1、使用基于事件驱动的编程模型,而不是多线程模型。

2、跨平台:为主流操作系统平台暴露出的事件通知系统提供统一的接口。

3、“内置电池”的能力:提供流行的应用层协议实现,因此Twisted马上就可为开发人员所用。

4、符合RFC规范,已经通过健壮的测试套件证明了其一致性。

5、能很容易的配合多个网络协议一起使用。

6、可扩展。

更多Twisted内容,请参考:

http://www.cnblogs.com/c9com/archive/2013/01/05/2845552.html(Twisted reactor解剖)

http://www.cnblogs.com/zhangjing0502/archive/2012/07/11/2586666.html(Twisted的网络通信模型

http://www.cnblogs.com/zhangjing0502/archive/2012/07/11/2586575.html(Python中reactor,factory,protocol)

http://www.cnblogs.com/zhangjing0502/archive/2012/05/16/2504415.html(Twisted异步编程--Deferred)

http://www.cnblogs.com/zhangjing0502/archive/2012/05/30/2526552.html([Python-Twisted] Twisted入门之端口转发服务器

http://www.cnblogs.com/Rex7/p/4752581.html(跟踪 twisted 里deferred 的Callback)

3 paramiko模块

linux运维中都需要对服务器进行配置,如果服务器数量较多,那么可以进行远程自动化批量操作。在python中的paramiko模块就是实现远程执行命令的模块。使用paramiko模块仅需要在本地安装相应的模块(pycrypto以及paramiko模块),对远程服务器没有配置要求,paramiko模块基于ssh协议,实现对远程服务器的相关操作,对于连接多台服务器,进行复杂的连接操作特别有帮助。

3.1 paramiko安装

1 windows下的安装paramiko
(1)解压pycrypto-2.6.tar.gz源码到路径C:\Python27\Lib\site-packages
(2)在windows控制台下进入目录pycrypto-2.6,依次执行python setup.py build和python setup.py install
   window是如果没有安装编译器,那么会报错,解决办法是安装VCForPython27.msi(Microsoft Visual C++ Compiler for Python 2.7)
   编译过程中会出现“Unable to find vcvarsall.bat”的错误,解决方法参考http://blog.csdn.net/donger_soft/article/details/44838109
   测试是否安装成功:在python命令行下输入:import pycrypto,检查是否报错
(3)解压paramiko-1.10.1.tar.gz源码到路径C:\Python27\Lib\site-packages
(4)在windows控制台下进入目录paramiko-1.10.1,依次执行python setup.py build和python setup.py install
   测试是否安装成功:在python命令行下输入:import paramiko,检查是否报错

2 ubuntu下的安装paramiko
(1)先安装python-devel(前提是要安装编译器gcc)
(2)解压pycrypto-2.6.tar.gz源码,进入目录pycrypto-2.6,执行python setup.py build && python setup.py install
   测试是否安装成功:在python命令行下输入:import pycrypto,检查是否报错
(3)解压paramiko-1.10.1.tar.gz源码,进入目录paramiko-1.10.1,执行python setup.py build && python setup.py install
   测试是否安装成功:在python命令行下输入:import paramiko,检查是否报错

3.2 paramiko使用

SSHClient方法

 #!/usr/bin/env python
#-*- coding:utf-8 -*- import paramiko ssh = paramiko.SSHClient() #创建ssh对象
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) #允许连接不在know_hosts文件中的主机
ssh.connect(hostname='192.168.1.100',port=22,username='root',password='') #hostname='主机名'或'ip地址'
stdin,stdout,stderror = ssh.exec_command('df') #在远程服务器执行命令df print stdout.read() #获取命令结果
print stderror.read() #如果命令执行错误,则返回标准错误输出
ssh.close() #关闭连接

实例1:在远程服务器执行命令

 #!/usr/bin/env python
#-*- coding:utf-8 -*- import paramiko transport = paramiko.Transport(('192.168.7.100',22)) #创建transport对象
transport.connect(username='root',password='nihao123!')#调用连接方法connect ssh = paramiko.SSHClient() #创建ssh对象
ssh._transport = transport #把上面创建的transport对象赋值给ssh对象中的_transport字段 stdin,stdout,stderr = ssh.exec_command('ifconfig') #执行命令ifconfig print stdout.read()
print stderr.read() transport.close()

实例2:在远程服务器执行命令

在上述两个实例中,其实实例1中connect内部封装了Transport,即:
   ssh = paramiko.SSHClient()
       t = self._transport = Transport(sock, gss_kex=gss_kex, gss_deleg_creds=gss_deleg_creds)
  注意:在操作文件时只能用实例2的方法

SFTPClient方法

 #!/usr/bin/env python
#-*- coding:utf-8 -*- import paramiko private_key = paramiko.RSAKey.from_private_key_file('/root/.ssh/id_rsa') ssh = paramiko.SSHClient() #创建ssh对象
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) #允许连接不在know_host文件中的的主机
ssh.connect(hostname='192.168.1.100',port=22,username='root',pkey=private_key) #连接服务器
stdin,stdout,stderr = ssh.exec_command('ifconfig') #执行命令
print stdout.read() #获取命令执行结果
ssh.close() '''
如果是运维人员这里不需要看
1、首先创建一个公钥和私钥
ssh-keygen
2、复制id_rsa.pub至要被远程执行命令的机器,并把id_rsa.pub里的内容增加至authorized_keys文件中
如果authorized_keys文件不存在创建即可
'''

实例5:基于用户名密码的上传下载

 #!/usr/bin/env python
#-*- coding:utf-8 -*- import paramiko private_key = paramiko.RSAKey.from_private_key_file('/root/.ssh/id_rsa') transport = paramiko.Transport(('192.168.1.100',22))
transport.connect(username='root',pkey=private_key) #连接 sftp = paramiko.SFTPClient.from_transport(transport)#创建SFTPClient对象 sftp.put('test.zip','/tmp/test.zip') #将test.zip上传到目标机器的/tmp/目录下,并命名为test.zip
sftp.get('/tmp/messages.log','test.log') #下载目标服务器/tmp/messages.log 到本地,并命名为test.log transport.close()

实例6:基于用户名密钥对的上传下载

在远程服务器执行命令时,其实时间主要消耗在建立连接上了。

自定义类的,在连接后进行相应的上传下载操作,这样就可以在一次连接中进行其它操作,避免频繁的创建连接,关闭连接,减少资源消耗

 #!/usr/bin/env python
#-*- coding:utf-8 -*- import paramiko
import uuid class DownUpLoad(object):
def __init__(self,ip,port,user,passwd):
self.hostname = ip
self.port = port
self.username = user
self.password = passwd def create_file(self):
file_name = str(uuid.uuid4()) #uuid.uuid4()会生成一个文件UUID,当作文件名
with open(file_name,'wb') as f:
f.write('This is test file!')
return file_name def run(self):
self.connect()
self.upload()
self.rename()
self.close() def connect(self): #连接方法
transport = paramiko.Transport((self.hostname, self.port)) #创建一个连接对象
transport.connect(username=self.username, password=self.password)#调用transport对象中的连接方法
self.__transport = transport #把transport赋值给__transport def close(self): #关闭连接
self.__transport.close() def upload(self): #上传文件方法
file_name = self.create_file() #创建文件
sftp = paramiko.SFTPClient.from_transport(self.__transport) #创建基于transport连接的SFTPClient
sftp.put(file_name,'/tmp/test.txt') #上传文件 def rename(self): #执行命名方法
ssh = paramiko.SSHClient() #建立ssh对象
ssh._transport = self.__transport #替换ssh_transport字段为self.__transport
stdin,stdout,stderr = ssh.exec_command('mv /tmp/test1 /tmp/test2') #执行命令
print stdout.read() #读取执行命令 if __name__ == '__main__':
ha = DownUpLoad()
ha.run()

自定义包含连接和上传下载方法的类

参考资料:

http://www.cnblogs.com/wupeiqi/articles/5095821.html

http://www.cnblogs.com/wupeiqi/articles/5040823.html

http://www.cnblogs.com/luotianshuai/p/5111587.html

http://www.cnblogs.com/luotianshuai/p/5131053.html

python网络编程——SocketServer/Twisted/paramiko模块的更多相关文章

  1. python网络编程socketserver模块(实现TCP客户端/服务器)

    摘录python核心编程 socketserver(python3.x版本重新命名)是标准库中的网络编程的高级模块.通过将创建网络客户端和服务器所必须的代码封装起来,简化了模板,为你提供了各种各样的类 ...

  2. python网络编程-socketserver模块

    使用socketserver 老规矩,先引入import socketserver 必须创建一个类,且继承socketserver.BaseRequestHandler 这个类中必须重写handle( ...

  3. linux下Python网络编程框架-Twisted安装

    Twisted是python下的用来进行网络服务和应用程序编程的框架,安装Twisted前需要系统预先安装有python. 一.安装Twisted http://twistedmatrix.com/R ...

  4. python网络编程--socketserver 和 ftp功能简单说明

    1. socketserver 我们之前写的tcp协议的socket是不是一次只能和一个客户端通信,如果用socketserver可以实现和多个客户端通信.它是在socket的基础上进行了一层封装,也 ...

  5. python网络编程-socketserver

    一:socketserver简化了网络服务器的编写. 它有4个类:TCPServer,UDPServer,UnixStreamServer,UnixDatagramServer. 这4个类是同步进行处 ...

  6. python 网络编程(socketserver,阻塞,其他方法)

    重点回顾: (重点)粘包 : 就是因为接收端不知道如何接收数据,造成接收数据的混乱的问题 只发生在tcp协议上. 因为tcp协议的特点是面向数据流形式的传输 粘包的发生主要是因为tcp协议有两个机制: ...

  7. Python学习(22)python网络编程

    Python 网络编程 Python 提供了两个级别访问的网络服务.: 低级别的网络服务支持基本的 Socket,它提供了标准的 BSD Sockets API,可以访问底层操作系统Socket接口的 ...

  8. Day07 - Python 网络编程 Socket

    1. Python 网络编程 Python 提供了两个级别访问网络服务: 低级别的网络服务支持基本的 Socket,它提供了标准的 BSD Sockets API,可以访问底层操作系统Socket接口 ...

  9. Python 网络编程相关知识学习

    Python 网络编程 Python 提供了两个级别访问的网络服务.: 低级别的网络服务支持基本的 Socket,它提供了标准的 BSD Sockets API,可以访问底层操作系统Socket接口的 ...

随机推荐

  1. Cross compile perl

    Alex Suykov had do some work for this purpose, and my compile script is based on her patch. Steps St ...

  2. 【Raspberry pi】GPIO注意事项

    1.GPIO编码的方法 第三列是树莓派板子上的自然编号(左边引脚为1-15,右边引脚为2-26),RPi.GPIO.setmode(GPIO.BOARD)采用这列编号 树莓派主芯片提供商Broadco ...

  3. java中Comparator的用法 -- 实现集合和数组排序

    在java中,如果要对集合对象或数组对象进行排序,需要实现Comparator接口以达到我们想要的目标. 接下来我们模拟下在集合对象中对日期属性进行排序 一.实体类Step package com.l ...

  4. HTML DOM和BOM常用操作总结

     JavaScript Code  1234567891011121314151617181920212223242526272829303132333435363738394041424344454 ...

  5. RadioButton ---- 样式效果切换

    \res\drawable\radio_button_bg.xml <?xml version="1.0" encoding="utf-8"?> & ...

  6. python中WSGI是什么

    uswgi学习文档 http://uwsgi-docs-cn.readthedocs.io/zh_CN/latest/WSGIquickstart.html WSGI是什么? WSGI,全称 Web ...

  7. SharePoint服务器端对象模型 完结

    整个系列已完结,大概看了一眼,平均阅读量不到200.估计也没什么人看了,而且服务器端对象模型除了在某些企业开发中会用到,从2013时代开始其实已经不是SharePoint开发的最佳选择了.不过既然已经 ...

  8. Get请求-Test版

    package com.fanqi.test; import java.io.DataInputStream; import java.io.IOException; import java.io.I ...

  9. Fluent Ribbon 第六步 StartScreen

    上一节,介绍了Toolbar的主要功能,说明了ToolBar的一些最基本用法,这一节,介绍Ribbon的一个重要功能startScreen, startScreen软件第一次启动,呈现的界面. 由于R ...

  10. bootstrap-table固定表头固定列

    1.引入 bootstrap依赖于jquery bootstrap-table依赖于bootstrap,所以都需要引入 2. bootstrap-table有两种方式,html.js <tabl ...