UDP简介:

UDP是一种无连接的传输协议,他提供一种简单,不可靠的数据传输服务。因为该协议不面向连接,且不可靠,所以适用于一次传递少量数据,不适用于大量数据传输。

UDP属于网络协议的传输层,直接负责数据的传输和接收。

UDP协议特点:

一.无连接:

两台主机使用UDP进行通信的时候,不需要建立连接,只需要知道对端的IP和端口就可以把数据发送给对端主机。

二.不可靠

1.UDP协议没有向TCP那些机制,可以保证数据一定可以传输给对端,如果因为一些事故导致没有将消息成功发送给对端主机,比如说网络故障,或者对端的接收缓冲区已经打满,都可以导致消息发送失败,那丢失的这条消息只能是丢了,没有重传机制。

2.对端的接受顺序是不可靠的,不会因为你先发送,这条消息就先到,这个和网购很像,不会因为你先下单这个物件一定就是先到的,因为每个消息走的路线可能都是不一样的,锁已无法向TCP那样保证消息的有序性。

三.面向数据报

UDP在传输数据时,是以数据报的方式传递过去的,不是向TCP那样以字节流的方式传递过去的,二者的区别就是,面向数据报的话,应用层发送了多少次消息,那么就将每条消息都封装成数据报发送给对端,面向字节流则不然,而是把消息发送金发送端的发送缓冲区当中,等封装成报文的时候,则是能带多少数据由TCP决定,可能你上端发送了十次消息,每次10字节,那么这100字节都停留在发送缓冲区当中,可能TCP封装一次报文就将这些数据全部发送给对端,但是UDP的话一定要封装十次才可以。


UDP报文格式

UDP协议栈属于内核协议栈,而内核是用C语言写的,在底层UDP的报头是一个位段类型的结构体。

struct udp_header
{
    //16位源端口号
    unsigned int src_port:16;
    //16位目的端口号
    unsigned int des_port:16;
    //16位UDP长度
    unsigned int udp_len:16;
    //16位UDP校验和
    unsigned int udp_cheack:16;
}
UDP缓冲区
  • UDP没有真正意义上的发送缓冲区。调用sendto会直接把数据交给内核,经过简单包装后,将内容传给网络协议层。
  • UDP具有接收缓冲区。
  1. 这个接收缓冲区不能保证收到的·UDP报文和发送时得UDP报文顺序是一致的。因为它们走的路径不一样,最终可能导致到达终点的顺序不一样。
  2. 这个接收缓冲区,也无法保证收到的内容等于发送的内容,可能你这个发送缓冲区满了,就会丢弃新发送过来的报文,或中间网络出现问题,导致数据发送失败,都可能导致接收缓冲区接收数据失败。

基于UDP实现的用户层协议

  • NFS:网络文件系统
  • TFTP:简单文件传输协议
  • DHCP:动态主机配置协议
  • BOOTP:启动协议(用于无盘设备启动)
  • DNS:域名解析协议
UDP报文各个字段
1.源端口号和目的端口号

1.1认识端口号

  • IP:32位无符号整数,用来标识公网中唯一一台主机。
  • 端口号:16位无符号整型,标识了主机中唯一一个进程。

在TCP/IP协议中,用源IP,目的IP,源端口号,目的端口号,协议号这样的五元组来标识一个通信。

补充知识:netstat命令介绍

语法:netstat [选项]

常用选项:

  • n拒绝显示别名,能显示数字的全部以数字形式展现出来。
  • l仅列出服务状态位Listen的进程。
  • p显示网络连接 / 端口对应的 PID(进程 ID) 和 进程名称。
  • t仅tcp相关选项。
  • u仅udp相关选项。
  • a显示所有选项,默认不显示Liten相关选项。

问1:端口号和进程的关系?

一个进程可以对应多个端口号。

一个端口号只能对应一个进程。

问2:为什么要这样?

因为这样可以通过端口号找到唯一的进程。

1.2端口号的范围划分

端口号一共有2^16 = 65536个,其中前面的端口号被分配给一些常用的协议。

  • 知名端口号(0~1023):HTTP,FTP,SS等这些广为使用的应用层协议,它们的端口号一般都是固定的。
  • 其它端口号(1024~65535):这个范围端口号是我们在使用时动态分配的

查看知名端口对应的服务的命令:

less/ etc/ services

1.3UDP中端口号的字段作用

  • 源端口号:将自己端口号封装进去,用来告诉接收端,是哪个进程给它发送的信息,这样可以实现全双工通信。
  • 目的端口号:可以通过该端口号确定将消息发送给哪个进程

问:UDP怎么实现报头和有效载荷分离的?

定长报头+自描述字段,16位UDP长度是总长度,而UDP报头长度是固定的8字节,所以总长度减去8字节剩余的就是数据大小。

2.UDP长度

UDP协议中包头中有一个内容为16位最大长度字段,该字段记录了UDP报文的总长度,也就是64K大小,在当今互联网时代,64K算得上是一个很小的数字。如果我们需要传递大于64K的数字需要在应用层手动分包,然后当接收端收到后手动合包。

3.UDP校验和

该校验和可以保证接收端接收到的数据一定是准确的,没有经过更改的,可以传输过来的顺序是不可靠的,传不传输成功也都是无所谓的,但是传输过来的内容一定是准确的,没有被更改的。因为报文在进行网络传输时,会经过各种传输线,路由器,信号放大器等传输介质,且随着网络状况不同,每个包的具体选择路径是不一样的。在网络传输中,受到外界的干扰,数据可能出错,比如某几位位置0变1,1变0,所以就需要在接收到数据之后需要校验一下,以保证接收到的数据的准确性。

UDP协议在网络传输中的使用案例
class Sockaddr_In
{
private:
    struct sockaddr_in local;
    socklen_t len;
public:
    Sockaddr_In(int port)
    {
        local.sin_family = AF_INET;
        //转换成大端字节序
        local.sin_port(htons(port));
        local.sin_addr_s_addr = INADDR_ANY;
    }
    struct sockaddr* Get_Sockaddr_In()
    {
        return &local;
    }
    socklen_t Get_Len()
    {
        return sizeof(local);
    }
};
class Udp_Server
{
private:
    int serverfd_;
    int serverport_;
    Sockaddr_In* local;
public:
    Udp_Server(std::string serverport)
        :serverip_(serverip),serverport_(atoi(srevrport))
    {
        Sockaddr_In local = new Sockaddr_In(sreverport_);    
        serverfd_ = socket(AF_INET,SOCK_STREAM,0);
        int ret = bind(serverfd_,local.Get_Sockaddr_In(),local.Get_Len());
    }
    void Sendto(std::string content)
    { 
        int n =  sendto(serverfd_,content.c_str(),content.size(),local->Get_Sockaddr_In(),local->Get_Len());
        if(n > 0)
            //...发送成功
        else
            //发送失败
            exit(1);
    }
    void RecvFrom(char* buffer,int sz)
    {
       int n = recvfrom(serverfd_,buffer,sz,local->Get_Sockaddr_In(),local->Get_Len());
         if(n > 0)
            //...读取成功
         else
            //读取失败
            exit(1);
    }
};
int main(int argc,char* argv)
{
    if(argc < 2)
    {
        std::cout<<"man ip port"<<std::endl;
        return 0; 
    }
    Udp_Server server(argv[1]);
    char buffer[1024];
    srever.RecvFrom(buffer,sizeof(buffer)-1);
    //将内容传递给上层,并进行解析
    //把上层处理好的内容发送出去
    std::string content;
    srever.Sendto(content);
    return 0;
}

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐