热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Python:UDP编程、心跳机制、UDP的应用场景

目录UDP服务端编程流程1、创建服务端流程2、UDP客户端编程流程3、UDP的socket对象创建常用方法练习——UDP版本群聊UDP协议的应用UDP服务端编程流程1、

目录

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 loggingFORMAT = "%(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]=currentcontinueelif data == "quit":#有可能数据不存在clients中self.clients.pop(raddr,None)logging.info("{} leaving".format(raddr))continueprint(11111)#有信息来就更新时间#什么时候比叫心跳时间尼?发送信息的时候,反正要遍历一遍self.clients[raddr]=currentmsg = "{} 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()breaklogging.info(threading.enumerate())logging.info(cs.clients)if __name__ == '__main__':main()

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

import threading
import socket
import loggingFORMAT = "%(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()breakcc1.start()# cc2.start()if __name__ == '__main__':main()


UDP协议的应用

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

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

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


推荐阅读
  • python网络编程 day27 网络编程初识 ——socket
    一、内容回顾1、两个内置函数(装饰器)及类中的魔术方法 ... [详细]
  • 并不是上一个用SocketServer的聊天室的延续。用远程调用完成的聊天室。正好有Java的RMI聊天室的作业,就先用Python写了一个简单的类似远程调用的东西& ... [详细]
  • 本文讨论了在VMWARE5.1的虚拟服务器Windows Server 2008R2上安装oracle 10g客户端时出现的问题,并提供了解决方法。错误日志显示了异常访问违例,通过分析日志中的问题帧,找到了解决问题的线索。文章详细介绍了解决方法,帮助读者顺利安装oracle 10g客户端。 ... [详细]
  • 1、Ipv4只能用于内网,外网只能用2、DNS:把域名解析成ip地址3、MAC地址就是物理地址(网卡序列号)   IP地址:电脑序列号4、不同电脑,微信之间互相通信,靠的是端口;  ... [详细]
  • TCP/IP详解 卷1 第一章概述
    第一章概述1.2分层网络编程通常分不同层次进行开发,每一层负责不同的通信功能。一个协议族比如TCPIP,通常是一组不同层次上多个协议的组合。一般可以认为 ... [详细]
  • Linux重启网络命令实例及关机和重启示例教程
    本文介绍了Linux系统中重启网络命令的实例,以及使用不同方式关机和重启系统的示例教程。包括使用图形界面和控制台访问系统的方法,以及使用shutdown命令进行系统关机和重启的句法和用法。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • 本文介绍了Redis的基础数据结构string的应用场景,并以面试的形式进行问答讲解,帮助读者更好地理解和应用Redis。同时,描述了一位面试者的心理状态和面试官的行为。 ... [详细]
  • 本文介绍了RPC框架Thrift的安装环境变量配置与第一个实例,讲解了RPC的概念以及如何解决跨语言、c++客户端、web服务端、远程调用等需求。Thrift开发方便上手快,性能和稳定性也不错,适合初学者学习和使用。 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • 本文介绍了计算机网络的定义和通信流程,包括客户端编译文件、二进制转换、三层路由设备等。同时,还介绍了计算机网络中常用的关键词,如MAC地址和IP地址。 ... [详细]
  • 关键词:Golang, Cookie, 跟踪位置, net/http/cookiejar, package main, golang.org/x/net/publicsuffix, io/ioutil, log, net/http, net/http/cookiejar ... [详细]
  • 个人学习使用:谨慎参考1Client类importcom.thoughtworks.gauge.Step;importcom.thoughtworks.gauge.T ... [详细]
  • 本文介绍了在Linux下安装和配置Kafka的方法,包括安装JDK、下载和解压Kafka、配置Kafka的参数,以及配置Kafka的日志目录、服务器IP和日志存放路径等。同时还提供了单机配置部署的方法和zookeeper地址和端口的配置。通过实操成功的案例,帮助读者快速完成Kafka的安装和配置。 ... [详细]
  • 解决nginx启动报错epoll_wait() reported that client prematurely closed connection的方法
    本文介绍了解决nginx启动报错epoll_wait() reported that client prematurely closed connection的方法,包括检查location配置是否正确、pass_proxy是否需要加“/”等。同时,还介绍了修改nginx的error.log日志级别为debug,以便查看详细日志信息。 ... [详细]
author-avatar
奈何为人非_800
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有