UDP

TCP与UDP区别总结:

1、TCP面向连接(如打电话要先拨号建立连接);UDP是无连接的,即发送数据之前不需要建立连接

2、TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即不保证可靠交付

Tcp通过校验和,重传控制,序号标识,滑动窗口、确认应答实现可靠传输。如丢包时的重发控制,还可以对次序乱掉的分包进行顺序控制。

3、UDP具有较好的实时性,工作效率比TCP高,适用于对高速传输和实时性有较高的通信或广播通信。

4.每一条TCP连接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通信

5、TCP对系统资源要求较多,UDP对系统资源要求较少。

6、TCP面向字节流,实际上是TCP把数据看成一连串无结构的字节流;UDP是面向报文的

1. UDP概述

https://www.cnblogs.com/skyfsm/p/6287787.html

UDP(User Datagram Protocol),用户数据报协议。只是在IP数据报服务之上增加了很少的一点功能(复用、分用及差错检验),其主要特点是:(DNS,TFTP,SNMP应用协议)

在这里插入图片描述
在这里插入图片描述

2. UDP报文头

在这里插入图片描述

在这里插入图片描述

数据报的长度是指包括报头和数据部分在内的总字节数。从理论上说,包含报头在内的数据报的最大长度为65535字节。不过,一些实际应用往往会限制数据报的大小,有时会降低到8192字节。

但检测到错误时,UDP不做错误校正,只是简单地把损坏的消息段扔掉,或者给应用程序提供警告信息。

UDP特性

我们知道TCP/IP通常被认为是一个四层协议系统,包括链路层、网络层、传输层、应用层UDP属于传输层,下面我们由下至上一步一步来看: 以太网(Ethernet)数据帧的长度必须在46-1500字节之间,这是由以太网的物理特性决定的。 这个1500字节被称为链路层的MTU(最大传输单元)。 但这并不是指链路层的长度被限制在1500字节,其实这个MTU指的是链路层的数据区并不包括链路层的首部和尾部的18个字节。所以事实上这个1500字节就是网络层IP数据报的长度限制。因为IP数据报的首部为20字节,所以IP数据报的数据区长度最大为1480字节。而这个1480字节就是用来放TCP传来的TCP报文段或UDP传来的UDP数据报的。又因为UDP数据报的首部8字节,所以UDP数据报的数据区最大长度为1472字节。这个1472字节就是我们可以使用的字节数。

鉴于Internet上的标准MTU值为576字节,所以我建议在进行Internet的UDP编程时. 最好将UDP的数据长度控件在548字节(576-8-20)以内。

基本socket编程

在这里插入图片描述

由以上框图可以看出,客户端要发起一次请求,仅仅需要两个步骤(socket和sendto),而服务器端也仅仅需要三个步骤即可接收到来自客户端的消息(socket、bind、recvfrom)。

(1)recvfrom

#include <sys/types.h>
#include <sys/socket.h>
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
                struct sockaddr *src_addr, socklen_t *addrlen);

第一个参数sockfd:正在监听端口的套接口文件描述符,通过socket获得
第二个参数buf:接收缓冲区,往往是使用者定义的数组,该数组装有接收到的数据
第三个参数len:接收缓冲区的大小,单位是字节
第四个参数flags:填0即可
第五个参数src_addr:指向发送数据的主机地址信息的结构体,也就是我们可以从该参数获取到数据是谁发出的
第六个参数addrlen:表示第五个参数所指向内容的长度
返回值:成功:返回接收成功的数据长度
失败: -1

(2)sendto

#include <sys/types.h>
#include <sys/socket.h>
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
              const struct sockaddr *dest_addr, socklen_t addrlen);

第一个参数sockfd:正在监听端口的套接口文件描述符,通过socket获得
第二个参数buf:发送缓冲区,往往是使用者定义的数组,该数组装有要发送的数据
第三个参数len:发送缓冲区的大小,单位是字节
第四个参数flags:填0即可
第五个参数dest_addr:指向接收数据的主机地址信息的结构体,也就是该参数指定数据要发送到哪个主机哪个进程
第六个参数addrlen:表示第五个参数所指向内容的长度
返回值:成功:返回发送成功的数据长度
失败: -1

服务端:

 1 #include <stdio.h>
 2 #include <sys/types.h>
 3 #include <sys/socket.h>
 4 #include <netinet/in.h>
 5 #include <string.h>
 6 
 7 #define SERVER_PORT 8888
 8 #define BUFF_LEN 1024
 9 
10 void handle_udp_msg(int fd)
11 {
12     char buf[BUFF_LEN];  //接收缓冲区,1024字节
13     socklen_t len;
14     int count;
15     struct sockaddr_in clent_addr;  //clent_addr用于记录发送方的地址信息
16     while(1)
17     {
18         memset(buf, 0, BUFF_LEN);
19         len = sizeof(clent_addr);
20         count = recvfrom(fd, buf, BUFF_LEN, 0, (struct sockaddr*)&clent_addr, &len);  //recvfrom是拥塞函数,没有数据就一直拥塞
21         if(count == -1)
22         {
23             printf("recieve data fail!\n");
24             return;
25         }
26         printf("client:%s\n",buf);  //打印client发过来的信息
27         memset(buf, 0, BUFF_LEN);
28         sprintf(buf, "I have recieved %d bytes data!\n", count);  //回复client
29         printf("server:%s\n",buf);  //打印自己发送的信息给
30         sendto(fd, buf, BUFF_LEN, 0, (struct sockaddr*)&clent_addr, len);  //发送信息给client,注意使用了clent_addr结构体指针
31 
32     }
33 }
34 
35 
36 /*
37     server:
38             socket-->bind-->recvfrom-->sendto-->close
39 */
40 
41 int main(int argc, char* argv[])
42 {
43     int server_fd, ret;
44     struct sockaddr_in ser_addr; 
45 
46     server_fd = socket(AF_INET, SOCK_DGRAM, 0); //AF_INET:IPV4;SOCK_DGRAM:UDP
47     if(server_fd < 0)
48     {
49         printf("create socket fail!\n");
50         return -1;
51     }
52 
53     memset(&ser_addr, 0, sizeof(ser_addr));
54     ser_addr.sin_family = AF_INET;
55     ser_addr.sin_addr.s_addr = htonl(INADDR_ANY); //IP地址,需要进行网络序转换,INADDR_ANY:本地地址
56     ser_addr.sin_port = htons(SERVER_PORT);  //端口号,需要网络序转换
57 
58     ret = bind(server_fd, (struct sockaddr*)&ser_addr, sizeof(ser_addr));
59     if(ret < 0)
60     {
61         printf("socket bind fail!\n");
62         return -1;
63     }
64 
65     handle_udp_msg(server_fd);   //处理接收到的数据
66 
67     close(server_fd);
68     return 0;
69 } 

客户端:

1 #include <stdio.h>
 2 #include <sys/types.h>
 3 #include <sys/socket.h>
 4 #include <netinet/in.h>
 5 #include <string.h>
 6 
 7 #define SERVER_PORT 8888
 8 #define BUFF_LEN 512
 9 #define SERVER_IP "172.0.5.182"
10 
11 
12 void udp_msg_sender(int fd, struct sockaddr* dst)
13 {
14 
15     socklen_t len;
16     struct sockaddr_in src;
17     while(1)
18     {
19         char buf[BUFF_LEN] = "TEST UDP MSG!\n";
20         len = sizeof(*dst);
21         printf("client:%s\n",buf);  //打印自己发送的信息
22         sendto(fd, buf, BUFF_LEN, 0, dst, len);
23         memset(buf, 0, BUFF_LEN);
24         recvfrom(fd, buf, BUFF_LEN, 0, (struct sockaddr*)&src, &len);  //接收来自server的信息
25         printf("server:%s\n",buf);
26         sleep(1);  //一秒发送一次消息
27     }
28 }
29 
30 /*
31     client:
32             socket-->sendto-->revcfrom-->close
33 */
34 
35 int main(int argc, char* argv[])
36 {
37     int client_fd;
38     struct sockaddr_in ser_addr;
39 
40     client_fd = socket(AF_INET, SOCK_DGRAM, 0);
41     if(client_fd < 0)
42     {
43         printf("create socket fail!\n");
44         return -1;
45     }
46 
47     memset(&ser_addr, 0, sizeof(ser_addr));
48     ser_addr.sin_family = AF_INET;
49     //ser_addr.sin_addr.s_addr = inet_addr(SERVER_IP);
50     ser_addr.sin_addr.s_addr = htonl(INADDR_ANY);  //注意网络序转换
51     ser_addr.sin_port = htons(SERVER_PORT);  //注意网络序转换
52 
53     udp_msg_sender(client_fd, (struct sockaddr*)&ser_addr);
54 
55     close(client_fd);
56 
57     return 0;
58 }

单播、多播、广播

https://www.cnblogs.com/jingliming/p/4477264.html

使用UDP协议进行信息的传输之前不需要建议连接。换句话说就是客户端向服务器发送信息,客户端只需要给出服务器的ip地址和端口号,然后将信息封装到一个待发送的报文中并且发送出去。至于服务器端是否存在,或者能否收到该报文,客户端根本不用管。

单播用于两个主机之间的端对端通信,广播用于一个主机对整个局域网上所有主机上的数据通信。单播和广播是两个极端,要么对一个主机进行通信,要么对整个局域网上的主机进行通信。实际情况下,经常需要对一组特定的主机进行通信,而不是整个局域网上的所有主机,这就是多播的用途。

1. 广播

广播UDP与单播UDP的区别就是IP地址不同,广播使用广播地址255.255.255.255,将消息发送到在同一广播网络上的每个主机。值得强调的是:本地广播信息是不会被路由器转发。当然这是十分容易理解的,因为如果路由器转发了广播信息,那么势必会引起网络瘫痪。这也是为什么IP协议的设计者故意没有定义互联网范围的广播机制。 但是广播还是要指明接收者的端口号的

服务端:

 1 #include<iostream>
 2 #include<stdio.h>
 3 #include<sys/socket.h>
 4 #include<unistd.h>
 5 #include<sys/types.h>
 6 #include<netdb.h>
 7 #include<netinet/in.h>
 8 #include<arpa/inet.h>
 9 #include<string.h>
10 using namespace std;
11 int main()
12 {
13     setvbuf(stdout,NULL,_IONBF,0);
14     fflush(stdout);
15     int sock=-1;
16     if((sock=socket(AF_INET,SOCK_DGRAM,0))==-1)
17     {
18         cout<<"sock error"<<endl;
19         return -1;
20     }
21     const int opt=-1;
22     int nb=0;
23     nb=setsockopt(sock,SOL_SOCKET,SO_BROADCAST,(char*)&opt,sizeof(opt));//设置套接字类型
24     if(nb==-1)
25     {
26         cout<<"set socket error...\n"<<endl;
27         return -1;
28     }
29     struct sockaddr_in addrto;
30     bzero(&addrto,sizeof(struct sockaddr_in));
31     addrto.sin_family=AF_INET;
32     addrto.sin_addr.s_addr=htonl(INADDR_BROADCAST);//套接字地址为广播地址
33     addrto.sin_port=htons(6000);//套接字广播端口号为6000
34     int nlen=sizeof(addrto);
35     while(1)
36     {
37         sleep(1);
38         char msg[]={"the message broadcast"};
39         int ret=sendto(sock,msg,strlen(msg),0,(sockaddr*)&addrto,nlen);//向广播地址发布消息
40         if(ret<0)
41         {
42             cout<<"send error...\n"<<endl;
43             return -1;
44         }
45         else 
46         {
47             printf("ok\n");
48         }
49     }
50     return 0;
51 }

广播和单播的处理过程是不同的,单播的数据只是收发数据的特定主机进行处理,而广播的数据整个局域网都进行处理

在这里插入图片描述
单播流程:主机A向主机B发送UDP数据报,发送的目的IP为192.168.1.151,端口为 80,目的MAC地址为00:00:00:00:00:02。此数据经过UDP层、IP层,到达数据链路层,数据在整个以太网上传播,在此层中其他主机会 判断目的MAC地址。主机C的MAC地址为00:00:00:00:00:03,与目的MAC地址00:00:00:00:00:02不匹配,数据链路层 不会进行处理,直接丢弃此数据。

主机B的MAC地址为00:00:00:00:00:02,与目的MAC地址00:00:00:00:00:02一致,此数据会经过IP层、UDP层,到达接收数据的应用程序。

广播的流程:主机A向整个网络发送广播数据,发送的目的IP为192.168.1.255,端口为 80,目的MAC地址为FF:FF:FF:FF:FF:FF。此数据经过UDP层、IP层,到达数据链路层,数据在整个以太网上传播,在此层中其他主机会 判断目的MAC地址。由于目的MAC地址为FF:FF:FF:FF:FF:FF,主机C和主机B会忽略MAC地址的比较(当然,如果协议栈不支持广播,则 仍然比较MAC地址),处理接收到的数据。

主机B和主机C的处理过程一致,此数据会经过IP层、UDP层,到达接收数据的应用程序。

2. 多播

在广域网上广播的时候,其中的交换机和路由器只向需要获取数据的主机复制并转发数据主机可以向路由器请求加入或退出某个组,网络中的路由器和交换机有选择地复制并传输数据,将数据仅仅传输给组内的主机。多播的这种功能,可以一次将数据发送到多个主机,又能保证不影响其他不需要(未加入组)的主机的其他通 信。

相对于传统的一对一的单播,多播具有如下的优点:

1、具有同种业务的主机加入同一数据流,共享同一通道,节省了带宽和服务器的优点,具有广播的优点而又没有广播所需要的带宽。

2、服务器的总带宽不受客户端带宽的限制。由于组播协议由接收者的需求来确定是否进行数据流的转发,所以服务器端的带宽是常量,与客户端的数量无关。

3、与单播一样,多播是允许在广域网即Internet上进行传输的,而广播仅仅在同一局域网上才能进行

组播的缺点:

1、多播与单播相比没有纠错机制,当发生错误的时候难以弥补,但是可以在应用层来实现此种功能。

2、多播的网络支持存在缺陷,需要路由器及网络协议栈的支持。

3、多播的应用主要有网上视频、网上会议等。

多播的地址是特定的,D类地址用于多播。D类IP地址就是多播IP地址,即224.0.0.0至239.255.255.255之间的IP地址,并被划分为局部连接多播地址、预留多播地址和管理权限多播地址3类:

1、局部多播地址:在224.0.0.0~224.0.0.255之间,这是为路由协议和其他用途保留的地址,路由器并不转发属于此范围的IP包。

2、预留多播地址:在224.0.1.0~238.255.255.255之间,可用于全球范围(如Internet)或网络协议。

3、管理权限多播地址:在239.0.0.0~239.255.255.255之间,可供组织内部使用,类似于私有IP地址,不能用于Internet,可限制多播范围。
  
多播的程序设计使用setsockopt()函数和getsockopt()函数来实现,组播的选项是IP层的,其选项值和含义参见11.5所示。

(1)建立一个socket。

(2)然后设置多播的参数,例如超时时间TTL、本地回环许可LOOP等。

(3)加入多播组。

(4)发送和接收数据。

(5)从多播组离开。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值