WEEK8:Python网络编程 Socket编程
- 动态导入模块
- 使用python内置方法__import__导入模块
1 #环境 2 #动态导入模块.py 3 #lib 4 #--__pycache__ 5 #--__init__.py 6 #--aa.py 7 8 #方法一 9 lib=__import__("lib.aa") #解释器内部使用 10 obj=lib.aa.C() 11 print(obj.name) 12 #方法二 13 import importlib 14 importlib.import_moudle("lib.aa") 15 print(aa.C().name)
- 使用python内置方法__import__导入模块
- 断言
- assert断言语句用来声明某个条件是真的,其作用是测试一个条件(condition)是否成立,如果不成立,则抛出异常。
- assert一般用法: assert condition
等同下面的逻辑:
如果condition为false,就raise一个AssertionError出来。逻辑上等同于:
if not condition:
raise AssertionError() - 另一种使用方法:assert condition,expression
如果condition为false,就raise一个描述为 expression 的AssertionError出来。逻辑上等同于:
if not condition:
raise AssertionError(expression)
assert的异常参数,其实就是在断言表达式后添加字符串信息,用来解释断言并更好的知道是哪里出了问题。格式如下:
assert expression [, arguments]
assert 表达式 [, 参数]
- 简易的SSH
- 客户端
1 import socket 2 client = socket.socket() 3 4 5 client.connect(('localhost',9999)) 6 7 while True: 8 cmd = input(">>:").strip() 9 if len(cmd) == 0: continue 10 client.send(cmd.encode("utf-8")) 11 cmd_res_size = client.recv(1024) ##接受命令结果的长度 12 print("命令结果大小:",cmd_res_size)
client.send("准备好接收了,loser可以发了".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 client.close() - 服务端
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)
client_ack=conn.recv(1024) #等待客户端确认
print("ack from client:",client_ack)
24 conn.send(cmd_res.encode("utf-8")) 25 print("send done") 26 #os.path.isfile() 27 #os.stat("sock") 28 server.close()
- 客户端
- FTP server
- 读取文件名
- 检测文件是否存在
- 打开文件
- 检测文件大小
- 发送文件大小给客户端
- 等待客户端确认
- 开始边读边发数据
- 发送MD5进行确认
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 server.close()
- FTP client
1 import socket 2 import hashlib 3 client = socket.socket() 4 client.connect(('localhost', 9999)) 5 while True: 6 cmd = input(">>:").strip() 7 if len(cmd) == 0: continue 8 if cmd.startswith("get"): 9 client.send(cmd.encode()) 10 server_response = client.recv(1024) 11 print("servr response:", server_response) 12 client.send(b"ready to recv file") 13 file_total_size = int(server_response.decode()) 14 received_size = 0 15 filename = cmd.split()[1] 16 f = open(filename + ".new", "wb") 17 m = hashlib.md5() 18 while received_size < file_total_size: 19 if file_total_size - received_size > 1024: # 要收不止一次 20 size = 1024 21 else: # 最后一次了,剩多少收多少 22 size = file_total_size - received_size 23 print("last receive:", size) 24 data = client.recv(size) 25 received_size += len(data) 26 m.update(data) 27 f.write(data) 28 # print(file_total_size,received_size) 29 else: 30 new_file_md5 = m.hexdigest() 31 print("file recv done", received_size, file_total_size) 32 f.close() 33 server_file_md5 = client.recv(1024) 34 print("server file md5:", server_file_md5) 35 print("client file md5:", new_file_md5) 36 client.close()
- SocketServer #简化网络服务的开发
详情请见:https://www.cnblogs.com/Security-Darren/p/4594393.html
- 主要类型
该模块有四个比较主要的类,其中常用的是 TCPServer 和 UDPServer。
- TCPServer(
socketserver.TCPServer
) - UDPServer(
socketserver.UDPServer
) - UnixStreamServer(
socketserver.UnixStreamServer
),类似于TCPServer提供面向数据流的套接字连接,但是旨在UNIX平台上可用 - UnixDatagramServer(
socketserver.UnixDatagramServer
),类似于UDPServer提供面向数据报的套接字连接,但是旨在UNIX平台上可用
这四个类型同步地处理请求,也就是说一个请求没有完成之前是不会处理下一个请求的,这种模式当然不适合生产环境,一个客户端连接就可能拖延所有的执行。所以这个模块还提供了两种支持异步处理的类: - ForkingMixIn(
socketserver.
ForkingTCPServer
或者socketserver.
ForkingUDPServer
),为每一个客户端请求派生一个新的进程去专门处理(在Windows系统上无法使用(原因:调用fork),在Linux平台上正常运行) - ThreadingMixIn(
socketserver.
ThreadingTCPServer
或者socketserver.
ThreadingUDPServer
),为每一个客户端请求派生一个新的线程去专门处理
继承自这两个类型的服务端在处理新的客户端连接时不会阻塞,而是创建新的进/线程专门处理客户端的请求
- TCPServer(
- 创建socketserver步骤:
- 根据需要选择一个合适的服务类型,如面向TCP连接的多进程服务器:ForkingTCPServer
- 创建一个请求处理器(request handler)类型,这个类型的 handle()(类似于回调函数)方法中定义如何处理到达的客户端连接
- 实例化服务器,传入服务器绑定的地址和第2步定义的请求处理器类
- 调用服务器实例的handle_request()或serve_forever()方法,一次或多次处理客户请求
- 客户端
1 import socket 2 client = socket.socket() 3 4 #client.connect(('192.168.16.200',9999)) 5 client.connect(('localhost',9999)) 6 7 while True: 8 cmd = input(">>:").strip() 9 if len(cmd) == 0: continue 10 client.send(cmd.encode("utf-8")) 11 cmd_res_size = client.recv(1024) ##接受命令结果的长度 12 print("命令结果大小:",cmd_res_size) 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 client.close()
- 服务端
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()
- 主要类型
仰天大笑出门去,吾辈岂是蓬蒿人!