进击的Python【第八章】:动态导入模块、断言、socket开发之SSH,FTP
一、动态导入模块
知道一个模块名的字符串形式,通过字符串来导入模块
1 mod = __import__("lib.aa") 2 print(mod) 3 4 instance = getattr(mod.aa, "C") 5 6 obj = instance() 7 print(obj.name)
__import__("lib.aa")看起来是导入了lib.aa,实际上只导入了lib
下面是官方建议的用法
1 import importlib 2 importlib.import_module("lib.aa") #这里就直接导入了lib.aa
二、断言
import importlib importlib.import_module("lib.aa") obj = aa.C() assert type(obj.name) is str #assert就是断言 print("dddd")
上面表示我断定obj.name就是str,如果正确程序往下走,如果错误直接报错AssertionError
三、通过socket实现SSH功能
server端:
1 import socket ,os,time 2 server = socket.socket() 3 server.bind(('localhost',9999) ) 4 5 server.listen() 6 7 while True: 8 conn, addr = server.accept() 9 print("new conn:",addr) 10 while True: 11 print("等待新指令") 12 data = conn.recv(1024) 13 if not data: 14 print("客户端已断开") 15 break 16 print("执行指令:",data) 17 cmd_res = os.popen(data.decode()).read() #接受字符串,执行结果也是字符串 18 print("before send",len(cmd_res)) 19 if len(cmd_res) ==0: 20 cmd_res = "cmd has no output..." 21 22 conn.send( str(len(cmd_res.encode())).encode("utf-8") ) #先发大小给客户端 23 #time.sleep(0.5) #lowb防粘包 24 client_ack = conn.recv(1024) #等待客户端应答,高端防粘包 25 conn.send(cmd_res.encode("utf-8")) 26 print("send done") 27 os.path.isfile() 28 os.stat("sock") 29 server.close() 30
client端:
1 import socket 2 client = socket.socket() 3 4 client.connect(('localhost',9999)) 5 6 while True: 7 cmd = input(">>:").strip() 8 if len(cmd) == 0: continue 9 client.send(cmd.encode("utf-8")) 10 cmd_res_size = client.recv(1024) ##接受命令结果的长度 11 print("命令结果大小:",cmd_res_size) 12 client.send("准备好接受".encode("utf-8")) #防粘包 13 received_size = 0 14 received_data = b'' 15 while received_size < int(cmd_res_size.decode()) : 16 data = client.recv(1024) 17 received_size += len(data) #每次收到的有可能小于1024,所以必须用len判断 18 #print(data.decode()) 19 received_data += data 20 else: 21 print("cmd res receive done...",received_size) 22 print(received_data.decode()) 23 24 25 client.close()
四、通过socket实现FTP功能
client端:
1 import socket 2 import hashlib 3 4 client = socket.socket() 5 6 client.connect(('localhost', 9999)) 7 8 while True: 9 cmd = input(">>:").strip() 10 if len(cmd) == 0: continue 11 if cmd.startswith("get"): 12 client.send(cmd.encode()) 13 server_response = client.recv(1024) 14 print("servr response:", server_response) 15 client.send(b"ready to recv file") 16 file_total_size = int(server_response.decode()) 17 received_size = 0 18 filename = cmd.split()[1] 19 f = open(filename + ".new", "wb") 20 m = hashlib.md5() 21 22 while received_size < file_total_size: 23 if file_total_size - received_size > 1024: # 要收不止一次 24 size = 1024 25 else: # 最后一次了,剩多少收多少 26 size = file_total_size - received_size 27 print("last receive:", size) 28 29 data = client.recv(size) 30 received_size += len(data) 31 m.update(data) # 记录MD5 32 f.write(data) 33 # print(file_total_size,received_size) 34 else: 35 new_file_md5 = m.hexdigest() 36 print("file recv done", received_size, file_total_size) 37 f.close() 38 server_file_md5 = client.recv(1024) 39 print("server file md5:", server_file_md5) # 输出服务端文件MD5 40 print("client file md5:", new_file_md5) # 输出传过来的文件的MD5 41 42 client.close()
server端:
1 import hashlib 2 import socket ,os,time 3 server = socket.socket() 4 server.bind(('0.0.0.0',9999) ) 5 server.listen() 6 while True: 7 conn, addr = server.accept() 8 print("new conn:",addr) 9 while True: 10 print("等待新指令") 11 data = conn.recv(1024) 12 if not data: 13 print("客户端已断开") 14 break 15 cmd,filename = data.decode().split() 16 print(filename) 17 if os.path.isfile(filename): 18 f = open(filename,"rb") 19 m = hashlib.md5() 20 file_size = os.stat(filename).st_size 21 conn.send( str(file_size).encode() ) #send file size 22 conn.recv(1024) #wait for ack 23 for line in f: 24 m.update(line) 25 conn.send(line) 26 print("file md5", m.hexdigest()) 27 f.close() 28 conn.send(m.hexdigest().encode()) #send md5 29 print("send done") 30 31 server.close()
五、通过SocketServer实现多并发
The socketserver
module simplifies the task of writing network servers.
There are four basic concrete server classes:
1 class socketserver.TCPServer(server_address, RequestHandlerClass, bind_and_activate=True)
This uses the Internet TCP protocol, which provides for continuous streams of data between the client and server. If bind_and_activate is true, the constructor automatically attempts to invoke server_bind()
andserver_activate()
. The other parameters are passed to the BaseServer
base class.
1 class socketserver.UDPServer(server_address, RequestHandlerClass, bind_and_activate=True)
This uses datagrams, which are discrete packets of information that may arrive out of order or be lost while in transit. The parameters are the same as for TCPServer
.
1 class socketserver.UnixStreamServer(server_address, RequestHandlerClass, bind_and_activate=True) 2 class socketserver.UnixDatagramServer(server_address, RequestHandlerClass,bind_and_activate=True)
-
These more infrequently used classes are similar to the TCP and UDP classes, but use Unix domain sockets; they’re not available on non-Unix platforms. The parameters are the same as for
TCPServer
.
These four classes process requests synchronously; each request must be completed before the next request can be started. This isn’t suitable if each request takes a long time to complete, because it requires a lot of computation, or because it returns a lot of data which the client is slow to process. The solution is to create a separate process or thread to handle each request; the ForkingMixIn
and ThreadingMixIn
mix-in classes can be used to support asynchronous behaviour.
There are five classes in an inheritance diagram, four of which represent synchronous servers of four types:
+------------+
| BaseServer |
+------------+
|
v
+-----------+ +------------------+
| TCPServer |------->| UnixStreamServer |
+-----------+ +------------------+
|
v
+-----------+ +--------------------+
| UDPServer |------->| UnixDatagramServer |
+-----------+ +--------------------+
创建一个socketserver 至少分以下几步:
- First, you must create a request handler class by subclassing the
BaseRequestHandler
class and overriding itshandle()
method; this method will process incoming requests. - Second, you must instantiate one of the server classes, passing it the server’s address and the request handler class.
- Then call the
handle_request()
orserve_forever()
method of the server object to process one or many requests. - Finally, call
server_close()
to close the socket.
基本的socketserver代码
1 import socketserver 2 3 class MyTCPHandler(socketserver.BaseRequestHandler): 4 """ 5 The request handler class for our server. 6 7 It is instantiated once per connection to the server, and must 8 override the handle() method to implement communication to the 9 client. 10 """ 11 12 def handle(self): 13 # self.request is the TCP socket connected to the client 14 self.data = self.request.recv(1024).strip() 15 print("{} wrote:".format(self.client_address[0])) 16 print(self.data) 17 # just send back the same data, but upper-cased 18 self.request.sendall(self.data.upper()) 19 20 if __name__ == "__main__": 21 HOST, PORT = "localhost", 9999 22 23 # Create the server, binding to localhost on port 9999 24 server = socketserver.TCPServer((HOST, PORT), MyTCPHandler) 25 26 # Activate the server; this will keep running until you 27 # interrupt the program with Ctrl-C 28 server.serve_forever()
上面的代码虽然使用了socketserver,但是依然不能实现多并发,我们要想实现多并发通信,需要用到下面这些多并发类
class socketserver.
ForkingTCPServer
class socketserver.
ForkingUDPServer
class socketserver.
ThreadingTCPServer
class socketserver.
ThreadingUDPServer
我们只需要把上面的代码中的
1 server = socketserver.TCPServer((HOST, PORT), MyTCPHandler)
替换为:
1 server = socketserver.ThreadingTCPServer((HOST, PORT), MyTCPHandler)
就可以实现多线程多并发了
下面我们举个栗子:
1 import socketserver 2 3 class MyTCPHandler(socketserver.BaseRequestHandler): 4 def handle(self): 5 while True: 6 try: 7 self.data = self.request.recv(1024).strip() 8 print("{} wrote:".format(self.client_address[0])) 9 print(self.data) 10 self.request.send(self.data.upper()) 11 except ConnectionResetError as e: 12 print("err",e) 13 break 14 if __name__ == "__main__": 15 HOST, PORT = "localhost", 9999 16 # Create the server, binding to localhost on port 9999 17 server = socketserver.ThreadingTCPServer((HOST, PORT), MyTCPHandler) 18 server.serve_forever()