UDP简单介绍
传输层主要应用的协议模型有两种,一种是TCP协议,另外一种则是UDP协议。TCP协议在网络通信中占主导地位,绝大多数的网络通信借助TCP协议完成数据传输。但UDP也是网络通信中不可或缺的重要通信手段。
相较于TCP而言,UDP通信的形式更像是发短信。不需要在数据传输之前建立、维护连接。只专心获取数据就好。省去了三次握手的过程,通信速度可以大大提高,但与之伴随的通信的稳定性和正确率便得不到保证。因此,我们称UDP为“无连接的不可靠报文传递”。
那么与我们熟知的TCP相比,UDP有哪些优点和不足呢?由于无需创建连接,所以UDP开销较小,数据传输速度快,实时性较强。多用于对实时性要求较高的通信场合,如视频会议、电话会议等。但随之也伴随着数据传输不可靠,传输数据的正确率、传输顺序和流量都得不到控制和保证。所以,通常情况下,使用UDP协议进行数据传输,为保证数据的正确性,我们需要在应用层添加辅助校验协议来弥补UDP的不足,以达到数据可靠传输的目的。
如下图所示,简单的UDP的CS模型通信过程,由于UDP不需要维护连接,程序逻辑简单了很多,但是UDP协议是不可靠的,保证通讯可靠性的机制需要在应用层实现。
代码实现:
server.c
1 #include<stdio.h> 2 #include<unistd.h> 3 #include<stdlib.h> 4 #include<sys/socket.h> 5 #include<string.h> 6 #include<arpa/inet.h> 7 #include<ctype.h> 8 9 #define SERVER_PORT 8000 10 11 int main(int agrc,char* argv[]) 12 { 13 int sockfd; 14 struct sockaddr_in servaddr,clieaddr; 15 socklen_t clieaddr_len; 16 char buf[BUFSIZ]; 17 char str[INET_ADDRSTRLEN]; 18 int i,n; 19 20 sockfd=socket(AF_INET,SOCK_DGRAM,0); 21 bzero(&servaddr,sizeof(servaddr)); 22 servaddr.sin_family=AF_INET; 23 servaddr.sin_addr.s_addr=htonl(INADDR_ANY); 24 servaddr.sin_port=htons(SERVER_PORT); 25 26 bind(sockfd,(struct sockaddr*)&servaddr,sizeof(servaddr)); 27 28 printf("Acceptint Connections ...\n"); 29 while(1) 30 { 31 clieaddr_len=sizeof(clieaddr); 32 n=recvfrom(sockfd,buf,BUFSIZ,0,(struct sockaddr*)&clieaddr,&clieaddr_len); 33 if(n==-1) 34 { 35 perror("recvfrom error"); 36 } 37 printf("received from %s at PORT %d\n",inet_ntop(AF_INET,&clieaddr.sin_addr,str,sizeof(str)),ntohs(clieaddr.sin_port)); 38 for(i=0;i<n;i++) 39 { 40 buf[i]=toupper(buf[i]); 41 } 42 n=sendto(sockfd,buf,n,0,(struct sockaddr*)&clieaddr,sizeof(clieaddr)); 43 if(n==-1) 44 { 45 perror("sendto error"); 46 } 47 } 48 close(sockfd); 49 50 return 0; 51 }
client.c
1 #include<stdio.h> 2 #include<string.h> 3 #include<unistd.h> 4 #include<arpa/inet.h> 5 #include<ctype.h> 6 7 #define SERVER_PORT 8000 8 9 int main(int argc,char* argv[]) 10 { 11 struct sockaddr_in servaddr; 12 int sockfd,n; 13 char buf[BUFSIZ]; 14 15 sockfd = socket(AF_INET,SOCK_DGRAM,0); 16 17 bzero(&servaddr,sizeof(servaddr)); 18 servaddr.sin_family = AF_INET; 19 inet_pton(AF_INET,"0.0.0.0",&servaddr.sin_addr); 20 servaddr.sin_port = htons(SERVER_PORT); 21 22 bind(sockfd,(struct sockaddr*)&servaddr,sizeof(servaddr)); 23 24 while(fgets(buf,BUFSIZ,stdin)!= NULL) 25 { 26 n = sendto(sockfd,buf,strlen(buf),0,(struct sockaddr*)&servaddr,sizeof(servaddr)); 27 if(n == -1) 28 { 29 perror("sendto error"); 30 //printf("*********************\n"); 31 } 32 n = recvfrom(sockfd,buf,BUFSIZ,0,NULL,0);//NULL:不关心对端信息 33 if(n == -1) 34 { 35 perror("recvfrom error"); 36 } 37 write(STDOUT_FILENO,buf,n); 38 } 39 close(sockfd); 40 return 0; 41 }
测试结果:
1.首先启动服务端程序
2.再启动客户端程序
3.在客户端输入一个字符串回车
4.在客户端可以看到服务端转换的大写字符串回写到客户端屏幕
5.服务端可以看到客户端连接的信息(IP和端口号)