网络基础:浅析UDP协议

UDP协议端格式

这里写图片描述
其中16为UDP长度表示为整个数据报(UDP报头信息+UDP数据)的最大长度,那么也就是说UDP发送的数据最大不能超过64K(包括UDP报头信息)由于64K在当今的互联网下是非常非常小的数字,所以当我们要传输的数据超过64K时,就需要在应用层手动的分包,多次发送,并且在接收端手动的拼装。其中UDP检验和是为了校验数据的对错的,如果错误,直接丢弃,并不会重传。

UDP特点

UDP传输的过程是不需要连接的,也就是说客户端可以直接给服务器发送数据,并不需要创建链接,只需要知道目的主机IP地址与端口号即可发送。并且在发送数据的过程中,没有确认机制以及重传机制(确认机制就是目的主机收到源主机的信息时对其回复收到信息,这就是确认机制。重传机制就是在传输过程中,由于某些原因,导致丢失数据包,目的主机会对源主机进行反馈,然后重传丢失数据包)。如果因为某些故障原因导致数据没有发送到目的主机,UDP协议层并不会给应用层返回任何错误信息。UDP传输时,应用层交给它多长的报文数据,UDP原样发送,不会拆分与合并。
总结起来UDP的特点为:

  • 无连接
  • 不可靠
  • 面向数据包
  • 速度快

UDP接收报文

在使用UDP来传输时,如何接收的报文数据呢?我们知道,如果网络中有数据传输给该主机是由网卡驱动驱动网卡来获取数据,而当网卡缓冲区内部有数据时,操作系统如何获取呢?
这里是由中断的方式来让操作系统处理显卡缓冲区内部的数据。其中中断分为两个部分,中断为上部分比较简单,并且紧急,下半部分为处理。这里的紧急意思为优先级就较高,一般情况下,操作系统判断出显卡缓冲区内有数据时,便会将其数据加载至操作系统内核缓冲区。加载完毕后,不一定立即对其继续数据处理分析。当
积累的报文信息很多时,便对这些报文信息进行描述与组织,对其进行管理。

UDP具有接收缓冲区的,这个接收缓冲区不能保证收到的UDP报的顺序与发送UDP报的顺序一致。如果缓冲区满了,后面到达的数据就会被丢弃。

UDP的socket既能读,也能写,这个概念叫做全双工。

基于UDP的应用层的协议

  • NFS:网络文件系统
  • TFTP:简单文件的传输协议
  • DHCP:动态主机配置协议
  • BOOTP:启动协议
  • DNS:域名解析协议

实现简单的UDP服务器

服务器

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>

int main(int argc, char* argv[])
{
  if(argc != 3) { //判断命令行的合法性
    printf("usage %s [IP] [port]\n", argv[0]);
    return 1;
  }

  int sock = socket(AF_INET, SOCK_DGRAM, 0);//创建套接字
  if(sock < 0) {
    printf("socket error!\n");
    return 2;
  }

  //声明sockaddr_in结构体,并填充
  struct sockaddr_in local;
  local.sin_family = AF_INET;
  local.sin_port = htons(atoi(argv[2]));//转化端口号为网络字节格式
  //inet_addr返回的地址已经是网络字节格式
  //无需调用htonl转化为网络字节格式 
  local.sin_addr.s_addr = inet_addr(argv[1]);

  //绑定套接字
  if(bind(sock, (struct sockaddr*)&local, sizeof(local)) < 0) {
    printf("bind error!\n");
    return 3;
  }

  char buf[1024];
  struct sockaddr_in client;
  while(1) {
    socklen_t len = sizeof(client);
    buf[0] = 0;
    ssize_t s = recvfrom(sock, buf, sizeof(buf) - 1, 0, 
                         (struct sockaddr*)&client, &len);
    if(s > 0) {
      buf[s] = 0;
      printf("[%s|%d]:%s\n",inet_ntoa(client.sin_addr), ntohs(client.sin_port), buf);
      sendto(sock, buf, strlen(buf), 0, 
             (struct sockaddr*)&client, len);
    }
  }
  close(sock);

  return 0;
}

客户端

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>

int main(int argc, char* argv[])
{
  if(argc != 3) {
    printf("usage %s [IP] [port]\n", argv[0]);
    return 1;
  }

  int sock = socket(AF_INET, SOCK_DGRAM, 0);
  if(sock < 0) {
    printf("socket error!\n");
    return 2;
  }

  struct sockaddr_in server;
  server.sin_family = AF_INET;
  server.sin_port = htons(atoi(argv[2]));
  server.sin_addr.s_addr = inet_addr(argv[1]);

  char buf[1024];
  struct sockaddr_in peer;
  while(1) {
    socklen_t len = sizeof(peer);
    buf[0] = 0;
    printf("please enter#");
    fflush(stdout);
    ssize_t s = read(0, buf, sizeof(buf) - 1);
    if(s < 0) {
      printf("read error!\n");
      return 3;
    }
    buf[s-1] = 0;
    sendto(sock, buf, strlen(buf), 0, 
           (struct sockaddr*)&server, sizeof(server));
    s = recvfrom(sock, buf, sizeof(buf) - 1, 0, 
             (struct sockaddr*)&peer, &len);
    if(s < 0) {
      printf("recvfrom error!\n");
      return 4;
    }
    buf[s] = 0;
    printf("peer return %s\n", buf);
  }
  close(sock);

  return 0;
}

这里写图片描述
这里写图片描述


欢迎大家共同讨论,如有错误及时联系作者指出,并改正。谢谢大家!

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值