在前两次主要讲述了关于TCP的相关内容,那么在运输层还有一个重要的协议叫做UDP协议。本篇主要来讲解有关于UDP的相关内容。UDP的三个特点是:无连接,不可靠的数据报服务;
一、UDP协议报文段的首部格式
用户数据报UDP有两个字段,数据字段和首部字段。首部格式如下图所示,比较简单,只有8个字节,由四个字段组成,每个字段的长度都是两个字节。各个字段的含义如下:
源端口号:在需要对方回信时选用,不需要时可全用0;
目的端口号:这在终点交付报文时必须使用;
报文段长度:UDP用户数据报的长度,其最小值为8.
校验和:检测UDP报文段在传输中是否出错,出错就舍弃;
二、UDP的主要特点
无连接不可靠,即就是UDP尽最大努力交付;数据报UDP没有拥塞控制;UDP支持一对一,一对多,多对一和多对多的交互通讯UDP的首部开销小;
三、分别介绍UDP的三个特点:无连接的不可靠的数据报服务;
无连接的:利用UDP进行通讯时,不需要先进行两端的连接。
不可靠的:UDP是尽最大努力进行数据交付,即不保证可靠的交付。
UDP的数据报服务:
发送的次数和接收的次数相等;
如果接收一次未将数据读取完,则剩余的丢弃
四、UDP通讯的编程流程——以客户端服务器为例
(一)服务器:被动通讯方
Int sockfd = socket(int domain,int type,int protocol);//创建socket
Int Bind(int sockerfd, const struct sockaddr *addr, socklen_t addrlen);//将服务器的IP地址、端口号与sockfd绑定;
Int recvfrom(int sockfd, void *buff, int len, int flags, struct sockaddr* destaddr, addrlen_t* len);//必须接受对端地址
int sendto(int sockfd,void *buff,int len,int flags,struct sockaddr* peeraddr,addrlen_t len);
Close(sockfd);//直接关闭服务器
(二)客户端:主动通讯方
Int sockfd = socket(int domain,int type,int protocol);//创建socket
(可选)Int Bind(int sockerfd, const struct sockaddr *addr, socklen_t addrlen);//将服务器的IP地址、端口号与sockfd绑定;
int sendto(int sockfd,void *buff,int len,int flags,struct sockaddr* peeraddr,addrlen_t len);
Int recvfrom(int sockfd, void *buff, int len, int flags, struct sockaddr* destaddr, addrlen_t* len);//可以不接收对端信息
Close(sockfd );//直接关闭客户端
(三)简单代码实现
/*
服务器端
*/
#include<stdio.h>
#include<string.h>
#include<assert.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>
int main()
{
int sockfd = socket(AF_INET,SOCK_DGRAM,0);
assert(sockfd != -1);
//绑定
struct sockaddr_in ser,cli;
memset(&ser,0,sizeof(ser));
ser.sin_family = AF_INET;
ser.sin_addr.s_addr = inet_addr("127.0.0.1");
ser.sin_port = htons(6500);
int res = bind(sockfd,(struct sockaddr*)&ser,sizeof(ser));
assert(res != -1);
while(1)
{
char buff[128] = {0};
int cli_len = sizeof(cli);
int n = recvfrom(sockfd,buff,127,0,(struct sockaddr*) &cli,&cli_len);
if(n == -1)
{
close(sockfd);
break;
}
unsigned short cli_port = ntohs(cli.sin_port);
char *cli_ip = inet_ntoa(cli.sin_addr);
printf("%s:%u %s\n",cli_ip,cli_port,buff);
sendto(sockfd,"ok",2,0,(struct sockaddr*)&cli,sizeof(cli));
}
close(sockfd);
}
/*
客户端代码
*/
#include<stdio.h>
#include<assert.h>
#include<string.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>
int main()
{
int sockfd = socket(AF_INET,SOCK_DGRAM,0);
assert(sockfd != -1);
struct sockaddr_in ser,cli;
memset(&ser,0,sizeof(ser));
ser.sin_family = AF_INET;
ser.sin_port = htons(6500);
ser.sin_addr.s_addr = inet_addr("127.0.0.1");
while(1)
{
printf("please input data:");
char buff[128] = {0};
fgets(buff,128,stdin);
if(strncmp(buff,"end",3) == 0)
{
close(sockfd);
break;
}
buff[strlen(buff) - 1] = 0;
sendto(sockfd,buff,strlen(buff),0,(struct sockaddr*)&ser, sizeof(ser));
char recvbuff[128] = {0};
int n = recvfrom(sockfd,recvbuff,127,0,NULL,NULL);
if(n == -1)
{
close(sockfd);
break;
}
printf("clien recvfrom data:%s\n",recvbuff);
}
}
实现结果:
两端简单的通讯。