zoukankan      html  css  js  c++  java
  • Python学习之UDP版socket&SocketServer

    7.6 基于UDP的socket

    无连接的,不必与对方建立连接,而是直接把数据发送给对方;
    适用于一次传输销量数据结构,可靠性不高的应用环境,因为其传输速率快

    # 服务端
    import socket
    server = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)  #这里的餐宿已经改成UDP格式了
    
    server.bind(('127.0.0.1',9000))
    
    while 1:
        from_client_data = server.recvfrom(1024)
        print(f"来自{from_client_data[1]}的消息:{from_client_data[0].decode('utf-8')}")
        se = input('>>>').encode('utf-8')
        server.sendto(se,from_client_data[1])
        
    # 客户端
    import socket
    
    client = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)   #这里的餐宿已经改成UDP格式了
    
    while 1:
        se = input('>>>').encode('utf-8')
        client.sendto(se,('127.0.0.1',9000))
        re = client.recvfrom(1024)
        print(f"来自{re[1]}的消息:{re[0].decode('utf-8')}")
    # 虽然可以实现能够与多个人进行数据交换,但实际上是在发送完数据后关闭了链接,并不是真正意义上的并行运行
    
    
    

    7.7 socketserver实现并行运行

    服务端

    import socketserver
    
    class Myserver(socketserver.BaseRequestHandler): # 定义的类名可以任意取,继承的父类固定格式
    
        def handle(self):       # 必须要使用handle这个名字
            print('listening_in_handle')
            while 1:
    
                from_client_data = self.request.recv(1024).decode('utf-8')
                print(from_client_data)
    
                to_client_data = input('>>>').strip()
                self.request.send(to_client_data.encode('utf-8'))
    
    
    if __name__ == '__main__':
    
    
        ip_port = ('127.0.0.1',8006)
        # socketserver.TCPServer.allow_reuse_address = True  # 允许端口重复使用
        server = socketserver.ThreadingTCPServer(ip_port,Myserver)   # 固定格式
        # 对 socketserver.ThreadingTCPServer 类实例化对象,将ip地址,端口号以及自己定义的类名传入,并返回一个对象
        server.serve_forever()   # 固定格式,对象执行serve_forever方法,开启服务端
        print('listening_begin')
    

    客户端

    可以设置多个客户端

    import socket
    
    client = socket.socket()
    
    client.connect(('127.0.0.1',8006))
    while 1:
        se = input('>>>').strip()
        client.send(se.encode('utf-8'))
        re = client.recv(1024).decode('utf-8')
        print(f"the massage from server:{re}")
    
    client.close()
    

    分析

    在整个socketserver这个模块中,最主要的两件事情:
    1、一个是循环建立链接的部分,每个客户端的链接都可以连接成功  
    2、一个通讯循环的部分,就是每个客户端链接成功之后,要循环的和客户端进行通信。
    
    看代码中的:server=socketserver.ThreadingTCPServer(('127.0.0.1',8006),MyServer)
    
    通过print(socketserver.ThreadingTCPServer.mro())查看对象继承的mro顺序,找到它的继承
    查找属性的顺序:ThreadingTCPServer->ThreadingMixIn->TCPServer->BaseServer
    
    建立循环连接
    **实例化得到server,先找ThreadMinxIn中的__init__方法,发现没有init方法,然后找类ThreadingTCPServer的__init__,在TCPServer中找到,在里面创建了socket对象,进而执行server_bind(相当于bind),server_active(点进去看执行了listen)
    **找server下的serve_forever,在BaseServer中找到,进而执行self._handle_request_noblock(),该方法同样是在BaseServer中
    **执行self._handle_request_noblock()进而执行request, client_address = self.get_request()(就是TCPServer中的self.socket.accept()),然后执行self.process_request(request, client_address)
    **在ThreadingMixIn中找到process_request,开启多线程应对并发,进而执行process_request_thread,执行self.finish_request(request, client_address)
    
    建立通讯:
    在BaseServer中找到finish_request,触发我们自己定义的类的实例化,去找__init__方法,其中:
    tcp:
        self.server即套接字对象
      self.request即一个链接
      self.client_address即客户端地址
    udp:
    	self.request是一个元组(第一个元素是客户端发来的数据,第二部分是服务端的udp套接字对象),如(b'adsf', <socket.socket fd=200, family=AddressFamily.AF_INET, type=SocketKind.SOCK_DGRAM, proto=0, laddr=('127.0.0.1', 8080)>)
      self.client_address即客户端地址
    
    仅供参考,欢迎指正
  • 相关阅读:
    .NET深入解析LINQ框架(四:IQueryable、IQueryProvider接口详解)
    .NET简谈组件程序设计之(初识NetRemoting)
    .NET简谈组件程序设计之(delegate与event关系)
    .NET简谈组件程序设计之(上下文与同步域)
    .NET简谈特性(代码属性)
    .NET可逆框架设计
    使用KTM(内核事务管理器)进行文件事务处理
    .NET面向上下文、AOP架构模式(实现)
    .NET简谈设计模式之(装饰者模式)
    .NET对存储过程的调用抽象封装
  • 原文地址:https://www.cnblogs.com/jjzz1234/p/11210284.html
Copyright © 2011-2022 走看看