IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> Python:UDP编程、心跳机制、UDP的应用场景 -> 正文阅读

[网络协议]Python:UDP编程、心跳机制、UDP的应用场景

目录

UDP服务端编程流程

1、创建服务端流程

2、UDP客户端编程流程

3、UDP的socket对象创建常用方法

练习——UDP版本群聊

UDP协议的应用


UDP服务端编程流程

1、创建服务端流程

  • 创建socket的对象。socket.SOCK_DGRAM
  • 绑定IP和Port,bind方法
  • 传输数据
    • 接受数据,socket.recvform(bufsize,[,flags]),获得一个二元组(string,address)
    • 发送数据,socket.sendto(string,address)发给某地址信息
  • 释放资源
import socket
sercice_udp = socket.socket(type=socket.SOCK_DGRAM)

sercice_udp.bind(("0.0.0.0",9999)) #绑定一个udp端口
data = sercice_udp.recv(1024)  #阻塞数据等待数据
data = sercice_udp.recvfrom(10235)  #阻塞等待一个数据(value,(ip,port))
sercice_udp.sendto(b"7",('192.168.1.102',10000))
sercice_udp.close()

结果状态

2、UDP客户端编程流程

  • 创建socket对象。socket.SOCK_DGRAM
  • 发送数据,socket.sendto(string,address)发给某地址某信息
  • 接受数据,socket.recvform(bufsize,[,flags]),获得一个二原则(string,address)
  • 释放资源

注意:UDP是无协议链接的,所以可以只有任何一端,例如客户端发往服务端,服务端存在与否无所谓

UDP创建socket对象后,是没有占用本地地址和端口的

import socket
client_ser = socket.socket(type=socket.SOCK_DGRAM)
raddr = ("192.168.1.102",10000)

client_ser.connect(raddr)

client_ser.sendto(b'8',raddr)
client_ser.send(b'9')

data = client_ser.recvfrom(1024) #阻塞等待数据(value,(ip,port))
data = client_ser.recv(1024)  #阻塞等待数据

client_ser.close()


结果:

3、UDP的socket对象创建常用方法

方法说明
bind()?可以指定本地地址和端口laddr,会立即使用
connect()?可以立即占用本地地址和端口,填充
sendto()可以立即占用本地地址和端口,并把数据发送指定远端。只有有了本地绑定端口,sendto就可以向任何远端发送数据
send()需要和connect方法配合,可以使用已经从本地端口把数据发往radder指定的远端
recv()要求一定要在占用了本地端口后,返回接受的数据
recvform()要求一定占用了本地端口后,返回接受的数据和对端地址的二元组

练习——UDP版本群聊

服务端代码改进

  • 加一个ack机制和心跳hearbeat。心跳,就是一端定时发往另一端的信息,一般每次数据越少越好,心跳时间间隔约定好就行。ack即响应,一端收到另一端

心跳机制

  • 一般来说客户端定时发往服务端的,服务端并不需要ack回复客户端,只需要记录该客户端还活着就行了
  • 如果是服务端定时发往客户端的,一般需要客户端ack响应来表示活着,如果没有收到ack的客户端,服务端移除其信息,这种实现较为复杂,用的较少
  • 也可以双向发心跳的,用的更少
import socket
import threading
import datetime
import logging

FORMAT = "%(asctime)s %(threadName)s %(thread)d %(message)s"
logging.basicConfig(format=FORMAT,level=logging.INFO)

class CharUDPserver:

    def __init__(self,ip="127.0.0.1",port=9988,interval=5):
        self.addr = (ip,port)
        self.sock = socket.socket(type=socket.SOCK_DGRAM)
        self.clients = {}  #记录客户端,字典
        self.event = threading.Event()
        self.interval = interval #默认10秒,超时就要移除对应的客户端

    def start(self):
        self.sock.bind(self.addr)
        #启动线程
        threading.Thread(target=self.recv,name="recv").start()
        # threading.Thread(target=self.recv,name="recv").start()

    def recv(self):
        while not self.event.is_set():
            loalset = set()
            data ,raddr = self.sock.recvfrom(1024) #阻塞接受数据
            data = data.decode().strip()
            current = datetime.datetime.now().timestamp()  #float点数

            if data == "hb":
                print("^^^^^^^^^hb",raddr,data,current)
                self.clients[raddr]=current
                continue
            elif data  ==  "quit":
                #有可能数据不存在clients中
                self.clients.pop(raddr,None)
                logging.info("{} leaving".format(raddr))
                continue

            print(11111)
            #有信息来就更新时间
            #什么时候比叫心跳时间尼?发送信息的时候,反正要遍历一遍
            self.clients[raddr]=current

            msg = "{} ack.form {} :{} ".format(data,*raddr)
            last_current = datetime.datetime.now().timestamp()  #float点数
            logging.info(msg)
            msg = msg.encode()



            for c ,stamp in self.clients.items():
                print(c,stamp)
                if last_current - stamp >= self.interval:
                    self.sock.sendto(msg,c)
                else:
                    loalset.add(c)

            for i in loalset:
                self.clients.pop(i)
            print(loalset)
    def stop(self):
        for a in self.clients:
            self.sock.sendto(b"bey",a)
        self.sock.close()
        self.event.set()


def main():
    cs = CharUDPserver()
    cs.start()

    while True:
        cmd = input(">>>>")
        if cmd.strip() == "quit":
            cs.stop()
            break
    logging.info(threading.enumerate())
    logging.info(cs.clients)

if __name__ == '__main__':
    main()

客户端代码改进【增加心跳机制】
?

import threading
import socket
import logging

FORMAT = "%(asctime)s %(threadName)s %(thread)d %(message)s"
logging.basicConfig(format=FORMAT,level=logging.INFO)

class ChatUDBClient():

    def  __init__(self,rip = "127.0.0.1",rport=9988):
        self.addr = (rip,rport)
        self.socket = socket.socket(type=socket.SOCK_DGRAM)
        self.event = threading.Event()

    def start(self):
        self.socket.connect(self.addr)   #占用本地地址和端口,设置远端地址和端口

        threading.Thread(target=self.recv,name="recv").start()
        threading.Thread(target=self._sendhb,name="heartbeat",daemon=True).start()


    def _sendhb(self):
        while not self.event.wait(2):
            self.send("hb")

    def recv(self):
        while not self.event.is_set():
            data ,raddr = self.socket.recvfrom(1024)
            msg = "{}。form {}:{}".format(data.decode(),*raddr)
            logging.info(msg)

    def send(self,msg:str):
        self.socket.sendto(msg.encode(),self.addr)

    def stop(self):
        self.send("quit")  #通知服务端退出
        self.socket.close()
        self.event.set()

def main():
    cc1 = ChatUDBClient()
    cc2 = ChatUDBClient()
    cc1.start()
    # cc2.start()
    print(cc1.start)
    # print(cc1.start)
    logging.info(threading.enumerate())
    while True:
        cmd = input("》》》")
        if cmd == "quit":
            cc1.stop()
            # cc2.stop()
            break
        cc1.start()
        # cc2.start()

if __name__ == '__main__':
    main()

UDP协议的应用

UDP是无连接协议,它基于以下假设:网络足够号,消息不会丢包,包不会乱序
但是,即使是在局域网,也不能保证不丢包,而且包的到达不一定有序

应用场景,视频、音频传输,一般来说,丢些包,问题不大,最多丢些图像、听不清华语,可以重新发话语来解决。海量数据,例如:传感器的数据,丢几十、几百也没有关系。DNS,数据内容下,一个包就能查询到结果,不存在丢包、乱序、重新请求解析。

一般来说,UDP的性能由于TCP,但是可靠性要求高的场合还是要选择TCP协议

  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章           查看所有文章
加:2021-07-14 00:25:09  更:2021-07-14 00:25:24 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/29 9:52:12-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码