UDP协议

频道:电子元器件 日期: 浏览:295

UDP协议

本文内容来自于互联网,分享UDP协议

UDP  UDP(User Datagram Protocol) 用户数据包协议

  用户数据包协议(UDP)是 OSI 参考模型中一种无连接的传输层协议,提供面向事务的简单不可靠信息传送服务。是一个简单的面向数据报的传输层协议,IETF RFC 768是UDP的正式规范。 UDP 协议基本上是 IP 协议与上层协议的接口。 UDP 协议适用端口分别运行在同一台设备上的多个应用程序。

  由于大多数网络应用程序都在同一台机器上运行,计算机上必须能够确保目的地机器上的软件程序能从源地址机器处获得数据包,以及源计算机能收到正确的回复。这是通过使用 UDP 的“端口号”完成的。例如,如果一个工作站希望在工作站 128.1.123.1 上使用域名服务系统,它就会给数据包一个目的地址 128.1.123.1 ,并在 UDP 头插入目标端口号 53 。源端口号标识了请求域名服务的本地机的应用程序,同时需要将所有由目的站生成的响应包都指定到源主机的这个端口上。 UDP 端口的详细介绍可以参照相关文章。

  与 TCP 不同, UDP 并不提供对 IP 协议的可靠机制、流控制以及错误恢复功能等。由于 UDP 比较简单, UDP 头包含很少的字节,比TCP负载消耗少。

  UDP适用于不需要TCP可靠机制的情形,比如,当高层协议或应用程序提供错误和流控制功能的时候。 UDP是传输层协议,服务于很多知名应用层协议,包括网络文件系统(NFS)、简单网络管理协议(SNMP)、域名系统(DNS)以及简单文件传输系统(TFTP)、动态主机配置协议(DHCP)、路由信息协议(RIP)和某些影音串流服务等等。

  协议结构

  Source Port — 16位。源端口是可选字段。当使用时,它表示发送程序的端口,同时它还被认为是没有其它信息的情况下需要被寻址的答复端口。如果不使用,设置值为0。

  Destination Port — 16位。目标端口在特殊因特网目标地址的情况下具有意义。

  Length — 16位。该用户数据报的八位长度,包括协议头和数据。长度最小值为8。

  Checksum — 16位。IP 协议头、UDP 协议头和数据位,最后用0填补的信息假协议头总和。如果必要的话,可以由两个八位复合而成。

  Data — 包含上层数据信息。

  UDP协议有如下的特点:

  1、UDP传送数据前并不与对方建立连接,即UDP是无连接的,在传输数据前,发送方和接收方相互交换信息使双方同步。

  2、UDP不对收到的数据进行排序,在UDP报文的首部中并没有关于数据顺序的信息(如TCP所采用的序号),而且报文不一定按顺序到达的,所以接收端无从排起。

  3、UDP对接收到的数据报不发送确认信号,发送端不知道数据是否被正确接收,也不会重发数据。

  4、UDP传送数据较TCP快速,系统开销也少。

  5、由于缺乏拥塞控制(congestion control),需要基于网络的机制来减小因失控和高速UDP流量负荷而导致的拥塞崩溃效应。换句话说,因为UDP发送者不能够检测拥塞,所以像使用包队列和丢弃技术的路由器这样的网络基本设备往往就成为降低UDP过大通信量的有效工具。数据报拥塞控制协议(DCCP)设计成通过在诸如流媒体类型的高速率UDP流中增加主机拥塞控制来减小这个潜在的问题。

  从以上特点可知,UDP提供的是无连接的、不可靠的数据传送方式,是一种尽力而为的数据交付服务。

  

UDP服务与应用场合

  UDP提供的服务是不可靠的、无连接的服务,UDP适用于无须应答并且通常一次只传送少量数据的情况。由于UDP协议在数据传输过程中无须建立逻辑连接,对数据报也不进行检查,因此UDP具有较好的实时性,效率高。在有些情况下,包括视频电话会议系统在内的众多的客户/服务器模式的网络应用都需要使用UDP协议。

  

UDP协议的几个特性

  

  [1](1) UDP是一个无连接协议,传输数据之前源端和终端不建立连接,当它想传送时就简单地去抓取来自应用程序的数据,并尽可能快地把它扔到网络上。在发送端,UDP传送数据的速度仅仅是受应用程序生成数据的速度、计算机的能力和传输带宽的限制;在接收端,UDP把每个消息段放在队列中,应用程序每次从队列中读一个消息段。

  (2) 由于传输数据不建立连接,因此也就不需要维护连接状态,包括收发状态等,因此一台服务机可同时向多个客户机传输相同的消息。

  (3) UDP信息包的标题很短,只有8个字节,相对于TCP的20个字节信息包的额外开销很小。

  (4) 吞吐量不受拥挤控制算法的调节,只受应用软件生成数据的速率、传输带宽、源端和终端主机性能的限制。

  虽然UDP是一个不可靠的协议,但它是分发信息的一个理想协议。例如,在屏幕上报告股票市场、在屏幕上显示航空信息等等。UDP也用在路由信息协议RIP(Routing Information Protocol)中修改路由表。在这些应用场合下,如果有一个消息丢失,在几秒之后另一个新的消息就会替换它。UDP广泛用在多媒体应用中,例如,Progressive Networks公司开发的RealAudio软件,它是在因特网上把预先录制的或者现场音乐实时传送给客户机的一种软件,该软件使用的RealAudio audio-on-demand protocol协议就是运行在UDP之上的协议,大多数因特网电话软件产品也都运行在UDP之上。

  

UDP协议的应用

  [2]UDP是一种不可靠的网络协议,那么还有什么使用价值或必要呢?其实不然,在有些情况下UDP协议可能会变得非常有用。因为UDP具有TCP所望尘莫及的速度优势。虽然TCP协议中植入了各种安全保障功能,但是在实际执行的过程中会占用大量的系统开销,无疑使速度受到严重的影响。反观UDP由于排除了信息可靠传递机制,将安全和排序等功能移交给上层应用来完成,极大降低了执行时间,使速度得到了保证。

  关于UDP协议的最早规范是RFC768,1980年发布。尽管时间已经很长,但是UDP协议仍然继续在主流应用中发挥着作用。包括视频电话会议系统在内的许多应用都证明了UDP协议的存在价值。因为相对于可靠性来说,这些应用更加注重实际性能,所以为了获得更好的使用效果(例如,更高的画面帧刷新速率)往往可以牺牲一定的可靠性(例如,会面质量)。这就是UDP和TCP两种协议的权衡之处。根据不同的环境和特点,两种传输协议都将在今后的网络世界中发挥更加重要的作用。

  UDP协议和TCP协议的区别

  TCP协议的中文名称是 传输控制协议 。而UDP协议的中文名称是 用户数据报协议 。

  TCP协议是互联网发展过程中非常重要的一个协议,当使用TCP协议作为底层协议时,他能够保证你发送的数据按照一定的时序到达目的地,并且目的地会根据TCP协议的控制数据来校验数据的完整性和正确性。同时TCP协议在网络流量比较拥堵的时候,可以控制数据的流量来防止丢包的发生。需要了解,TCP协议是一个非常严谨的协议,他能够保证数据在恶劣介质的网络(比如wifi,grps连接等)上传送的时候保证数据安全到达。

  然而,TCP协议这种严谨性同时带来了一个问题,由于对数据完整性和正确性的苛刻要求,TCP协议不得不在协议自身中加入大量控制内容。这些控制内容可以用于检验数据包的时序,完整性,正确性等。由于这些数据的加入,导致发送端和接收端的计算量加大,并且,由于这些控制数据的加入,使得传输数据的体积也加大了很多。加重了对网络的负载。这些问题最后都指向一个致命的问题:数据的延迟性被增大了。

  对于网络游戏,视频聊天,语音聊天这种应用,由于用户对数据实时性的要求很高,而对数据完全正确性的要求又有所降低。(比如,聊天的时候,如果有个别数据包丢失或者有误,充其量你就得到一些声音不清楚,不会影响聊天的体验。) UDP协议就诞生在这种需求下。

  所以,总结起来,UDP协议被广泛的使用在对网络数据传输实时性很高而对数据准确性要求不是非常高的场合。而当今网络传输物理介质的高速提升(光纤)也降低了数据包丢失的几率。当网络状态很好的时候,UDP协议的这两个缺点又可以很大程度上被克服。因此,UDP协议现在被广泛运用在很多应用中。

[编辑本段]UDP 程序设计

  [2]UDP Server程序

  1、编写UDP Server程序的步骤

  (1)使用socket()来建立一个UDP socket,第二个参数为SOCK_DGRAM。

  (2)初始化sockaddr_in结构的变量,并赋值。sockaddr_in结构定义:

  struct sockaddr_in {

  uint8_t sin_len;

  sa_family_t sin_family;

  in_port_t sin_port;

  struct in_addr sin_addr;

  char sin_zero[8];

  };

  这里使用“08”作为服务程序的端口,使用“INADDR_ANY”作为绑定的IP地址即任何主机上的地址。

  (3)使用bind()把上面的socket和定义的IP地址和端口绑定。这里检查bind()是否执行成功,如果有错误就退出。这样可以防止服务程序重复运行的问题。

  (4)进入无限循环程序,使用recvfrom()进入等待状态,直到接收到客户程序发送的数据,就处理收到的数据,并向客户程序发送反馈。这里是直接把收到的数据发回给客户程序。

  2、udpserv.c程序内容:

  #include

  #include

  #include

  #include

  #include

  #include

  #define MAXLINE 80

  #define SERV_PORT 8888

  void do_echo(int sockfd, struct sockaddr *pcliaddr, socklen_t clilen)

  {

  int n;

  socklen_t len;

  char mesg[MAXLINE];

  for(;;)

  {

  len = clilen;

  /* waiting for receive data */

  n = recvfrom(sockfd, mesg, MAXLINE, 0, pcliaddr, &len);

  /* sent data back to client */

  sendto(sockfd, mesg, n, 0, pcliaddr, len);

  }

  }

  int main(void)

  {

  int sockfd;

  struct sockaddr_in servaddr, cliaddr;

  sockfd = socket(AF_INET, SOCK_DGRAM, 0); /* create a socket */

  /* init servaddr */

  bzero(&servaddr, sizeof(servaddr));

  servaddr.sin_family = AF_INET;

  servaddr.sin_addr.s_addr = htonl(INADDR_ANY);

  servaddr.sin_port = htons(SERV_PORT);

  /* bind address and port to socket */

  if(bind(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) == -1)

  {

  perror("bind error");

  exit(1);

  }

  do_echo(sockfd, (struct sockaddr *)&cliaddr, sizeof(cliaddr));

  return 0;

UDP协议

  }

  UDP Client程序

  1、编写UDP Client程序的步骤

  (1)初始化sockaddr_in结构的变量,并赋值。这里使用“8888”作为连接的服务程序的端口,从命令行参数读取IP地址,并且判断IP地址是否符合要求。

  (2)使用socket()来建立一个UDP socket,第二个参数为SOCK_DGRAM。

  (3)使用connect()来建立与服务程序的连接。与TCP协议不同,UDP的connect()并没有与服务程序三次握手。上面说了UDP是非连接的,实际上也可以是连接的。使用连接的UDP,kernel可以直接返回错误信息给用户程序,从而避免由于没有接收到数据而导致调用recvfrom()一直等待下去,看上去好像客户程序没有反应一样。

  (4)向服务程序发送数据,因为使用连接的UDP,所以使用write()来替代sendto()。这里的数据直接从标准输入读取用户输入。

  (5)接收服务程序发回的数据,同样使用read()来替代recvfrom()。

  (6)处理接收到的数据,这里是直接输出到标准输出上。

  udpclient.c程序内容:

  #include

  #include

  #include

  #include

  #include

  #include

  #include

  #include

  #define MAXLINE 80

  #define SERV_PORT 8888

  void do_cli(FILE *fp, int sockfd, struct sockaddr *pservaddr, socklen_t servlen)

  {

  int n;

  char sendline[MAXLINE], recvline[MAXLINE + 1];

  /* connect to server */

UDP协议

  if(connect(sockfd, (struct sockaddr *)pservaddr, servlen) == -1)

  {

  perror("connect error");

  exit(1);

  }

  while(fgets(sendline, MAXLINE, fp) != NULL)

  {

  /* read a line and send to server */

  write(sockfd, sendline, strlen(sendline));

  /* receive data from server */

  n = read(sockfd, recvline, MAXLINE);

  if(n == -1)

  {

  perror("read error");

  exit(1);

  }

  recvline[n] = 0; /* terminate string */

  fputs(recvline, stdout);

  }

  }

  int main(int argc, char **argv)

  {

  int sockfd;

  struct sockaddr_in srvaddr;

  /* check args */

  if(argc != 2)

  {

  printf("usage: udpclient \n");

  exit(1);

  }

  /* init servaddr */

  bzero(&servaddr, sizeof(servaddr));

  servaddr.sin_family = AF_INET;

  servaddr.sin_port = htons(SERV_PORT);

  if(inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0)

  {

  printf("[%s] is not a valid IPaddress\n", argv[1]);

  exit(1);

  }

  sockfd = socket(AF_INET, SOCK_DGRAM, 0);

  do_cli(stdin, sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));

  return 0;

  }

  运行例子程序

  1、编译例子程序

  使用如下命令来编译例子程序:

  gcc -Wall -o udpserv udpserv.c

  gcc -Wall -o udpclient udpclient.c

  编译完成生成了udpserv和udpclient两个可执行程序。

  2、运行UDP Server程序

  执行。/udpserv &命令来启动服务程序。我们可以使用netstat -ln命令来观察服务程序绑定的IP地址和端口,部分输出信息如下:

  Active Internet connections (only servers)

  Proto Recv-Q Send-Q Local Address Foreign Address State

  tcp 0 0 0.0.0.0:32768 0.0.0.0:* LISTEN

  tcp 0 0 0.0.0.0:111 0.0.0.0:* LISTEN

  tcp 0 0 0.0.0.0:6000 0.0.0.0:* LISTEN

  tcp 0 0 127.0.0.1:631 0.0.0.0:* LISTEN

  udp 0 0 0.0.0.0:32768 0.0.0.0:*

  udp 0 0 0.0.0.0:8888 0.0.0.0:*

  udp 0 0 0.0.0.0:111 0.0.0.0:*

  udp 0 0 0.0.0.0:882 0.0.0.0:*

  可以看到udp处有“0.0.0.0:8888”的内容,说明服务程序已经正常运行,可以接收主机上任何IP地址且端口为8888的数据。

  如果这时再执行。/udpserv &命令,就会看到如下信息:

  bind error: Address already in use

  说明已经有一个服务程序在运行了。

  运行UDP Client程序

  执行。/udpclient 127.0.0.1命令来启动客户程序,使用127.0.0.1来连接服务程序,执行效果如下:

  Hello, World!

  Hello, World!

  this is a test

  this is a test

  ^d

  输入的数据都正确从服务程序返回了,按ctrl+d可以结束输入,退出程序。

  如果服务程序没有启动,而执行客户程序,就会看到如下信息:

  $ ./udpclient 127.0.0.1

  test

  read error: Connection refused

  说明指定的IP地址和端口没有服务程序绑定,客户程序就退出了。这就是使用connect()的好处,注意,这里错误信息是在向服务程序发送数据后收到的,而不是在调用connect()时。如果使用tcpdump程序来抓包,会发现收到的是ICMP的错误信息。

关键词:协议UDP