zoukankan      html  css  js  c++  java
  • python中UDP基于套接字编程,并发的TCP与UDP编程,TCP与UDP的差异。

    菩提本无根,明镜亦非台

    基于UDP协议的套接字通信:

    1.UDP是无连接的,先启动那一端都不会报错。

    UDP服务端:

    ss = socket()   #创建一个服务器的套接字
    ss.bind()       #绑定服务器套接字
    inf_loop:       #服务器无限循环
       cs = ss.recvfrom()/ss.sendto() # 对话(接收与发送)
    ss.close()                         # 关闭服务器套接字
    

    UDP客户端:

    cs = socket()   # 创建客户套接字
    comm_loop:      # 通讯循环
        cs.sendto()/cs.recvfrom()   # 对话(发送/接收)
    cs.close()                      # 关闭客户套接字
    

    2.UDP套接字通信,简单示例:

    UDP服务端:

    from socket import *
    import time
    
    server = socket(AF_INET, SOCK_DGRAM)
    server.bind(('127.0.0.1', 8080))
    
    while True:
        data, client_addr = server.recvfrom(1024)
        time.sleep(10)
        server.sendto(data.upper(), client_addr)
    

    UDP客户端:

    from socket import *
    
    client = socket(AF_INET, SOCK_DGRAM)
    
    while True:
        msg = input('>>: ').strip()
        client.sendto(msg.encode("utf-8"), ('127.0.0.1', 8080))
    
        data, server_addr = client.recvfrom(1024)
        print(data.decode('utf-8'))
    

    TCP协议 VS UDP协议

    1.可靠性:

    • tcp协议是可靠协议:
      双方在通信过程中,对方必须回复一个ack确认信息,才会将自己这端的数据从内存中删除
    • udp协议不可靠:
      双方通信过程中,发送一条消息就会立即删除,不管对方是否接收到

    2.有无链接:

    • tcp有链接
    • udp无链接

    3.传输数据的效率:

    • tcp需要互相通信 (效率低)
    • udp不需要互相通信(效率高)

    4.粘包问题

    • udp协议称之为数据报协议,每次发送都是一个完整的数据报,一个发送唯一对应一个接收所以udp协议没有粘包问题

    • 对于tcp的粘包问题请参考上一篇博客。

    5.深度理解连接https://www.cnblogs.com/linhaifeng/articles/6129246.html

    基于socketserver模块实现并发

    了解进程:

    1.进程是什么?

    • 顾名思义,进程即正在执行的一个过程。进程是对正在运行程序的一个抽象。

    2.进程的概念是从哪来的?

    • 进程的概念起源于操作系统,是操作系统最核心的概念,也是操作系统提供的最古老也是最重要的抽象概念之一。操作系统的其他所有内容都是围绕进程的概念展开的。

    3.深度理解连接

    4.并发连接

    实现并发:

    基于tcp的套接字,关键就是两个循环一个链接循环一个通信循环

    socketserver模块中分两大类:server类(解决链接问题)和request类(解决通信问题)

    server类:

    img

    request类:

    img

    继承关系:

    img

    img

    img

    TCP服务端(支持并发):

    # 支持并发版本
    import socketserver
    
    
    class MyRequestHandler(socketserver.BaseRequestHandler):
        def handle(self):  # 处理通信
            print(self.client_address)
            while True:
                try:
                    data = self.request.recv(1024)  # self.request=>conn
                    if len(data) == 0: break
                    self.request.send(data.upper())
                except Exception:
                    break
            self.request.close()
    
    
    if __name__ == '__main__':
        s = socketserver.ThreadingTCPServer(('127.0.0.1', 8080), MyRequestHandler, bind_and_activate=True)
        s.serve_forever()
    

    TCP客户端:

    from socket import *
    
    client=socket(AF_INET,SOCK_STREAM)
    client.connect(('127.0.0.1',8080))
    
    while True:
        msg=input(">>: ").strip()
        if len(msg) == 0:
            continue
    
        client.send(msg.encode('utf-8'))
        data=client.recv(1024)
        print(data.decode('utf-8'))
    

    UDP服务端(支持并发):

    import socketserver
    
    class MyRequestHandler(socketserver.BaseRequestHandler):
        def handle(self):  # 处理通信
            data,server=self.request
            server.sendto(data.upper(),self.client_address)
    
    if __name__ == '__main__':
        s = socketserver.ThreadingUDPServer(('127.0.0.1', 8080), MyRequestHandler, bind_and_activate=True)
        s.serve_forever()
    

    UDP客户端:

    from socket import *
    
    client = socket(AF_INET, SOCK_DGRAM)
    
    while True:
        msg = input('>>: ').strip()
        client.sendto(msg.encode("utf-8"), ('127.0.0.1', 8080))
    
        data, server_addr = client.recvfrom(1024)
        print(data.decode('utf-8'))
    
    

    自行阅读:

    以下述代码为例,分析socketserver源码:
    
    ftpserver=socketserver.ThreadingTCPServer(('127.0.0.1',8080),FtpServer)
    ftpserver.serve_forever()
    查找属性的顺序:ThreadingTCPServer->ThreadingMixIn->TCPServer->BaseServer
    
    实例化得到ftpserver,先找类ThreadingTCPServer的__init__,在TCPServer中找到,进而执行server_bind,server_active
    找ftpserver下的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__方法,而我们自己定义的类没有该方法,则去它的父类也就是BaseRequestHandler中找....
    源码分析总结:
    
    基于tcp的socketserver我们自己定义的类中的
    
      self.server即套接字对象
      self.request即一个链接
      self.client_address即客户端地址
    基于udp的socketserver我们自己定义的类中的
    
      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即客户端地址
    
    
    努力学习!
  • 相关阅读:
    js伪数组转数组内部实现
    Vuex核心部分学习参考地址
    vue中让异步代码变成同步的写法
    node.js中文件操作路径和模板标识路径问题
    如果不想安装cnpm又想使用淘宝的服务器来下载,怎么做?
    npm常用命令
    node中模块加载机制
    通过nodejs,简单模拟客户端和服务端进行通信
    vue中非父子组件的传值
    图论1-2
  • 原文地址:https://www.cnblogs.com/Orange-YXH/p/13648098.html
Copyright © 2011-2022 走看看