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)从多播组离开。