UDP协议编程_udp c语言

UDP协议编程_udp c语言UDP编程与Socket文章目录UDP编程与SocketUDP服务端编程练习–UDP版本群聊UDP协议的应用相关测试命令windows查找udp是否启动端口:netstart-anpudp|find”9999″netstart-anbpudp|findstr9999linux下发给服务端数据echo”123abc”|nc-u172.0.0….

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

UDP编程与Socket

  • 相关测试命令
    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 socket

logging.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 socket

logging.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 socket

logging.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 datetime

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

class ChatUDPServer:
    def __init__(self,ip="127.0.0.1",port=3999,timeout=10):
        self.socket = socket.socket(type = socket.SOCK_DGRAM)
        self.laddr = ip,port
        self.event = threading.Event()
        self.timeout = timeout
        self.clients = { 
   }

    def start(self):
        socket = self.socket
        socket.bind(self.laddr)
        threading.Thread(target=self.run,name="run").start()

    def run(self):
        socket = self.socket
        clients = self.clients

        while not self.event.is_set():
            try:
                data,raddr = socket.recvfrom(1024)
            except:
                continue
            utctime = datetime.datetime.now().timestamp()
            if data.strip() == b"by": #如果用户自己发送by表示要退出
                self.clients.pop(raddr)
                continue
            clients[raddr] = utctime

            if data.strip() == b"^hh^": #如果是心跳,就忽略
                continue

            msg = "[{}] {}".format(raddr,data)
            logging.info(msg)

            outclient = [] #记录超时的链接地址
            for cr,tm in clients.items():
                if 0 <= utctime - tm <= 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()

    @classmethod
    def main(cls):
        chserver = cls()
        chserver.start()
        while True:
            cmd = input(">>>>")
            if cmd.strip() == "quit":
                chserver.stop()
                threading.Event().wait(1)
                break
            logging.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 threading

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

class UdpClient:
    def __init__(self,ip="127.0.0.1",prost = 3999,heartbeattime = 5):
        self.socket = socket.socket(type=socket.SOCK_DGRAM)
        self.raddr = ip,prost
        self.event = threading.Event()
        self.heartbeattime = heartbeattime

    def start(self):
        self.socket.connect(self.raddr)
        self.send("hello")
        threading.Thread(target=self.heartbeat,name="heartbeat").start()
        threading.Thread(target=self.run,name="client").start()

    #发送心跳包,保持链接
    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 = self.socket.recvfrom(1024)
            except:
                continue
            logging.info("[ {} msg ] {}".format(raddr,data))

    def send(self,msg):#发送消息
        socket = self.socket
        socket.send(msg.encode())

    def stop(self):#停止
        self.event.set()
        self.socket.close()

    @classmethod
    def main(cls):
        client = cls()
        client.start()
        while True:
            cmd = input(">>>")
            if cmd.strip() == "quit":
                client.stop()
                break
            else:
                client.send(cmd)

UdpClient.main()
  1. 服务端代码
    • 增加心跳heartbeat机制或ack机制。这些机制同样可以用在TCP通信的时候。
    • 心跳,就是一端定时发往另一端的信息,一般每次数据越少越好。心跳时间间隔约定好就行。
    • ack即响应,一端收到另一端的消息后返回的确认信息。
  • 心跳机制
    1. 一般来说是客户端定时发往服务端的,服务端并不需要ack回复客户端,只需要记录该客户端还活着就行了。
    2. 如果是服务端定时发往客户端的,一般需要客户端ack响应来表示活着,如果没有收到ack的客户端,服务端 移除其信息。这种实现较为复杂,用的较少。
    3. 也可以双向都发心跳的,用的更少。

UDP协议的应用

  • UDP是无连接协议,它基于以下假设:
    1. 网络足够好
    2. 消息不会丢包
    3. 包不会乱序
  • 但是,即使是在局域网,也不能保证不丢包,而且包的到达不一定有序。
  • 应用场景
    1. 视频、音频传输,一般来说,丢些包,问题不大,最多丢些图像、听不清话语,可以重新发话语来解决。 海量采集数据,例如传感器发来的数据,丢几十、几百条数据也没有关系。
    2. DNS协议,数据内容小,一个包就能查询到结果,不存在乱序,丢包,重新请求解析。
  • 一般来说,UDP性能优于TCP,但是可靠性要求高的场合的还是要选择TCP协议。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/196114.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • Struts2学习笔记1

    Struts2学习笔记1

    2021年11月23日
    134
  • PO模式简介「建议收藏」

    PO模式简介「建议收藏」PO模式简介1.什么是PO模式PO模型是:PageObjectModel的简写页面对象模型作用:就是把测试页面和测试脚本进行分离,即把页面封装成类,供测试脚本进行调用;分层机制,让不同层去做不同类型的事情,让代码结构清晰,增加复用性。PO设计模式是Selenium自动化测试中最佳的设计模式之一,主要体现在对界面交互细节的封装2.不使用PO设计会出现以下几种情况:复用性不太好,扩展性不好,易读性差,不好维护,UI界面频繁的项目维护起来比较麻烦。3.PO模式的优缺点优点:提高代

    2022年6月11日
    67
  • 排队论模型(一):基本概念、输入过程与服务时间的常用概率分布

    排队论模型(一):基本概念、输入过程与服务时间的常用概率分布排队论模型 一 基本概念 输入过程与服务时间的常用概率分布排队论模型 二 生灭过程 M M s 等待制排队模型 多服务台模型排队论模型 三 M M s s 损失制排队模型排队论模型 四 M M s 混合制排队模型排队论模型 五 有限源排队模型 服务率或到达率依赖状态的排队模型排队论模型 六 非生灭过程排队模型 爱尔朗 Erlang 排队

    2025年9月5日
    3
  • 崩溃日志记录Landroid/support/v4/animation/AnimatorCompatHelper[通俗易懂]

    崩溃日志记录Landroid/support/v4/animation/AnimatorCompatHelper

    2022年3月12日
    34
  • 机房搬迁遇到的问题[通俗易懂]

    机房搬迁遇到的问题[通俗易懂]春节之前,公司接到了项目,机房搬迁,一般的机房搬迁也无所谓,但是这次是工商行政管理局的机房搬迁,从9楼搬到一楼,现把遇到的问题记录如下。总共有3套系统运行在机房,重要的是全省的工商系统,硬件是2台小型机IBM570和一套磁盘阵列存储数据,这套系统已经运行10年之久,之前一直没有关机过,所以我们很是谨慎处理这套系统,在搬迁之前已经重启过机器,因为按照以往的经验计算机长时间的运行,重启后就就有可

    2025年7月23日
    3
  • psm倾向得分匹配法举例_【计量地图】倾向得分匹配法(PSM)理论、操作与案例…[通俗易懂]

    这个方法的难点在于:首先,要明白反事实框架是一个什么样的东西?为什么一般把参与项目和不参与项目进行对比时会出现选择偏误?其次,搞清楚上面的原理之后,PSM真正难的是找到合适的协变量和完成两个苛刻的检验(共同支撑检验和平衡性检验)这篇文章我想达到哪些学习目标:(1)尽量汇集我看过的有用的资料(2)展示一个PSM分析的理论框架(3)针对难点说一下模型的调整问题(协变量选择、两个检验的调整)主要框架:1…

    2022年4月12日
    247

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号