socketserver 编程

socket粘包                                

  原理:服务器端或客户端连续调用2次send时,数据其实并没有立刻被发送出去,而是放到了系统的socket发送缓冲区里,等缓冲区满了、或者数据等待超时了,数据才会被send到客户端,这样就把好几次的小数据拼成一个大数据,统一发送,这么做的目地是为了提高io利用效率,一次性发送总比连发好几次效率高嘛。 但也带来一个问题,就是“粘包”,即2次或多次的数据粘在了一起统一发送。

  解决方法:

  1. 设置超时时间  time.sleep(0.5)

  2. 客户端发送确认 conn.recv(1024)

  3. 添加 进行进行数据区分

  4. 检测最后一次还剩多少就收多少

socketserver介绍                         

   socketserver模块实际上是socket的封装,简化了编写网络服务程序的任务。同时SocketServer模块也 是Python标准库中很多服务器框架的基础。

        socketserver中包含了两种类,一种为服务类(server class),一种为请求处理类(request handle class)。前者提供了许多方法:像绑定,监听,运行…… (也就是建立连接的过程) 后者则专注于如何处理用户所发送的数据(也就是事务逻辑)。

5种类型:BaseServer,TCPServer,UnixStreamServer,UDPServer,UnixDatagramServer。

BaseServer不直接对外服务。

TCPServer针对TCP套接字流(ThreadingTCPServer、ForkingTCPServer为多并发)

UDPServer针对UDP数据报套接字(ThreadingUDPServer、ForkingUDPServer为多并发)

UnixStreamServer和UnixDatagramServer针对UNIX域套接字,不常用。

        +------------+
        | BaseServer |
        +------------+
              |
              v
        +-----------+        +------------------+
        | TCPServer |------->| UnixStreamServer |
        +-----------+        +------------------+
              |
              v
        +-----------+        +--------------------+
        | UDPServer |------->| UnixDatagramServer |
        +-----------+        +--------------------+
BaseRequestHandler类的实例h可以实现以下方法 

h.handle() 调用该方法执行实际的请求操作。调用该函数可以不带任何参数,但是几个实例变量包含有用的值。h.request包含请求,h.client_address包含客户端地址,h.server包含调用处理程序的实例。
对于TCP之类的数据流服务,h.request属性是套接字对象。对于数据报服务,它是包含收到数据的字节字符串。 h.setup() 该方法在handle()之前调用。默认情况下,它不执行任何操作。如果希望服务器实现更多连接设置(如建立SSL连接),可以在这里实现。 h.finish() 调用本方法可以在执行完handle()之后执行清除操作。默认情况下,它不执行任何操作。如果setup()和handle()方法都不生成异常,则无需调用该方法。
 1 import socketserver
 2 import threading
 3 import socket
 4 
 5 
 6 class MyTCPHandler(socketserver.BaseRequestHandler):
 7     def setup(self):
 8         ip = self.client_address[0].strip()  # 获取客户端的ip
 9         port = self.client_address[1]  # 获取客户端的port
10         print(ip + ":" + str(port) + " is connect!")
11 
12     def handle(self):
13         # while True:  # while循环
14         data = str(self.request.recv(1024), 'ascii')
15         if data:  # 判断是否接收到数据
16             cur_thread = threading.current_thread()
17             response = bytes("{}: {}".format(cur_thread.name, data), 'ascii')
18             self.request.sendall(response)
19 
20     def finish(self):
21         print("client is disconnect!")
22 
23 
24 def client(ip, port, message):
25     with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
26         sock.connect((ip, port))
27         sock.sendall(bytes(message, 'ascii'))
28         response = str(sock.recv(1024), 'ascii')
29         print("Received: {}".format(response))
30 
31 
32 if __name__ == "__main__":
33     # Port 0 means to select an arbitrary unused port
34     HOST, PORT = "localhost", 0
35 
36     server = socketserver.TCPServer((HOST, PORT), MyTCPHandler)
37     ip, port = server.server_address
38 
39     # Start a thread with the server -- that thread will then start one
40     # more thread for each request
41     server_thread = threading.Thread(target=server.serve_forever)
42     # Exit the server thread when the main thread terminates
43     server_thread.daemon = True
44     server_thread.start()
45     print("Server loop running in thread:", server_thread.name)
46 
47     client(ip, port, "Hello World 1")
48     # client(ip, port, "Hello World 2")
49     # client(ip, port, "Hello World 3")
50 
51     server.shutdown()
52     server.server_close()
socketserver实例

 

 server = socketserver.TCPServer((HOST, PORT), MyTCPHandler)   # 单线程

server = socketserver.ThreadingTCPServer((HOST, PORT), MyTCPHandler)   # 多线程,每连接一个新用户多开一个线程

server = socketserver.ForkingTCPServer((HOST, PORT), MyTCPHandler)    # 多进程,每连接一个新用户多开一个进程

BaseServer 主要用法                       

 1 class socketserver.BaseServer(server_address, RequestHandlerClass)
 2 
 3 fileno()     # 文件描述
 4 
 5 hand_request()   # 处理单个请求
 6 
 7 serve_forever(poll_interval=0.5)    # 处理多个请求, poll_interval设置每0.5秒轮询是否关闭, 跳过超时属性,能够调service_actions()清理僵尸子进程
 8 
 9 
10 service_actions()   # 能够让server_forever循环调用
11 
12 shutdown()  # 告诉server_forever()循环停止
13 
14 server_close()  # 清除server
15 
16 address_family    # 地址簇
17 
18 RequestHandlerClass   # 请求处理类,为每一个请求创建实例
19 
20 server_address     # (ip,port)
21 
22 allow_reuse_address    # 地址重用, 默认是false
23 
24 socket_type   # socket类型,普遍是socket.SOCK_STREAM和socket.SOCK_DGRAM
25 
26 finish_request()   # 实例化RequestHandlerClass实际处理请求并调用handle()方法
27 
28 verify_request(request, client_address)  # 返回布尔值, 默认为true, 为true处理请求, false不处理

补充知识点                                 

查文件大小,不用把文件都读取出来:os.stat(filename).st_size

原文地址:https://www.cnblogs.com/sshcy/p/8232666.html