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