zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    fastjson
    抽象类和接口
    Linux发行版,分类,CentOS下载
    《Head First 设计模式》读后总结:基础,原则,模式
    java.lang.NoSuchMethodError
    在word中优雅地插入代码
    Java读取Maven工程下的配置文件,工具类
    移动互联网10年,传奇一直在发生
    Spring整合MybatisPlus学习笔记
    IDEA环境下SSM整合------注解开发
  • 原文地址:https://www.cnblogs.com/sshcy/p/8232666.html
Copyright © 2011-2022 走看看