【网络编程】深入了解UDP协议:快速数据传输的利器

news2024/11/18 5:39:57
  • (꒪ꇴ꒪ ),Hello我是祐言QAQ
  • 我的博客主页:C/C++语言,数据结构,Linux基础,ARM开发板,网络编程等领域UP🌍
  • 快上🚘,一起学习,让我们成为一个强大的攻城狮!
  • 送给自己和读者的一句鸡汤🤔:集中起来的意志可以击穿顽石!
  • 作者水平很有限,如果发现错误,请在评论区指正,感谢🙏


        在计算机网络中,UDP(User Datagram Protocol)是一种重要的传输层协议,与TCP(Transmission Control Protocol)一样位于 OSI 模型的传输层。但与TCP不同,UDP提供了一种无连接、轻量级的数据传输方式,适用于需要快速传输数据的应用场景。本文将深入探讨UDP协议的特点、用途以及与TCP的对比。

一、UDP的特点

  1. 无连接性:UDP不需要在通信前建立连接,也不维护连接状态,因此它更加轻量级。这使得UDP适用于实时数据传输,如音频和视频流。

  2. 不可靠性:UDP不提供数据包的可靠性传输。这意味着数据包可能会丢失、重复或无序到达目标。因此,UDP通常用于那些可以容忍一些数据丢失的应用,如实时多媒体流。

  3. 高性能:由于不需要建立连接和维护状态信息,UDP的开销较低,具有较高的性能。这使得它成为一种适用于高吞吐量、低延迟的协议。

  4. 头部小:UDP的头部相对较小,只包含源端口、目标端口、长度和校验和等字段,这有助于减少数据传输时的开销。

  5. 多播和广播: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;
	}

	// 创建套接字socket
	int 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跟PORT
	int 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/sendto
	while(1)
	{
		bzero(buf, sizeof(buf));
		// 每接收一条客户端发送的信息,保存一次客户端的IP+PORT
		recvfrom(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);
	}

	// 关闭套接字close
	close(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+PORT
		recvfrom(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) 创建套接字socket
	int 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地址(一般以传参的传进来)

	// 先发一条上线的消息给server
	char 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');

		// 发送数据buf
		sendto(cli_socket, buf, strlen(buf), 0, (struct sockaddr *)&addr, sizeof(addr));
	}

	// (5) 关闭套接字close
	close(cli_socket);

	return 0;
}

四、UDP套接字获取和设置

        在UDP套接字编程中,你可以使用 getsockoptsetsockopt 函数来获取和设置套接字的属性。以下是一些常见的UDP套接字属性以及如何使用这两个函数来处理它们:

获取套接字属性(使用 getsockopt 函数):

  1. 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 中包含接收缓冲区的大小
      
  2. SO_RCVTIMEO 和 SO_SNDTIMEO

    • 功能:获取套接字的接收超时时间和发送超时时间。
    • 示例代码:
      struct timeval timeout;
      socklen_t optlen = sizeof(timeout);
      getsockopt(socket_fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, &optlen);
      // 现在 timeout 中包含接收超时时间
      

设置套接字属性(使用 setsockopt 函数):

  1. SO_RCVBUF 和 SO_SNDBUF

    • 功能:设置套接字的接收缓冲区和发送缓冲区的大小。
    • 示例代码:
      int buffer_size = 8192; // 设置缓冲区大小
      setsockopt(socket_fd, SOL_SOCKET, SO_RCVBUF, &buffer_size, sizeof(buffer_size));
      

  2. 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套接字属性设置选项。可以根据需要使用 getsockoptsetsockopt 函数来获取和设置套接字的其他属性,具体选项取决于你的应用程序的需求。套接字属性设置允许你自定义套接字的行为,以满足不同的网络通信需求。在上面的服务端与客户端通信中也有用到一些示例。

五、与TCP的对比

UDP和TCP是两种不同的传输协议,它们在以下方面有所不同:

  • 连接性:UDP无连接,TCP面向连接。

  • 可靠性:UDP不提供可靠性传输,TCP提供可靠性传输。

  • 开销:UDP开销较低,TCP开销较高。

  • 适用场景:UDP适用于需要快速传输但可以容忍一些数据丢失的应用,而TCP适用于需要确保数据完整性和可靠性的应用。

六、总结

        UDP协议在网络通信中扮演着重要的角色,尤其是在需要实时性和低延迟的应用中。虽然它不提供可靠性传输,但在正确的应用场景下,UDP是一个强大的工具,能够满足快速数据传输的需求。了解UDP的特点和用途有助于网络工程师更好地选择合适的协议来满足应用程序的需求。

        更多C/C++语言Linux系统数据结构ARM板实战相关文章,关注专栏:

   手撕C语言

            玩转linux

                    脚踢数据结构

                            系统、网络编程

                                     探索C++

                                             6818(ARM)开发板实战

📢写在最后

  • 今天的分享就到这啦~
  • 觉得博主写的还不错的烦劳 一键三连喔~
  • 🎉🎉🎉感谢关注🎉🎉🎉

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/984625.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MILP(混合整数线性规划)

线性规划定义 线性规划问题需要满足以下三个条件&#xff1a; 1.每一个问题用一组决策变量表示某一方案 2.约束条件可以用一组线性等式或者线性不等式来表示 3.目标函数为由决策变量及其有关的价值系数构成线性函数 ILP与MILP定义 整数线性规划中如果所有的变量被限制为&a…

闭包的详细认识与实例

参考https://www.bilibili.com/video/BV1sY4y1U7BT/?spm_id_from333.337.search-card.all.click&vd_source2a0404a7c8f40ef37a32eed32030aa18 一、什么叫闭包 1、问题引出&#xff1a; 不准用全局变量&#xff0c;也不准在调用代码块使用变量&#xff0c;实现计数…

以气象行业为例,浅谈在ToB/ToG行业中如何做好UI设计

商业气象公司是典型的TOB/TOG性质的公司&#xff0c;客户包括农业、能源、航空航天、交通运输、建筑工程等行业&#xff0c;它们需要准确的气象数据、预报和分析来支持业务决策和运营管理。商业气象公司通常会提供各种气象服务&#xff0c;如气象数据采集与分析、预报产品、风险…

软文推广效果怎么样?这篇揭晓答案

软文推广是一种常用的网络营销手段&#xff0c;它通过以文章形式发布关于产品、服务或品牌的信息&#xff0c;来引起受众的兴趣和关注。相较于直接宣传广告&#xff0c;软文推广更注重内容的质量和吸引力&#xff0c;能够更好地传递信息并提升用户转化率。本文伯乐网络传媒将探…

2023高教社杯全国大学生数学建模竞赛选题建议

如下为C君的2023高教社杯全国大学生数学建模竞赛&#xff08;国赛&#xff09;选题建议&#xff0c; 提示&#xff1a;DS C君认为的难度&#xff1a;C<B<A&#xff0c;开放度&#xff1a;B<A<C 。 D、E题推荐选E题&#xff0c;后续会直接更新E论文和思路&#xf…

财报解读:休闲零食全渠道时代来临,卫龙如何追寻长期价值?

2023上半年&#xff0c;休闲零食行业进入边际复苏周期&#xff0c;据Sandalwood电商监测数据&#xff0c;2023年5月和6月&#xff0c;休闲食品线上销售同比增速分别为11%和12%。这一态势下&#xff0c;辣味休闲食品行业的龙头企业卫龙也取得阶段性成果。 近日&#xff0c;卫龙…

python+django医院住院收费管理系统设计与实现vue

基于Python语言设计并实现了医院管理系统。该系统基于B/S即所谓浏览器/服务器模式&#xff0c;应用B/S框架&#xff0c;选择MySQL作为后台数据库。系统主要包括首页、个人中心、用户管理、医生管理、科室管理、挂号管理、接诊管理、诊断结果管理、开处方管理、药房管理、药品出…

浪潮服务器安装CentOS 7 教程,并解决一直卡在 dracut问题

准备工作 服务器装centOS7.9 1.下载正确的镜像。 2.使用软碟通或者refus刻U 盘启动盘。 3.服务器插入U盘&#xff0c;开机&#xff0c;在inspur浪潮logo界面按F11 进入启动菜单页面&#xff0c;选择U 盘启动。 4.开始安装centos系统。 注意&#xff1a;必须使用软碟通或者re…

《C++设计模式》——结构型

前言 结构模式可以让我们把很多小的东西通过结构模式组合起来成为一个打的结构&#xff0c;但是又不影响各自的独立性&#xff0c;尽可能减少各组件之间的耦合。 Adapter Class/Object(适配器&#xff09; Bridge(桥接&#xff09; Composite(组合) Decorator(装饰) 动态…

项目打包docker镜像 | 上传nexus | jenkins一键构建

文章目录 前言准备实操1、打开docker的远程访问2、编写dockerfile文件3、指定nexus环境4、配置jenkins5、使用jenkins构建 总结 前言 Docker部署项目是指使用Docker容器化技术将应用程序及其依赖项打包成一个独立的、可移植的运行环境&#xff0c;并在各种操作系统和平台上进行…

敏感信息防泄漏:透明加密与通信内容安全策略深度解析

随着信息技术的迅猛发展&#xff0c;计算机和网络已经成为了我们日常生活中不可或缺的工具&#xff0c;用于办公、通信和协作。尽管这些信息系统提高了工作效率&#xff0c;但也引发了一系列与信息安全相关的问题&#xff0c;例如如何有效地保护存储在这些系统中的关键数据&…

主动获取用户的ColaKey接口

主动获取用户的ColaKey接口 一、主动获取用户的ColaKey接口二、使用步骤1、接口***重要提示:建议使用https协议,当https协议无法使用时再尝试使用http协议***2、请求参数 三、 请求案例和demo1、请求参数例子&#xff08;POST请求&#xff0c;参数json格式&#xff09;2、响应返…

LTD242次升级 | 商品订单可后台改价格 • 产品分享页可下载附件 • 购物车中可修改规格

1、商品订单支持后台修改价格与关闭、支持会员ID搜索 2、购物车支持修改规格、支持预约天数等信息展示 3、官微名片首页支持分享朋友圈&#xff0c;界面展示优化 4、产品分享页支持附件下载 5、详情页附件下载支持保存为原文件名 6、其他已知问题修复与样式优化 01 官微中心 1…

vector以及其使用

vector vector类型是一个标准库中的类型&#xff0c;代表一个容器、集合或者动态数组这样一种概念。既然是容器&#xff0c;那就可以把若干个对象放到里面。当然&#xff0c;这些对象的类型必须相同。简单来说&#xff0c;可以把一堆int型数字放到vector容器中去&#xff0c;复…

Ubuntu之apt-get系列--安装JDK8--方法/教程

原文网址&#xff1a;Ubuntu之apt-get系列--安装JDK8--方法/教程_IT利刃出鞘的博客 简介 本文介绍如何在Ubuntu下安装JDK8。 验证是否安装 可以通过如下命令判断系统是否有安装ssh服务&#xff1a; 命令 java -version 结果 如上所示&#xff0c;表示还没有安装。 查看…

自动化运维工具Ansible教程(一)【入门篇】

文章目录 前言Ansible 入门到精通入门篇进阶篇精通篇入门篇1. Ansible 简介2. 安装 Ansible1. 通过包管理器安装&#xff1a;2. 通过源码安装&#xff1a; 3. Ansible 的基本概念和核心组件4. 编写和运行第一个 Ansible Playbook5. 主机清单和组织结构主机清单组织结构 6. Ansi…

好用免费的Chat GPT(亲测有用)

1、MindLink麦灵 MindLink麦灵 点进登录后 普通用户可以提问100次 2、你问我答 你问我答 无限次数的。 3、灵感 灵感 点击链接后会提示你如何下载使用。 这个有win版和mac版&#xff0c;点击登陆后&#xff0c;每日都会有30次GPT3/3.5的提问。 4、WebTab 在浏览器插件中…

如何加载卫星影像全国一张图?

我们在“你的家乡清晰可见&#xff0c;全国卫星影像100%覆盖&#xff01;”一文中&#xff0c;为你分享了一个可以十分方便地查看家乡高清卫星影像的方法。 该卫星影像数据源由长光卫星提供&#xff0c;你可以通过水经微图PC端或Web端查看&#xff0c;也可以将该卫星影像加载到…

指针跃动——客户运营服务中心上线了!

指针跃动——客户运营服务中心上线了&#xff01; ——打通客户运营服务全链路—— 随着全国代驾业务需求的不断增长&#xff0c;“指针跃动”宣布&#xff1a;指针跃动——客户运营服务中心上线了&#xff01; 以新的思维方式来看待客户服务&#xff0c;利用人工智能、大数据等…

Flyway-数据库管理工具使用与命令

工作流程 应用程序完成数据库连接池的建立后&#xff0c;flyway自动运行初次使用&#xff0c;flyway会创建一个flyway_schema_history表&#xff0c;用于记录sql执行记录flyway会扫描项目指定路径&#xff08;默认classpath: db/migration&#xff09;下的所有sql脚本&#xf…