前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >【Linux网络编程】传输协议UDP

【Linux网络编程】传输协议UDP

作者头像
南桥
发布2024-12-14 09:02:36
发布2024-12-14 09:02:36
12300
代码可运行
举报
文章被收录于专栏:南桥谈编程南桥谈编程
运行总次数:0
代码可运行

再谈端口号

端口号标识了一个主机上进行通信的不同的应用程序

TCP/IP 协议中,使用 五元组 (5-tuple) 来唯一标识一条网络通信。这个五元组包含以下五个信息元素:

  1. 源 IP 地址:发送方设备的 IP 地址,用于标识通信的源。
  2. 源端口号:发送方应用程序的端口号,标识发送方在其设备上的具体应用进程。
  3. 目的 IP 地址:接收方设备的 IP 地址,用于标识通信的目标。
  4. 目的端口号:接收方应用程序的端口号,标识接收方设备上的具体应用进程。
  5. 协议号:用于标识协议类型的字段,通常用于区分不同的传输层协议。例如,TCP 使用协议号 6,UDP 使用协议号 17。

可以通过netstat -nltp查看:

端口号的范围划分

  • 0 - 1023: 知名端口号, HTTP, FTP, SSH 等这些广为使用的应用层协议, 他们的端口号都是固定的
  • 1024 - 65535: 操作系统动态分配的端口号. 客户端程序的端口号, 就是由操作系统从这个范围分配的

知名端口号

  • ssh 服务器, 使用 22 端口
  • ftp 服务器, 使用 21 端口
  • telnet 服务器, 使用 23 端口
  • http 服务器, 使用 80 端口
  • https 服务器, 使用 443

在Linux系统中,可通过vim /etc/services来查看知名端口号:

一个进程是否能绑定多个端口号?

可以。以TCP为例,可以创建多个listen套接字,用的是不同的端口号。一个服务器可以创建两个端口号,一个进行发送数据,另一个进行发送控制命令。

一个端口号是否可以被多个进程绑定?

原则上不可以。需要保证端口号与服务之间的唯一性。

理解端口号和进程的关系

进程在Linux内核中实际上是一个struct task_struct,这就是描述进程的一个结构体。操作系统内部维护了一张哈希表,哈希表对应的key对应端口号,value对应进程PCB的地址。在进行bind绑定的时候是将进程PCB地址与哈希表的key端口号进程绑定,换言之,所谓的绑定就是将PCB地址和端口号构建在哈希表中。底层收到数据,读取到目的端口号就可以找到对应的进程,就可以将数据交给这个进程。因此一个端口号只能被一个进程绑定,需要保持key值唯一。

UDP协议

UDP协议格式

UDP报头一定是一个结构体

16 位 UDP 长度, 表示整个数据报(UDP 首部+UDP 数据)的最大长度

UDP特点

  • 无连接: 知道对端的 IP 和端口号就直接进行传输, 不需要建立连接;
  • 不可靠: 没有确认机制, 没有重传机制; 如果因为网络故障该段无法发到对方,UDP 协议层也不会给应用层返回任何错误信息;
  • 面向数据报: 不能够灵活的控制读写数据的次数和数量;

面向数据报

应用层交给 UDP 多长的报文, UDP 原样发送, 既不会拆分, 也不会合并

UDP缓冲区

  • UDP 没有真正意义上的 发送缓冲区. 调用 sendto 会直接交给内核, 由内核将数据传给网络层协议进行后续的传输动作;
  • UDP 具有接收缓冲区. 但是这个接收缓冲区不能保证收到的 UDP 报的顺序和发送 UDP 报的顺序一致; 如果缓冲区满了, 再到达的 UDP 数据就会被丢弃

UDP不需要可靠性保证,不需要丢包重传,只需要添加报头,UDP的报头很简单只有8个字节,添加报头后直接发送,因此不需要放在发送缓冲区保存起来。

虽然UDP不需要保证可靠性,但是起码需要保证报文不会大面积丢失,因此提供一个接收缓冲区,当上层正在读取UDP报文,操作系统可以继续接收UDP数据,这样也会在一定程度提高效率。接收缓冲区一旦写满了,这样再接收到的数据就会丢失。

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

使用注意事项

UDP 协议首部中有一个 16 位的最大长度. 也就是说一个 UDP 能传输的数据最大长度是 64K(包含 UDP 首部)。如果我们需要传输的数据超过 64K, 就需要在应用层手动的分包, 多次发送, 并在接收端手动拼装。

基于UDP的应用层协议

  • NFS: 网络文件系统
  • TFTP: 简单文件传输协议
  • DHCP: 动态主机配置协议
  • BOOTP: 启动协议(用于无盘设备启动)
  • DNS: 域名解析协议

进一步理解UDP报头

UDP报头实际上也是一个结构体,它的具体内容如下:

代码语言:javascript
代码运行次数:0
复制
struct udphdr {
    __be16 source;      // 源端口号
    __be16 dest;        // 目标端口号
    __be16 len;         // UDP 数据长度(包括头部和数据部分)
    __be16 check;       // 校验和(UDP 校验和)
};

当我们需要拿到对应成员的数据时,使用二进制格式进行序列化即可,struct udphdr* h指向对应的成员。

进一步理解报文

在接收方或者发送方,通信双方的操作系统内会同时存在很多报文,要么向上交付,要么向下交付,UDP报文会接受很多数据。在进行通信时,需要对报文进行管理,先描述,再组织

描述报文的结构体为struct sk_buff,内部有数据包的头信息、数据、缓冲区等。将应用层数据拷贝到缓冲区实际上是将应用层数据拷贝到缓冲区,此时有了数据。

代码语言:javascript
代码运行次数:0
复制
struct sk_buff {
    struct sk_buff *next;            // 指向下一个 sk_buff(链表结构)
    struct sk_buff *prev;            // 指向上一个 sk_buff(链表结构)

    struct net_device *dev;          // 网络设备(接口),即接收数据包的网卡

    unsigned int len;                // 数据包的长度
    unsigned int data_len;           // 有效数据的长度(不包括协议头)

    unsigned char *data;             // 指向数据区的指针(即数据包的负载部分)
    unsigned char *head;             // 数据包的开始地址(头部)

    unsigned char *tail;             // 数据包的尾部(通常指向空闲区域的结束)
    unsigned char *end;              // 数据包的结束地址(缓冲区末尾)

    unsigned int truesize;           // sk_buff 的实际大小(包括头部、数据区和尾部)

    struct sk_buff *next_free;       // 用于内核的 sk_buff 内存池中的链表

    struct sock *sk;                // 套接字结构体(用于连接和数据传输)
    unsigned int protocol;           // 数据包的协议类型(如 IPv4、IPv6、ARP 等)
    __be16 transport_header;        // 运输层协议头部位置(如 UDP、TCP)
    __be16 network_header;          // 网络层协议头部位置(如 IP)
    __be16 mac_header;              // 链路层协议头部位置(如以太网)

    // 更多字段和标志用于特定功能(例如 QoS、优先级、标记等)
};

然后添加UDP报头:

代码语言:javascript
代码运行次数:0
复制
struct sk_buff bufffer;
(struct udphdr*) buffer->head-=sizeof(struct udphdr);
buffer->head->source=12345;
buffer->head->dest=8888;
buffer->head->len=100;
buffer->head->check=Check();

后续需要再添加报文时,head就继续往前移动即可。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-12-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 再谈端口号
    • 端口号的范围划分
    • 知名端口号
    • 一个进程是否能绑定多个端口号?
    • 一个端口号是否可以被多个进程绑定?
    • 理解端口号和进程的关系
  • UDP协议
    • UDP协议格式
    • UDP特点
    • 面向数据报
    • UDP缓冲区
    • 使用注意事项
    • 基于UDP的应用层协议
    • 进一步理解UDP报头
    • 进一步理解报文
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档