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

UDP编程与Socket

UDP编程与Socket文章目录UDP编程与SocketUDP服务端编程练习--UDP版本群聊UDP协议的应用相关测试命令windows查找udp是否启动端口:net
UDP编程与Socket

文章目录

  • UDP编程与Socket
    • UDP服务端编程
    • 练习--UDP版本群聊
    • UDP协议的应用


  • 相关测试命令
    1. windows查找udp是否启动端口:
      • netstart -anp udp | find "9999"
      • netstart -anbp udp | findstr 9999
    2. linux下发给服务端数据
      • echo "123abc" | nc -u 172.0.0.1 9999

UDP服务端编程


  • UDP服务端编程流程
    udp_001

  1. 创建socket对象。socket.SOCK_DGRAM
  2. 绑定IP和Port,bind()方法
  3. 传输数据
    • 接收数据,socket.recvfrom(bufsize[,flags]),获得一个二元组(string,address)
    • 发送数据,socket.sendto(string,address)发给某地址某信息
  4. 释放资源

import logging
import sys
import socketlogging.basicConfig(format="%(asctime)s %(threadName)s %(thread)d %(message)s",stream=sys.stdout,level=logging.INFO)server = socket.socket(type=socket.SOCK_DGRAM) #创建一个基于UDP的socket
server.bind(("127.0.0.1",3999)) #立即绑定一个udp端口
# data = server.recv(1024) #阻塞等待数据
data,radde = server.recvfrom(1024) #阻塞等待数据(value,(ip,port))
logging.info("{}-{}".format(radde,data))
server.sendto("{} server msg = {}".format(server.getsockname(),data).encode(),radde)
server.close()

  • UDP客户端编写流程

    1. 创建socket对象。socket.SOCK_DGRAM
    2. 发送数据,socket_sendto(string,address)发给某地址信息
    3. 接收数据,socket.recvfrom(bufsize[,flags]),获得一个二元组(string,address)
    4. 释放资源
  • 第一个版本

import logging
import sys
import socketlogging.basicConfig(format="%(asctime)s %(threadName)s %(thread)d %(message)s",stream=sys.stdout,level=logging.INFO)client = socket.socket(type=socket.SOCK_DGRAM)
raddr = "127.0.0.1",3999
client.connect(raddr) #connect方法会自动分配一个本地的UDP地址,和设置UDP的链接对象raddr地址
logging.info(client)
client.send(b"hello") #由于使用了connect方法,所以不指定终端也能发送
client.sendto(b"why",raddr) #也可以使用指定地址发送
data,radde = client.recvfrom(1024)
logging.info("{}-{}".format(radde,data))
client.close()

udp_002

  • 第二个版本,不使用connect指定目标

import logging
import sys
import socketlogging.basicConfig(format="%(asctime)s %(threadName)s %(thread)d %(message)s",stream=sys.stdout,level=logging.INFO)client = socket.socket(type=socket.SOCK_DGRAM)
raddr = "127.0.0.1",3999
client.sendto(b"hello",raddr)
logging.info(client)
data,laddr = client.recvfrom(1024)
logging.info("{}-{}".format(data,laddr))
client.close()

udp_003

  • 注意:UDP是无链接协议,所以可以只有任何一端,例如客户端数据发往服务端,服务端存在与否无所谓。
  • UDP编程中bind、connect、send、sendto、recv、recvfrom方法使用
  • UDP的socket对象创建后,是没有占用本地地址和端口的。

方法说明
bind(laddr)可以指定本地地址和端口laddr,会立即占用,laddr为一个元组,(ip,prot)
connect(raddr)会随机分配一个本地的端口laddr,会绑定远端地址和端口raddr,raddr是个元组,(ip,prot)
sendto(msg,raddr)可以立即占用本地地址和端口laddr,并把数据发往指定远端。只有有了本地绑定的端口,sendto就可以向任何远端发送数据
msg #要发送的数据。bytes类型。
raddr#远端地址和端口组成的一个元组(ip,prot)
send(msg)需要和connect方法配合,可以使用已经从本地端口把数据发往raddr指定的远端
msg#需要发送的消息bytes类型
recv(buffersize)要求一定要在占用了本地端口后,返回接受的数据,buffersize指定一个缓冲区大小
recvfrom(buffersize)要求一定要占用了本地端口后,返回接收的数据和对端地址的二元组(msg,raddr)
buffersize指定一个缓冲区大小。

练习–UDP版本群聊


  • 服务端代码

"""
author:xdd
date:2019-06-17 09:20
"""

import logging
import sys
import socket
import threading
import datetimelogging.basicConfig(format&#61;"%(asctime)s %(threadName)s %(thread)d %(message)s",stream&#61;sys.stdout,level&#61;logging.INFO)class ChatUDPServer:def __init__(self,ip&#61;"127.0.0.1",port&#61;3999,timeout&#61;10):self.socket &#61; socket.socket(type &#61; socket.SOCK_DGRAM)self.laddr &#61; ip,portself.event &#61; threading.Event()self.timeout &#61; timeoutself.clients &#61; {}def start(self):socket &#61; self.socketsocket.bind(self.laddr)threading.Thread(target&#61;self.run,name&#61;"run").start()def run(self):socket &#61; self.socketclients &#61; self.clientswhile not self.event.is_set():try:data,raddr &#61; socket.recvfrom(1024)except:continueutctime &#61; datetime.datetime.now().timestamp()if data.strip() &#61;&#61; b"by": #如果用户自己发送by表示要退出self.clients.pop(raddr)continueclients[raddr] &#61; utctimeif data.strip() &#61;&#61; b"^hh^": #如果是心跳&#xff0c;就忽略continuemsg &#61; "[{}] {}".format(raddr,data)logging.info(msg)outclient &#61; [] #记录超时的链接地址for cr,tm in clients.items():if 0 <&#61; utctime - tm <&#61; self.timeout:socket.sendto(msg.encode(),cr)else:outclient.append(cr)for cr in outclient: #超时后删除self.clients.pop(cr)def stop(self):try:self.event.set()self.socket.close()finally:self.clients.clear()&#64;classmethoddef main(cls):chserver &#61; cls()chserver.start()while True:cmd &#61; input(">>>>")if cmd.strip() &#61;&#61; "quit":chserver.stop()threading.Event().wait(1)breaklogging.info(threading.enumerate())logging.info(chserver.clients)ChatUDPServer.main()

  • UDP版本客户端代码

"""
author:xdd
date:2019-06-17 10:26
"""
import logging
import sys
import socket
import threadinglogging.basicConfig(format&#61;"%(asctime)s %(thread)d %(threadName)s %(message)s",stream&#61;sys.stdout,level&#61;logging.INFO)class UdpClient:def __init__(self,ip&#61;"127.0.0.1",prost &#61; 3999,heartbeattime &#61; 5):self.socket &#61; socket.socket(type&#61;socket.SOCK_DGRAM)self.raddr &#61; ip,prostself.event &#61; threading.Event()self.heartbeattime &#61; heartbeattimedef start(self):self.socket.connect(self.raddr)self.send("hello")threading.Thread(target&#61;self.heartbeat,name&#61;"heartbeat").start()threading.Thread(target&#61;self.run,name&#61;"client").start()#发送心跳包&#xff0c;保持链接def heartbeat(self):while not self.event.wait(self.heartbeattime):self.send("^hh^")logging.info("心跳结束")def run(self):while not self.event.is_set():try:data,raddr &#61; self.socket.recvfrom(1024)except:continuelogging.info("[ {} msg ] {}".format(raddr,data))def send(self,msg):#发送消息socket &#61; self.socketsocket.send(msg.encode())def stop(self):#停止self.event.set()self.socket.close()&#64;classmethoddef main(cls):client &#61; cls()client.start()while True:cmd &#61; input(">>>")if cmd.strip() &#61;&#61; "quit":client.stop()breakelse:client.send(cmd)UdpClient.main()

  1. 服务端代码
    • 增加心跳heartbeat机制或ack机制。这些机制同样可以用在TCP通信的时候。
    • 心跳&#xff0c;就是一端定时发往另一端的信息&#xff0c;一般每次数据越少越好。心跳时间间隔约定好就行。
    • ack即响应&#xff0c;一端收到另一端的消息后返回的确认信息。

  • 心跳机制
    1. 一般来说是客户端定时发往服务端的&#xff0c;服务端并不需要ack回复客户端&#xff0c;只需要记录该客户端还活着就行了。
    2. 如果是服务端定时发往客户端的&#xff0c;一般需要客户端ack响应来表示活着&#xff0c;如果没有收到ack的客户端&#xff0c;服务端 移除其信息。这种实现较为复杂&#xff0c;用的较少。
    3. 也可以双向都发心跳的&#xff0c;用的更少。

UDP协议的应用


  • UDP是无连接协议&#xff0c;它基于以下假设&#xff1a;
    1. 网络足够好
    2. 消息不会丢包
    3. 包不会乱序
  • 但是&#xff0c;即使是在局域网&#xff0c;也不能保证不丢包&#xff0c;而且包的到达不一定有序。
  • 应用场景
    1. 视频、音频传输&#xff0c;一般来说&#xff0c;丢些包&#xff0c;问题不大&#xff0c;最多丢些图像、听不清话语&#xff0c;可以重新发话语来解决。 海量采集数据&#xff0c;例如传感器发来的数据&#xff0c;丢几十、几百条数据也没有关系。
    2. DNS协议&#xff0c;数据内容小&#xff0c;一个包就能查询到结果&#xff0c;不存在乱序&#xff0c;丢包&#xff0c;重新请求解析。
  • 一般来说&#xff0c;UDP性能优于TCP&#xff0c;但是可靠性要求高的场合的还是要选择TCP协议。

推荐阅读
  • http:my.oschina.netleejun2005blog136820刚看到群里又有同学在说HTTP协议下的Get请求参数长度是有大小限制的,最大不能超过XX ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • 本文介绍了Web学习历程记录中关于Tomcat的基本概念和配置。首先解释了Web静态Web资源和动态Web资源的概念,以及C/S架构和B/S架构的区别。然后介绍了常见的Web服务器,包括Weblogic、WebSphere和Tomcat。接着详细讲解了Tomcat的虚拟主机、web应用和虚拟路径映射的概念和配置过程。最后简要介绍了http协议的作用。本文内容详实,适合初学者了解Tomcat的基础知识。 ... [详细]
  • 本文介绍了计算机网络的定义和通信流程,包括客户端编译文件、二进制转换、三层路由设备等。同时,还介绍了计算机网络中常用的关键词,如MAC地址和IP地址。 ... [详细]
  • 本文介绍了在Linux下安装和配置Kafka的方法,包括安装JDK、下载和解压Kafka、配置Kafka的参数,以及配置Kafka的日志目录、服务器IP和日志存放路径等。同时还提供了单机配置部署的方法和zookeeper地址和端口的配置。通过实操成功的案例,帮助读者快速完成Kafka的安装和配置。 ... [详细]
  • 本文介绍了Python爬虫技术基础篇面向对象高级编程(中)中的多重继承概念。通过继承,子类可以扩展父类的功能。文章以动物类层次的设计为例,讨论了按照不同分类方式设计类层次的复杂性和多重继承的优势。最后给出了哺乳动物和鸟类的设计示例,以及能跑、能飞、宠物类和非宠物类的增加对类数量的影响。 ... [详细]
  • Python实现变声器功能(萝莉音御姐音)的方法及步骤
    本文介绍了使用Python实现变声器功能(萝莉音御姐音)的方法及步骤。首先登录百度AL开发平台,选择语音合成,创建应用并填写应用信息,获取Appid、API Key和Secret Key。然后安装pythonsdk,可以通过pip install baidu-aip或python setup.py install进行安装。最后,书写代码实现变声器功能,使用AipSpeech库进行语音合成,可以设置音量等参数。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • 使用Ubuntu中的Python获取浏览器历史记录原文: ... [详细]
  • 关键词: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 ... [详细]
  • 利用Visual Basic开发SAP接口程序初探的方法与原理
    本文介绍了利用Visual Basic开发SAP接口程序的方法与原理,以及SAP R/3系统的特点和二次开发平台ABAP的使用。通过程序接口自动读取SAP R/3的数据表或视图,在外部进行处理和利用水晶报表等工具生成符合中国人习惯的报表样式。具体介绍了RFC调用的原理和模型,并强调本文主要不讨论SAP R/3函数的开发,而是针对使用SAP的公司的非ABAP开发人员提供了初步的接口程序开发指导。 ... [详细]
  • 本文介绍了如何使用C#制作Java+Mysql+Tomcat环境安装程序,实现一键式安装。通过将JDK、Mysql、Tomcat三者制作成一个安装包,解决了客户在安装软件时的复杂配置和繁琐问题,便于管理软件版本和系统集成。具体步骤包括配置JDK环境变量和安装Mysql服务,其中使用了MySQL Server 5.5社区版和my.ini文件。安装方法为通过命令行将目录转到mysql的bin目录下,执行mysqld --install MySQL5命令。 ... [详细]
  • web.py开发web 第八章 Formalchemy 服务端验证方法
    本文介绍了在web.py开发中使用Formalchemy进行服务端表单数据验证的方法。以User表单为例,详细说明了对各字段的验证要求,包括必填、长度限制、唯一性等。同时介绍了如何自定义验证方法来实现验证唯一性和两个密码是否相等的功能。该文提供了相关代码示例。 ... [详细]
  • 本文详细介绍了如何使用MySQL来显示SQL语句的执行时间,并通过MySQL Query Profiler获取CPU和内存使用量以及系统锁和表锁的时间。同时介绍了效能分析的三种方法:瓶颈分析、工作负载分析和基于比率的分析。 ... [详细]
author-avatar
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有