zoukankan      html  css  js  c++  java
  • UDP通讯协议

    与TCP相同的是 客户端也不需要bind一个固定端口 让系统随机分一个



    UDP和TCP异同处

    UDP在使用时
    1.修改socket的参数 第一个任然是AF_INET 第二个需要换成AOCK_DGRAM
    2.UDP 不需要建立连接 所以没有三次握手和四次挥手




    相同点:
    服务器:都需要绑定端口和ip
    recv与recvfrom都是阻塞的



    不同点:
    服务器:不需要监听和接受请求
    TCP服务器默认只能与一个客户端进行通讯 下一个客户端必须等待上一个断开连接才能被处理
    UDP多个客户端的请求会被一次处理 由于不需要建立连接 所以给你感觉时好像可以同时处理

    客户端:不需要建立连接 直接发送即可
    可以发送空消息


    在UDP中 无论是客户端还是服务器 接受:recvfrom 发送:sendto
    UDP是基于数据报的协议
    发送和接收都是以数据报为单位
    而TCP得单位是字节


    接收方的缓冲区大小即使大于发送方发送的数据长度 也不会沾包

    当接受方缓冲区的长度小于数据报的长度 windows会报异常 而Linux不会 缓冲区有多大就收几个

    注意:UDP在使用时,必须保证收到的缓冲区大小 大于或等于发送的数据
    由于缓冲区大小不可能无限大 所以UDP不适用于数据量较大的情况下 如果一定要使用UDP来传输大量数据的话
    需要自己来对数据进行切割和组装

    udp最大的数据报 受数据帧大小限制 最大为1472字节

    TCP发送数据后 不会立即删除缓存数据 需要等到对方确认信息到达

    结论:当数据量较大时 需要TCP
    import socket
    c=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
    
    
    addr=('127.0.0.1',8808)
    c.sendto('hello 我是udp客户端'.encode(),addr)
    print('over')
    
    
    
    data,addr=c.recvfrom(1024)
    print(data.decode(),addr)
    客户端
    import socket
    
    
    
    s=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
    s.bind(('127.0.0.1',8808))
    
    
    
    
    while True:
        data,addr=s.recvfrom(1024)
        s.sendto(data.upper(),addr)
        print(data)
    服务器


    自定义报头
    发送端:
    1.先将所有的额外信息打包到一个头中
    2.然后先发送头部数据
    3.最后发送真实数据

    接收端:
    1.接收固定长度的头部长度数据
    2.根据长度数据获取头部数据
    3.根据头部数据获取真实数据
    import struct
    
    def send_msg(data,c):
        # 发数据
        data = data.encode("utf-8")
        len_bytes = struct.pack("q",len(data))
        c.send(len_bytes)
        c.send(data)
    
    def recv_msg(sock):
        # 接收响应
        length = struct.unpack("q",sock.recv(8))[0]
    
    
        # 已接收长度
        c_size = 0
    
        # 存储总数据
        data = b""
        while c_size < length:
            res = sock.recv(1024)
            if not res:
                break
            c_size += len(res)
            data += res # 拼接数据
    
        # 长度符合则接收成功
        if length == c_size:
            print("接收成功")
    
        return data.decode("utf-8")
    tool
    import socket
    import tool
    
    s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    s.bind(("127.0.0.1",8989)) # 0 - 1023 > 可用端口 <  65535
    
    s.listen() # 最大的半连接数量限制
    
    while True:
        c,addr = s.accept()
    
        while True:
            try:
                # 从操作系统缓冲区读取1024到应用程序
                data = tool.recv_msg(c)  # 阻塞函数   等到操作系统缓冲区有数据为止
                if not data: # 对方正常下线 ,,linux对方异常断开连接
                    c.close()
                    break
    
                print(data)
    
                # 返回数据
                tool.send_msg(data.upper(),c)
            except Exception as e: # 抛出异常仅在windows下 对方异常下线才会发生
                print(e)
                c.close()
                break
    服务器
    import socket
    import tool
    c = socket.socket()
    
    c.connect(("127.0.0.1",8989)) # 就在执行三次握
    
    
    while True:
        msg = input(">>>:")
        if not msg:
            continue
        tool.send_msg(msg,c) # 发送
    
        res = tool.recv_msg(c) # 接收
        print(res)
    客户端
  • 相关阅读:
    SQL面试题:有A B C三列,用SQL语句实现:当A列大于B列时选择A列否则选择B列
    Centos下Yum安装PHP5.5
    docker 容器内服务自启动
    centos6.6系统初始化脚本
    不重启linuxVMWare虚拟机添加虚拟磁盘
    linux(centos6)搭建ftp服务器
    记一次扩容操作
    mongodb数据迁移的两种方式
    mongodb 数据库操作--备份 还原 导出 导入
    关于PHP参数的引用传递和值传递
  • 原文地址:https://www.cnblogs.com/gengbinjia/p/10471544.html
Copyright © 2011-2022 走看看