UDP通信协议详解

news/2024/7/3 7:03:08
中文名                用户数据报协议
英文名

User Datagram Protocol

基础

IP数据包服务上增加一点功能

类别

传输层协议

特点

无连接、不可靠、快速传输

用途发送IP数据包

如右图所所示为udp协议的基本信息

上图就是UDP的数据报服务,sendto两次发送的是单独的两个个体,接收端也就必须recvfrom两次,所以UDP没有粘包这种概念!

UDP(User Datagram Protocol)用户数据报协议,非连接的协议,传输数据之前源端和终端不 建立连接,当它想传送时就简单地去抓取来自应用程序的数据,并尽可能快地把它扔到网络上。 在发送端,UDP传送数据的速度仅仅是受应用程序生成数据的速度、计算机的能力和传输带宽 的限制;在接收端,UDP把每个消息段放在队列中,应用程序每次从队列中读一个消息段。 相比TCP就是无需建立链接,结构简单,无法保证正确性,容易丢包(菜鸟教程节选)。

UDP的不可靠性:

上面我们在表格中也说到了UDP协议它的特点就是无连接、不可靠、快速传输,先来说下它为什么不可靠,或者说它的不可靠可以为我们带来什么别的方面的优化:

        我们都知道TCP是流传输且它的特点是可靠(因为它需要确认应答、超时重传这些操作),而在UDP传输则不需要哪些操作(TCP就像我们打电话,得知道对方的电话号码,还得等对方接听起来才可以就那些通话,但是UDP的话就像是发短信,只需要知道号码就可以执行了,至于发送成功了没这不重要,只要发出去就好了)

UDP的应用场景:

        在我们视频通话的时候用的就是UDP传输,假设A,B两人再进行视频通话,其中A网络有点慢导致接收B的数据慢的很,但是B还是按照他那边网速来劲传输,这样就会导致两人在视频通话过程中丢包,但是因为这是UDP协议传输,所以无所谓啊,丢包就丢包,等A的网速好起来了再问下说你刚刚说了啥,B重新说一遍就好.

        假设视频通话使用的是TCP协议传输的话,在A网络卡顿的时候就会造成接收缓冲区堆积,等A网络好的时候看到的B相当于是几分钟之前的B,相当于看的B的录屏,这在视频通话中是根本不行的,所以TCP和UDP协议适用于不同的场景之下:TCP适合那种不允许丢包的网络传输中,而UDP协议适用于那种允许丢包的网络传输中(UDP效率很高)

大家不熟悉TCP的可以看下这篇:

TCP协议的服务器与客户端的程序设计(代码注释超详细)_神厨小福贵!的博客-CSDN博客

UDP客户端和服务器端编程示例

服务器端

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<assert.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>int main()
{int sockfd = socket(AF_INET,SOCK_DGRAM,0);//创建套接字  SOCK_DGRAM这个为UDP数据报套接字assert(sockfd != -1);struct sockaddr_in saddr,caddr; //sockaddr_in在头文件#include<netinet/in.h>或#include <arpa/inet.h>中定义,saddr代表服务器端地址  caddr代表客户端地址memset(&saddr,0,sizeof(saddr));//saddr其实有四项成员,最后一项用来占位的,必须搞为0,索性我们开始直接给全部置为0,后面再来绑定ip和端口saddr.sin_family = AF_INET;//地址族,TCP/ipv4协议族saddr.sin_port = htons(6000);//端口为小端序列,htons转换为网络字节序,也是大端字节序(一般使用都是5000以上,5000以内一般都是特定使用的,比如你办了个手机卡,你能用110这个号码嘛,博客园因为110有特殊意义,一个道理)sadd r.sin_addr.s_addr = inet_addr("192.168.0.108");//自己本地的IP地址(终端ifconfig查询自己的IP)//inet_addr将点分十进制转换为午饭后整型int res = bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));//将sockfd和本地IP绑定//为什么要这个呢(struct sockaddr*)强转呢,bind这个参数类型为struct sockaddr与sockaddr_in类型不一致,所以强转assert(res != -1);// UDP协议传输中没有监听队列这个东西while(1){int len = sizeof(caddr);char buff[128] = {0};recvfrom(sockfd,buff,127,0,(struct sockaddr*)&caddr,&len); //接收客户端发的数据printf("buff = %s",buff);sendto(sockfd,"ok",2,0,(struct sockaddr*)&caddr,sizeof(caddr)); //给客户端发送okclose(c);}
}

客户端:(和服务器端比起来就是,没有那个bind\recvfrom和sendto的顺序)

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<assert.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>int main()
{int sockfd = socket(AF_INET,SOCK_DGRAM,0);//创建套接字assert(sockfd != -1);struct sockaddr_in saddr,caddr; //sockaddr_in在头文件#include<netinet/in.h>或#include <arpa/inet.h>中定义,saddr代表服务器端地址  caddr代表客户端地址memset(&saddr,0,sizeof(saddr));//saddr其实有四项成员,最后一项用来占位的,必须搞为0,索性我们开始直接给全部置为0,后面再来绑定ip和端口saddr.sin_family = AF_INET;//地址族,TCP/ipv4协议族saddr.sin_port = htons(6000);//端口为小端序列,htons转换为网络字节序,也是大端字节序(一般使用都是5000以上,5000以内一般都是特定使用的,比如你办了个手机卡,你能用110这个号码嘛,博客园因为110有特殊意义,一个道理)sadd r.sin_addr.s_addr = inet_addr("192.168.0.108");//自己本地的IP地址(终端ifconfig查询自己的IP)//inet_addr将点分十进制转换为午饭后整型while(1){char budd[128] = {0};fgets(buff,128,stdin);if(strncmp(buff,"end",3) == 0){break;}sendto(sockfd,buff,strlen(buff)-1,0,(struct sockaddr*)&saddr,sizeof(saddr));//TCP中参数只需要写到0那块  主要是TCP中可以通过描述符查询到底层端口memset(buff,0,128);int len = sizeof(saddr);recvfrom(sockfd,buff,127,0,(struct sockaddr*)&saddr,&len);printf("buff = %s \n",buff);}close(sockfd);
}

不可靠的解决?

我们都知道UDP传输不可靠,那么如何解决呢?有种笨办法就是在每次传输完数据之后必须接收recvfrom一个数据才可以得以继续进行,否则就堵塞在revcfrom那块,那么这种方法不就和TCP一样了吗(并且可能自己在应用层实现的应答确认机制没有TCP中的应答确认机制效率高而将它弄成四不像),且丢失了UDP的最大特点-------效率.(最后这段话完全是自己的想法,不知道正确与否,如有不恰当之处,欢迎各位指出)

"好好学习,趁着还来得及!!!"

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

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

相关文章

简单的HTTP服务器程序的编写

HTTP 协议一般指 HTTP&#xff08;超文本传输协议&#xff09;。 超文本传输协议&#xff08;英语&#xff1a;HyperText Transfer Protocol&#xff0c;缩写&#xff1a;HTTP&#xff09;是一种用于分布式、协作式和超媒体信息系统的应用层协议&#xff0c;是因特网上应用最为…

【C++】何时需要自定义拷贝构造函数和赋值符

先来说结论&#xff1a;当类中有指针类型成员变量的时候&#xff0c;一定要自定义拷贝构造和赋值运算符 原因&#xff1a;当我们在有指针类成员变量的时候&#xff0c;还是用默认拷贝构造函数(拷贝构造函数执行的时候会调用赋值符)&#xff0c;默认赋值为浅拷贝&#xff0c;会…

iOS自动布局一

Align: Pin&#xff1a; 转载于:https://www.cnblogs.com/123qw/p/4404167.html

【C++】左值、右值、移动拷贝构造函数、移动赋值函数

左值和右值的定义以及区别: 先来看在C语言中的左值和右值 &#xff1a; 左值&#xff1a;可赋值的值为左值 右值&#xff1a;不可赋值的值为右值 再来看C中左值右值的定义如下&#xff1a; 左值&#xff1a;可以取地址的值&#xff08;有名字的值、非临时量&#xff09; …

【C++】typedfe和宏定义的区别

先来说结论&#xff1a; 1.宏定义作用于编译之前(也就是预编译阶段&#xff0c;而typedef作用于编译阶段 2.typedef仅限于类型的重定义&#xff0c;而宏定义不仅可以为类型起别名还可以为数值定义起别名(简单的替换) 下面来看一下区别 下面这是typedef的用法 typedef int* PI…

GPS部标平台的架构设计(十)-基于Asp.NET MVC构建GPS部标平台

在当前很多的GPS平台当中&#xff0c;有很多是基于asp.NETsiverlight开发的遗留项目&#xff0c;代码混乱而又难以维护&#xff0c;各种耦合和关联&#xff0c;要命的是界面也没见到比Javascript做的控件有多好看&#xff0c;随着需求的增多&#xff0c;平台已经臃肿不堪。 设计…

【C++】虚函数

虚函数是构成C多态的重要一步&#xff0c;今天来说一下虚函数&#xff01; 虚函数&#xff1a; 在基类(或父类)中&#xff0c;使用virtual关键字对函数进行声明为并在一个或多个派生类(子类)中被重新定义的成员函数&#xff0c;通过指向派生类的基类指针或引用&#xff0c;访…

看了极光推送技术原理的几点思考

看了极光推送技术原理的几点思考 分类&#xff1a; android2012-11-26 20:50 16586人阅读 评论(18) 收藏 举报目录(?)[] 移动互联网应用现状 因为手机平台本身、电量、网络流量的限制&#xff0c;移动互联网应用在设计上跟传统 PC 上的应用很大不一样&#xff0c;需要根据手机…