学习python_day10
io多路复用的封装服务端
模块名:panglicai
import socket import select class Panglicai(object): def __init__(self,routers): self.routers = routers def process_data(self,conn): data = bytes() while True: try: chunk = conn.recv(4096) except Exception as e: chunk = None if not chunk: break data += chunk data_str = str(data,encoding="utf-8") header,body = data_str.split("\r\n\r\n",1) header_list = header.split("\r\n") header_dict ={} for line in header_list: value = line.split(":",1) if len(value) ==2: k,v = value header_dict[k]=v else: header_dict["method"],header_dict["url"],header_dict["protal"]=line.split(" ") return header_dict ,body def run(self,host="127.0.0.1",port = 8888): sk= socket.socket() sk.setblocking(False) sk.bind((host,port)) sk.listen(5) inputs = [sk,] while True: try: r,w,e = select.select(inputs,[],[],0.5) for client in r: if client ==sk: conn,addr = client.accept() inputs.append(conn) conn.setblocking(False) else: header_dict,body = self.process_data(client) reuest_url=header_dict["url"] # routers = [ # ('/index.html', f1), # ('/login.html', f2) # ] func_name = None for item in self.routers: if item[0]==reuest_url: func_name =item[1] break if not func_name: client.sendall(b"404") else: reslut = func_name(header_dict,body) client.sendall(reslut.encode()) inputs.remove(client) client.close() except OSError as e: pass
导入模块
import panglicai def f1(header_dict,body): return "beautiful!" def f2(header_dict,body): return "漂亮!" routers = [ ("/index.html",f1), ("/login.html",f2), ] obj = panglicai.Panglicai(routers) obj.run()
socket客户端:利用一个线程,同时发送n个请求(异步非阻塞模块)
实现过程:循环列表,为每个url生成一个socket对象
url = [http://www.baidu.com,http://cnblogs.com,]每个socket对象向远程发送链接请求,如果链接成功,发送数据(遵循http协议格式),获取响应内容,关闭链接
注意:当socket对象发送链接请求时,是等待服务端响应,这时socket对象是可读的(读服务端返回允许链接),等读到服务端响应允许连接时,表示已经链接成功了,
链接成功后,socket对象就变成可写了,就是发送数据,发送完数据就变为可读状态了,是为了等待接受服务端返回的数据了,(等待接受服务端响应是可读,自己发送数据是可写)。
1、单独的一个知识点
import select import socket sk = socket.socket() sk.bind(("127.0.0.1",8888)) sk.listen(5) inputs = [sk,] # class Foo(object): # def __init__(self,name): # self.sk = socket.socket() # self.name = name # def fileno(self): # return self.sk.fileno() while True: r,w,e = select.select(inputs,[],[],0.5)#inputs 就是[sk,] #select模块监听的就是[sk,]列表,他内部会自动调用fileno方法实现监听的(socket对象内部有个fileno方法) #所以[sk,]列表中个放其他的对象只要按照规则就行,我们就可以封装socket对象了 #r,w,e = select.select([Foo(),[],[],0.5])这样就可以把socket对象封装在Foo()中了,又可以添加新的功能(Foo().name ) # 因此[]列表中添加的对象只要能自动执行fileno方法调用出socket对象的fileno方法就行,
也把客户端做成模块化,模块名:iomodle
import select import socket class Foo(object): def __init__(self,sock,callback,url,host): self.sock = sock self.callback = callback self.url =url self.host = host def fileno(self): return self.sock.fileno() class Nbio(object): def __init__(self): self.fds = [] self.connetions = [] def request(self,url_list): for item in url_list: conn=socket.socket() conn.setblocking(False)#不等待上个连接同时发送url_list中的所有请求连接,不加会等待一个连接成功后再发送下个连接 try: conn.connect((item["host"],80)) except BlockingIOError as e: pass obj = Foo(conn,item["callback"],item["url"],item["host"]) self.fds.append(obj) self.connetions.append(obj) def send(self):#连接成功后监听conn的变化 while True: try: if len(self.fds) == 0:#等于0时说明都返回了数据处理完了 return #w:代表可写,如果w有对象就代表连接成功了 r,w,e = select.select(self.fds,self.connetions,self.fds,0.5) for obj in r: conn = obj.sock data =bytes() while True: try: d = conn.recv(1024) data+=d except BlockingIOError as e: d = None if not d: break obj.callback(data) self.fds.remove(obj) for obj in w: conn = obj.sock templet = "GET %s HTTP/1.1\r\nHost: %s\r\n\r\n" %(obj.url,obj.host,) conn.send(templet.encode()) self.connetions.remove(obj) except OSError as e:#OSError 是系统问题在linux和mac上不会报这个错(是当监听的r w都为空时Windows会报错) pass
导入模块使用
""" socket客户端同时发送多个请求,收到响应后根据不同的请求调用不同的函数处理 """ import iomodle def f1(data): print(data) def f2(data): print(data) url_list =[ {"host":"www.baidu.com","url":"/","callback":f1}, {"host":"www.cnblogs.com","url":"/plc-python","callback":f2}, {"host":"www.bing.com","url":"/","callback":f1}, ] panglicai = iomodle.Nbio() panglicai.request(url_list) panglicai.send()
paramiko,第三方模块,内部封装了socket 可以根据ssh协议发送数据和接受数据
导入模块,用python代码实现远程服务的操作
SSHClient
基于用户名密码连接:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
import paramiko # 创建SSH对象ssh = paramiko.SSHClient()# 允许连接不在know_hosts文件中的主机ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())# 连接服务器ssh.connect(hostname='c1.salt.com', port=22, username='wupeiqi', password='123') # 执行命令stdin, stdout, stderr = ssh.exec_command('df')# 获取命令结果result = stdout.read() # 关闭连接ssh.close() |
SSHClient内部其实也是调用的transport
import paramiko transport = paramiko.Transport(('hostname', 22)) transport.connect(username='wupeiqi', password='123') ssh = paramiko.SSHClient() ssh._transport = transport stdin, stdout, stderr = ssh.exec_command('df') print stdout.read() transport.close()
基于公钥密钥连接:
import paramikoprivate_key = paramiko.RSAKey.from_private_key_file('/home/auto/.ssh/id_rsa')# 创建SSH对象ssh = paramiko.SSHClient()# 允许连接不在know_hosts文件中的主机ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())# 连接服务器ssh.connect(hostname='c1.salt.com', port=22, username='wupeiqi', key=private_key)# 执行命令stdin, stdout, stderr = ssh.exec_command('df')# 获取命令结果result = stdout.read()# 关闭连接ssh.close()
import paramiko private_key = paramiko.RSAKey.from_private_key_file('/home/auto/.ssh/id_rsa') transport = paramiko.Transport(('hostname', 22)) transport.connect(username='wupeiqi', pkey=private_key) ssh = paramiko.SSHClient() ssh._transport = transport stdin, stdout, stderr = ssh.exec_command('df') transport.close()
import paramiko from io import StringIO key_str = """-----BEGIN RSA PRIVATE KEY----- MIIEpQIBAAKCAQEAq7gLsqYArAFco02/55IgNg0r7NXOtEM3qXpb/dabJ5Uyky/8 NEHhFiQ7deHIRIuTW5Zb0kD6h6EBbVlUMBmwJrC2oSzySLU1w+ZNfH0PE6W6fans H80whhuc/YgP+fjiO+VR/gFcqib8Rll5UfYzf5H8uuOnDeIXGCVgyHQSmt8if1+e 7hn1MVO1Lrm9Fco8ABI7dyv8/ZEwoSfh2C9rGYgA58LT1FkBRkOePbHD43xNfAYC tfLvz6LErMnwdOW4sNMEWWAWv1fsTB35PAm5CazfKzmam9n5IQXhmUNcNvmaZtvP c4f4g59mdsaWNtNaY96UjOfx83Om86gmdkKcnwIDAQABAoIBAQCnDBGFJuv8aA7A ZkBLe+GN815JtOyye7lIS1n2I7En3oImoUWNaJEYwwJ8+LmjxMwDCtAkR0XwbvY+ c+nsKPEtkjb3sAu6I148RmwWsGncSRqUaJrljOypaW9dS+GO4Ujjz3/lw1lrxSUh IqVc0E7kyRW8kP3QCaNBwArYteHreZFFp6XmtKMtXaEA3saJYILxaaXlYkoRi4k8 S2/K8aw3ZMR4tDCOfB4o47JaeiA/e185RK3A+mLn9xTDhTdZqTQpv17/YRPcgmwz zu30fhVXQT/SuI0sO+bzCO4YGoEwoBX718AWhdLJFoFq1B7k2ZEzXTAtjEXQEWm6 01ndU/jhAasdfasdasdfasdfa3eraszxqwefasdfadasdffsFIfAsjQb4HdkmHuC OeJrJOd+CYvdEeqJJNnF6AbHyYHIECkj0Qq1kEfLOEsqzd5nDbtkKBte6M1trbjl HtJ2Yb8w6o/q/6Sbj7wf/cW3LIYEdeVCjScozVcQ9R83ea05J+QOAr4nAoGBAMaq UzLJfLNWZ5Qosmir2oHStFlZpxspax/ln7DlWLW4wPB4YJalSVovF2Buo8hr8X65 lnPiE41M+G0Z7icEXiFyDBFDCtzx0x/RmaBokLathrFtI81UCx4gQPLaSVNMlvQA 539GsubSrO4LpHRNGg/weZ6EqQOXvHvkUkm2bDDJAoGATytFNxen6GtC0ZT3SRQM WYfasdf3xbtuykmnluiofasd2sfmjnljkt7khghmghdasSDFGQfgaFoKfaawoYeH C2XasVUsVviBn8kPSLSVBPX4JUfQmA6h8HsajeVahxN1U9e0nYJ0sYDQFUMTS2t8 RT57+WK/0ONwTWHdu+KnaJECgYEAid/ta8LQC3p82iNAZkpWlGDSD2yb/8rH8NQg 9tjEryFwrbMtfX9qn+8srx06B796U3OjifstjJQNmVI0qNlsJpQK8fPwVxRxbJS/ pMbNICrf3sUa4sZgDOFfkeuSlgACh4cVIozDXlR59Z8Y3CoiW0uObEgvMDIfenAj 98pl3ZkCgYEAj/UCSni0dwX4pnKNPm6LUgiS7QvIgM3H9piyt8aipQuzBi5LUKWw DlQC4Zb73nHgdREtQYYXTu7p27Bl0Gizz1sW2eSgxFU8eTh+ucfVwOXKAXKU5SeI +MbuBfUYQ4if2N/BXn47+/ecf3A4KgB37Le5SbLDddwCNxGlBzbpBa0= -----END RSA PRIVATE KEY-----""" private_key = paramiko.RSAKey(file_obj=StringIO(key_str)) transport = paramiko.Transport(('10.0.1.40', 22)) transport.connect(username='wupeiqi', pkey=private_key) ssh = paramiko.SSHClient() ssh._transport = transport stdin, stdout, stderr = ssh.exec_command('df') result = stdout.read() transport.close() print(result)
SFTPClient
用于连接远程服务器并执行上传下载
基于用户名密码上传下载
import paramikotransport = paramiko.Transport(('hostname',22))transport.connect(username='wupeiqi',password='123')sftp = paramiko.SFTPClient.from_transport(transport)# 将location.py 上传至服务器 /tmp/test.pysftp.put('/tmp/location.py', '/tmp/test.py')# 将remove_path 下载到本地 local_pathsftp.get('remove_path', 'local_path')transport.close()基于公钥密钥上传下载
import paramiko private_key = paramiko.RSAKey.from_private_key_file('/home/auto/.ssh/id_rsa') transport = paramiko.Transport(('hostname', 22)) transport.connect(username='wupeiqi', pkey=private_key ) sftp = paramiko.SFTPClient.from_transport(transport) # 将location.py 上传至服务器 /tmp/test.py sftp.put('/tmp/location.py', '/tmp/test.py') # 将remove_path 下载到本地 local_path sftp.get('remove_path', 'local_path') transport.close()
把paramiko模块实现的命名和文件封装到一个模块中同时实现两种功能
import paramiko class SshHelper(object): def __init__(self,host,port,username,pwd): self.host = host self.port = port self.username = username self.pwd = pwd self.transport = None def connect(self): transport = paramiko.Transport((self.host, self.port,)) transport.connect(username=self.username, password=self.pwd) self.transport = transport def upload(self,local,target): sftp = paramiko.SFTPClient.from_transport(self.transport) # 将location.py 上传至服务器 /tmp/test.py sftp.put(local, target) # 将remove_path 下载到本地 local_path # sftp.get('remove_path', 'local_path') def cmd(self,shell): ssh = paramiko.SSHClient() ssh._transport = self.transport stdin, stdout, stderr = ssh.exec_command(shell) res=stdout.read() print(res) def close(self): self.transport.close() if __name__ == '__main__': obj = SshHelper('192.168.3.65',22,"root","redhat") obj.connect() obj.cmd("ls") obj.upload("C:/Users/panglc/PycharmProjects/day1/day10/panglicai.py","/tmp/test.py") #....可以执行多次 obj.close()

浙公网安备 33010602011771号