【网络编程】深入了解UDP协议:快速数据传输的利器
- (꒪ꇴ꒪ ),Hello我是祐言QAQ
- 我的博客主页:C/C++语言,数据结构,Linux基础,ARM开发板,网络编程等领域UP🌍
- 快上🚘,一起学习,让我们成为一个强大的攻城狮!
- 送给自己和读者的一句鸡汤🤔:集中起来的意志可以击穿顽石!
- 作者水平很有限,如果发现错误,请在评论区指正,感谢🙏
在计算机网络中,UDP(User Datagram Protocol)是一种重要的传输层协议,与TCP(Transmission Control Protocol)一样位于 OSI 模型的传输层。但与TCP不同,UDP提供了一种无连接、轻量级的数据传输方式,适用于需要快速传输数据的应用场景。本文将深入探讨UDP协议的特点、用途以及与TCP的对比。
一、UDP的特点
-
无连接性:UDP不需要在通信前建立连接,也不维护连接状态,因此它更加轻量级。这使得UDP适用于实时数据传输,如音频和视频流。
-
不可靠性:UDP不提供数据包的可靠性传输。这意味着数据包可能会丢失、重复或无序到达目标。因此,UDP通常用于那些可以容忍一些数据丢失的应用,如实时多媒体流。
-
高性能:由于不需要建立连接和维护状态信息,UDP的开销较低,具有较高的性能。这使得它成为一种适用于高吞吐量、低延迟的协议。
-
头部小:UDP的头部相对较小,只包含源端口、目标端口、长度和校验和等字段,这有助于减少数据传输时的开销。
-
多播和广播:UDP支持多播和广播,可以同时向多个接收方发送数据包,适用于一对多或多对多通信。
二、UDP的用途
UDP在许多应用中发挥着重要作用,包括但不限于:
-
实时音视频传输:VoIP电话、视频会议和直播流都使用UDP来传输实时音视频数据,因为它具有低延迟和快速传输的特性。
-
DNS查询:域名系统(DNS)使用UDP来快速查询域名解析。
-
游戏数据传输:在线游戏经常使用UDP来传输游戏数据,以确保低延迟和实时性。
-
网络广播:UDP用于发送广播消息,例如局域网内的设备发现和服务广告。
三、UDP实现服务器与客户端相互通信
在此之前我们已经学习掌握了TCP/IP实现服务器与客户端通信,链接我放这里:
【网络编程】TCP传输控制协议(Transmission Control Protocol)_祐言QAQ的博客-CSDN博客
那么现在让我们一起来学习一下UDP如何实现通信。
1.UDP服务器与客户端设计思路

不难看出其中与TCP通信有几个不同点:
①套接字类型:
TCP使用 SOCK_STREAM 表示流式套接字,这意味着它提供面向连接的、可靠的、基于字节流的通信;
UDP使用 SOCK_DGRAM 表示数据报套接字,这表明它提供无连接的、不可靠的、基于数据报的通信。
②通信流程:
在TCP中,通信需要经过 listen、accept 和 connect 过程,其中建立连接是必要的;
在UDP中,通信是无连接的,不需要建立连接,因此不需要进行 listen、accept 和 connect 步骤。
③收发数据的函数:
在TCP中,通常使用 recv 和 send 函数来进行数据的接收和发送;
在UDP中,通常使用 recvfrom 和 sendto 函数来进行数据的接收和发送。这些函数需要指定目标地址,因为UDP是无连接的,每个数据包都需要包含目标地址信息。
2.具体实现代码
udp_server.c
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <strings.h>
#include <pthread.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>// 定义一个结构体用于存储客户端信息
struct Client
{struct sockaddr_in addr; // 客户端地址结构体int ser_socket; // 服务器套接字
};// 线程函数,用于发送数据
void *send_data(void *arg)
{struct Client *cli = (struct Client *)arg;char buf[1024];while (1){scanf("%[^\n]", buf); // 从用户输入读取数据while (getchar() != '\n');// 发送数据到客户端sendto(cli->ser_socket, buf, strlen(buf), 0, (struct sockaddr *)&(cli->addr), sizeof(cli->addr));}
}int main(int argc, char const *argv[])
{if (argc != 2){printf("./server <port>\n");return -1;}// 创建套接字socketint ser_socket = socket(AF_INET, SOCK_DGRAM, 0);if (ser_socket == -1){perror("socket");return -1;}// 设置套接字属性,SO_REUSEADDR 允许地址端口重用int on = 1;if (setsockopt(ser_socket, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1){perror("setsockopt");return -1;}// 初始化地址结构体struct sockaddr_in addr;addr.sin_family = AF_INET; // 地址簇addr.sin_port = atoi(argv[1]); // 端口(一般以传参的传进来)// addr.sin_addr.s_addr = inet_addr("192.168.1.128"); // IP地址addr.sin_addr.s_addr = htonl(INADDR_ANY); // 用特殊的"0.0.0.0"这个IP来绑定本机IP地址// bind 绑定IP跟PORTint b = bind(ser_socket, (struct sockaddr *)&addr, sizeof(struct sockaddr_in));if(b == -1){perror("bind");return -1;}printf("绑定成功\n");struct sockaddr_in c_addr; // IPV4地址结构体int addrlen = sizeof(c_addr);char buf[1024];// 接收客户端的第一条消息recvfrom(ser_socket, buf, sizeof(buf), 0, (struct sockaddr *)&c_addr, &addrlen);printf("[%s] [%d]:%s\n", inet_ntoa(c_addr.sin_addr), c_addr.sin_port, buf);struct Client cli;cli.addr = c_addr;cli.ser_socket = ser_socket;// 创建一个线程用来发送数据pthread_t pid;pthread_create(&pid, NULL, send_data, &cli);// 接收/发送数据 recvfrom/sendtowhile(1){bzero(buf, sizeof(buf));// 每接收一条客户端发送的信息,保存一次客户端的IP+PORTrecvfrom(ser_socket, buf, sizeof(buf), 0, (struct sockaddr *)&c_addr, &addrlen);// 第一次接收,创建线程发送数据,将套接字,对方的IP地址传递给线程任务函数printf("[%s] [%d]:%s\n", inet_ntoa(c_addr.sin_addr), c_addr.sin_port, buf);}// 关闭套接字closeclose(ser_socket);return 0;
}
udp_client.c
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <strings.h>
#include <pthread.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>// 线程函数,用于接收数据
void *recv_data(void *arg)
{int cli_socket = *(int *)arg;struct sockaddr_in c_addr;int addrlen = sizeof(c_addr);char buf[1024];while(1){bzero(buf, sizeof(buf));// 每接收一条客户端发送的信息,保存一次客户端的IP+PORTrecvfrom(cli_socket, buf, sizeof(buf), 0, (struct sockaddr *)&c_addr, &addrlen);printf("[%s] [%d]:%s\n", inet_ntoa(c_addr.sin_addr), c_addr.sin_port, buf);}
}int main(int argc, char const *argv[])
{if (argc != 3){printf("./client <ip> <port>\n");return -1;}// (1) 创建套接字socketint cli_socket = socket(AF_INET, SOCK_DGRAM, 0);if (cli_socket == -1){perror("socket");return -1;}// (2) 初始化地址结构体(服务器的)struct sockaddr_in addr;addr.sin_family = AF_INET; // 地址簇addr.sin_port = atoi(argv[2]); // 服务器端的端口(一般以传参的传进来)addr.sin_addr.s_addr = inet_addr(argv[1]); // 服务器端的IP地址(一般以传参的传进来)// 先发一条上线的消息给serverchar buf[1024] = "on line";sendto(cli_socket, buf, strlen(buf), 0, (struct sockaddr *)&addr, sizeof(addr));// 创建线程用来接收数据pthread_t pid;pthread_create(&pid, NULL, recv_data, &cli_socket);// (3) 发送数据while(1){scanf("%[^\n]", buf); // 从用户输入读取数据while(getchar()!='\n');// 发送数据bufsendto(cli_socket, buf, strlen(buf), 0, (struct sockaddr *)&addr, sizeof(addr));}// (5) 关闭套接字closeclose(cli_socket);return 0;
}
四、UDP套接字获取和设置
在UDP套接字编程中,你可以使用 getsockopt 和 setsockopt 函数来获取和设置套接字的属性。以下是一些常见的UDP套接字属性以及如何使用这两个函数来处理它们:
获取套接字属性(使用 getsockopt 函数):
-
SO_RCVBUF 和 SO_SNDBUF:
- 功能:获取套接字的接收缓冲区和发送缓冲区的大小。
- 示例代码:
int buffer_size; socklen_t optlen = sizeof(buffer_size); getsockopt(socket_fd, SOL_SOCKET, SO_RCVBUF, &buffer_size, &optlen); // 现在 buffer_size 中包含接收缓冲区的大小
-
SO_RCVTIMEO 和 SO_SNDTIMEO:
- 功能:获取套接字的接收超时时间和发送超时时间。
- 示例代码:
struct timeval timeout; socklen_t optlen = sizeof(timeout); getsockopt(socket_fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, &optlen); // 现在 timeout 中包含接收超时时间
设置套接字属性(使用 setsockopt 函数):
-
SO_RCVBUF 和 SO_SNDBUF:
- 功能:设置套接字的接收缓冲区和发送缓冲区的大小。
- 示例代码:
int buffer_size = 8192; // 设置缓冲区大小 setsockopt(socket_fd, SOL_SOCKET, SO_RCVBUF, &buffer_size, sizeof(buffer_size));
-
SO_RCVTIMEO 和 SO_SNDTIMEO:
- 功能:设置套接字的接收超时时间和发送超时时间。
- 示例代码:
struct timeval timeout; timeout.tv_sec = 5; // 设置超时时间为5秒 timeout.tv_usec = 0; setsockopt(socket_fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
这些是一些常见的UDP套接字属性设置选项。可以根据需要使用 getsockopt 和 setsockopt 函数来获取和设置套接字的其他属性,具体选项取决于你的应用程序的需求。套接字属性设置允许你自定义套接字的行为,以满足不同的网络通信需求。在上面的服务端与客户端通信中也有用到一些示例。
五、与TCP的对比
UDP和TCP是两种不同的传输协议,它们在以下方面有所不同:
-
连接性:UDP无连接,TCP面向连接。
-
可靠性:UDP不提供可靠性传输,TCP提供可靠性传输。
-
开销:UDP开销较低,TCP开销较高。
-
适用场景:UDP适用于需要快速传输但可以容忍一些数据丢失的应用,而TCP适用于需要确保数据完整性和可靠性的应用。
六、总结
UDP协议在网络通信中扮演着重要的角色,尤其是在需要实时性和低延迟的应用中。虽然它不提供可靠性传输,但在正确的应用场景下,UDP是一个强大的工具,能够满足快速数据传输的需求。了解UDP的特点和用途有助于网络工程师更好地选择合适的协议来满足应用程序的需求。
更多C/C++语言、Linux系统、数据结构和ARM板实战相关文章,关注专栏:
手撕C语言
玩转linux
脚踢数据结构
系统、网络编程
探索C++
6818(ARM)开发板实战
📢写在最后
- 今天的分享就到这啦~
- 觉得博主写的还不错的烦劳
一键三连喔~ - 🎉🎉🎉感谢关注🎉🎉🎉
相关文章:
【网络编程】深入了解UDP协议:快速数据传输的利器
(꒪ꇴ꒪ ),Hello我是祐言QAQ我的博客主页:C/C语言,数据结构,Linux基础,ARM开发板,网络编程等领域UP🌍快上🚘,一起学习,让我们成为一个强大的攻城狮࿰…...
WordPress(5)在主题中添加文章字数和预计阅读时间
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 样式图一、添加位置二、找到主题文件样式图 提示:以下是本篇文章正文内容,下面案例可供参考 一、添加位置 二、找到主题文件 在主题目录下functions.php文件把下面的代码添加进去: // 文章字数…...
STM32WB55开发(1)----套件概述
STM32WB55开发----1.套件概述 所用器件视频教学样品申请优势支持协议系统控制和生态系统访问功能示意图系统框图跳线设置开发板原理图 所用器件 所使用的器件是我们自行设计的开发板,该开发板是基于 STM32WB55 系列微控制器所构建。STM32WBXX_VFQFPN68 不仅是一款评…...
CUDA相关知识科普
显卡 显卡(Video card,Graphics card)全称显示接口卡,又称显示适配器,是计算机最基本配置、最重要的配件之一。就像电脑联网需要网卡,主机里的数据要显示在屏幕上就需要显卡。因此,显卡是电脑进…...
恒运资本:总市值和总资产区别?
总市值和总财物是财政术语中经常被提到的两个概念,很多人会将它们混淆。在金融领域中,了解这两个概念的差异十分重要。本文将从多个视点深入分析总市值和总财物的差异。 1.定义 总市值是指公司发行的一切股票的商场总价值。所谓商场总价值…...
CTF安全竞赛介绍
目录 一、赛事简介 二、CTF方向简介 1.Web(Web安全) (1)简介 (2)涉及主要知识 2.MISC(安全杂项) (1)介绍 (2)涉及主要知识 3…...
DC/DC开关电源学习笔记(四)开关电源电路主要器件及技术动态
(四)开关电源电路主要器件及技术动态 1.半导体器件2.变压器3.电容器4.功率二极管5.其他常用元件5.1 电阻5.2 电容5.3 电感5.4 变压器5.5 二极管5.6 整流桥5.7 稳压管5.8 绝缘栅-双极性晶体管1.半导体器件 功率半导体器件仍然是电力电子技术发展的龙头, 电力电子技术的进步必…...
数据可视化与数字孪生:理解两者的区别
在数字化时代,数据技术正在引领创新,其中数据可视化和数字孪生是两个备受关注的概念。尽管它们都涉及数据的应用,但在本质和应用方面存在显著区别。本文带大探讨数据可视化与数字孪生的差异。 概念 数据可视化: 数据可视化是将复…...
C++ socket编程(TCP)
服务端保持监听客户端, 服务端采用select实现,可以监听多个客户端 客户端源码 在这里插入代码片 #include <iostream> //#include <windows.h> #include <WinSock2.h> #include <WS2tcpip.h> using namespace std; #pragma co…...
ldd用于打印程序或库文件所依赖的共享库列表
这是一个Linux命令行指令,将两个常用的命令 ldd 和 grep 组合使用。我来逐一为您解释: ldd: 这是一个Linux工具,用于打印程序或库文件所依赖的共享库列表。通常,当你有一个可执行文件并且想知道它链接到哪些动态库时,你…...
vue+elementUI el-table实现单选
if (selection.length > 1) {this.$refs.table.clearSelection();this.$refs.table.toggleRowSelection(selection.pop());}...
前端组件库造轮子——Message组件开发教程
前端组件库造轮子——Message组件开发教程 前言 本系列旨在记录前端组件库开发经验,我们的组件库项目目前已在Github开源,下面是项目的部分组件。文章会详细介绍一些造组件库轮子的技巧并且最后会给出完整的演示demo。 文章旨在总结经验,开…...
单片机第二季:温度传感器DS18B20
目录 1,DS18B20介绍 2,DS18B20数据手册 2.1,初始化时序 2.2,读写时序 3,DS18B20工作流程 4,代码 1,DS18B20介绍 DS18B20的基本特征: (1)内置集成ADC,外部数字接…...
抓包工具fiddler的基础知识
目录 简介 1、作用 2、使用场景 3、http报文分析 3.1、请求报文 3.2、响应报文 4、介绍fiddler界面功能 4.1、AutoResponder(自动响应器) 4.2、Composer(设计请求) 4.3、断点 4.4、弱网测试 5、app抓包 简介 fiddler是位于客户端和服务端之间的http代理 1、作用 监控浏…...
监控基本概念
监控:这个词在不同的上下文中有不同的含义,在讲到监控MySQL或者监控Redis时,这里只涉及数据采集和可视化,不涉及告警引擎和事件处理。要是监控系统的话,不但包括数据采集和可视化,而且也包括告警和事件发送…...
【数据结构】 七大排序详解(壹)——直接插入排序、希尔排序、选择排序、堆排序
文章目录 🍀排序的概念及引用🐱👤排序的概念🐱👓排序运用🐱🐉常见的排序算法 🌴插入排序🎋基本思想:🛫直接插入排序📌算法步骤&…...
【Linux】高级IO --- Reactor网络IO设计模式
人其实很难抵制诱惑,人只能远离诱惑,所以千万不要高看自己的定力。 文章目录 一、LT和ET模式1.理解LT和ET的工作原理2.通过代码来观察LT和ET工作模式的不同3.ET模式高效的原因(fd必须是非阻塞的)4.LT和ET模式使用时的读取方式 二…...
Agisoft Metashape相机标定笔记
Lens Calibration(镜头标定) 使用Metashape进行自动相机标定是可能的。Metashape使用LCD显示屏作为标定目标(可选:使用打印的棋盘格图案,但需保证它是平坦的且单元格是正方形)。 相机标定步骤支持全相机标定矩阵的估计ÿ…...
vue-cropper在ie11下选择本地图片后,无显示、拒绝访问的问题
问题:vue-cropper在ie11下选择本地图片后,网页上并未显示出图片,打开F12有报错:拒绝访问blabla的。但是在chrome下一切正常。 开发环境:node14.17.5 , vue2 , vue-cropper0.6.2 , macOS big sur 11.4(M1). 解决办法&…...
Excel VSTO开发11-自定义菜单项
版权声明:本文为博主原创文章,转载请在显著位置标明本文出处以及作者网名,未经作者允许不得用于商业目的。 11 自定义菜单项 自定义菜单项可以在插件启动时候添加,即增加到ThisAddIn_Startup() 内。 下面以具体代码说明&#x…...
UE5 学习系列(二)用户操作界面及介绍
这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…...
iPhone密码忘记了办?iPhoneUnlocker,iPhone解锁工具Aiseesoft iPhone Unlocker 高级注册版分享
平时用 iPhone 的时候,难免会碰到解锁的麻烦事。比如密码忘了、人脸识别 / 指纹识别突然不灵,或者买了二手 iPhone 却被原来的 iCloud 账号锁住,这时候就需要靠谱的解锁工具来帮忙了。Aiseesoft iPhone Unlocker 就是专门解决这些问题的软件&…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个生活电费的缴纳和查询小程序
一、项目初始化与配置 1. 创建项目 ohpm init harmony/utility-payment-app 2. 配置权限 // module.json5 {"requestPermissions": [{"name": "ohos.permission.INTERNET"},{"name": "ohos.permission.GET_NETWORK_INFO"…...
ios苹果系统,js 滑动屏幕、锚定无效
现象:window.addEventListener监听touch无效,划不动屏幕,但是代码逻辑都有执行到。 scrollIntoView也无效。 原因:这是因为 iOS 的触摸事件处理机制和 touch-action: none 的设置有关。ios有太多得交互动作,从而会影响…...
html-<abbr> 缩写或首字母缩略词
定义与作用 <abbr> 标签用于表示缩写或首字母缩略词,它可以帮助用户更好地理解缩写的含义,尤其是对于那些不熟悉该缩写的用户。 title 属性的内容提供了缩写的详细说明。当用户将鼠标悬停在缩写上时,会显示一个提示框。 示例&#x…...
MacOS下Homebrew国内镜像加速指南(2025最新国内镜像加速)
macos brew国内镜像加速方法 brew install 加速formula.jws.json下载慢加速 🍺 最新版brew安装慢到怀疑人生?别怕,教你轻松起飞! 最近Homebrew更新至最新版,每次执行 brew 命令时都会自动从官方地址 https://formulae.…...
MySQL 主从同步异常处理
阅读原文:https://www.xiaozaoshu.top/articles/mysql-m-s-update-pk MySQL 做双主,遇到的这个错误: Could not execute Update_rows event on table ... Error_code: 1032是 MySQL 主从复制时的经典错误之一,通常表示ÿ…...
【Elasticsearch】Elasticsearch 在大数据生态圈的地位 实践经验
Elasticsearch 在大数据生态圈的地位 & 实践经验 1.Elasticsearch 的优势1.1 Elasticsearch 解决的核心问题1.1.1 传统方案的短板1.1.2 Elasticsearch 的解决方案 1.2 与大数据组件的对比优势1.3 关键优势技术支撑1.4 Elasticsearch 的竞品1.4.1 全文搜索领域1.4.2 日志分析…...
用鸿蒙HarmonyOS5实现中国象棋小游戏的过程
下面是一个基于鸿蒙OS (HarmonyOS) 的中国象棋小游戏的实现代码。这个实现使用Java语言和鸿蒙的Ability框架。 1. 项目结构 /src/main/java/com/example/chinesechess/├── MainAbilitySlice.java // 主界面逻辑├── ChessView.java // 游戏视图和逻辑├──…...
k8s从入门到放弃之HPA控制器
k8s从入门到放弃之HPA控制器 Kubernetes中的Horizontal Pod Autoscaler (HPA)控制器是一种用于自动扩展部署、副本集或复制控制器中Pod数量的机制。它可以根据观察到的CPU利用率(或其他自定义指标)来调整这些对象的规模,从而帮助应用程序在负…...
