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)
  • 断言
    • 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),为每一个客户端请求派生一个新的线程去专门处理
        继承自这两个类型的服务端在处理新的客户端连接时不会阻塞,而是创建新的进/线程专门处理客户端的请求
    • 创建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()

       

posted @ 2019-06-11 21:39  飞琼君  阅读(177)  评论(0编辑  收藏  举报