传输层协议UDP原理
端口号回顾
端口号的作用类似pid,用来标识进程的唯一性。只是为了与系统解耦,所以有了端口号。
通过ip来确定唯一主机,再通过端口号找到指定的进程。就可以让全网内唯一的两个进程通信了。
所以一个完整的报文至少要携带ip和端口号,ip是在网络层协议来维护的本章不做讲解,而端口号是在传输层协议中维护的,传输层协议常用的两种:UDP协议和TCP协议,本章将要讲解的是UDP协议,TCP协议在下一期进行讲解。
端口号:2字节(16个比特位)其中:
- 0 - 1023: 知名端口号, HTTP, FTP, SSH 等这些广为使用的应用层协议, 它们的端口号都是固定的。
- 1024 - 65535: 操作系统动态分配的端口号. 客户端程序的端口号, 就是由操作系统从这个范围分配的
认识知名端口号
有些服务器是非常常用的, 为了使用方便, 人们约定一些常用的服务器), 都是用以下这些
固定的端口号:
- ssh 服务器, 使用 22 端口
- ftp 服务器, 使用 21 端口
- telnet 服务器, 使用 23 端口
- http 服务器, 使用 80 端口
- https 服务器, 使用 443 端口
执行下面的命令, 可以看到知名端口号:
cat /etc/services
思考:
- 一个进程是否可以 bind 多个端口号?
- 一个端口号是否可以被多个进程 bind?
答1:一个进程是可以绑定多个端口号的,当一个进程提供多个不同服务时,就可以通过绑定多个端口来优化。只要一个端口能确定唯一进程就行。
答2:不能。要保证一个端口确定唯一进程。
UDP协议端格式
- 16位源端口和16位目的端口用来确定两个唯一进程,这没啥说的。
- 16位UDP长度:数据字段的大小不是固定的,所以该字段来表示整个数据报(UDP 首部+UDP 数据)的长度。
- 16位UDP检验和:不保证可靠性,校验和是唯一确定数据是否有效的机制。因为在数据传输过程中物理干扰、路由错误等可能导致数据损坏。
UDP协议特点
- 无连接: 知道对端的 IP 和端口号就直接进行传输, 不需要建立连接。
- 不可靠:报文发出去任务就完成了,报文是否丢失不关心。注意这不是缺点,是特点!
- 面向数据报:发10次,收10次。而TCP协议是面向字节流的,类似自来水。
- 缓冲区:UDP没有发送缓冲区,直接发(TCP有发送缓冲区是为了方便重传)。有接收缓冲区,出于效率考量,忙的时候,可以缓一缓。缓冲区满了就把报文丢弃。为全双工。
内核源码
UDP协议格式其实就是一个结构体,源码如下:
struct udphdr {unsigned shortsrc_port;unsigned shortdst_port;unsigned shortlen;unsigned shortchksum;};
在把数据交付给传输层时,数据在应用层必做序列化和反序列化。当然可直接用结构体变量代替,但非常不推荐(结构体存在内存对齐有内存浪费,与其他语言不兼容,需要考虑字节序问题等等)。
注:即使通信双方操作系统完全不同,但网络内核部分一定相同(所以能够通信)。操作系统内核都是使用c语言实现。
在OS内部一定会同时存在大量的报文,而这些报文可分布在各个协议层,OS必须管理这些报文。如果管理?先描述,再组织。如何描述:内核源码中结构体 struct sk_buff,如下:
struct sk_buff {struct sk_buff* next;/* Next buffer in list */struct sk_buff* prev;/* Previous buffer in list */struct sk_buff_head * list;/* List we are on*/#if CONFIG_SKB_CHECKintmagic_debug_cookie;#endifstruct sk_buff*link3;/* Link for IP protocol level buffer chains */struct sock*sk;/* Socket we are owned by */unsigned longwhen;/* used to compute rtt\'s*/struct timevalstamp;/* Time we arrived*/struct device*dev;/* Device we arrived on/are leaving by*/union {struct tcphdr*th;struct ethhdr*eth;struct iphdr*iph;struct udphdr*uh;unsigned char*raw;/* for passing file handles in a unix domain socket */void *filp;} h; union {/* As yet incomplete physical layer views */ unsigned char *raw; struct ethhdr*ethernet;} mac; struct iphdr*ip_hdr;/* For IPPROTO_RAW */unsigned long len;/* Length of actual data*/unsigned longcsum;/* Checksum */__u32saddr;/* IP source address*/__u32daddr;/* IP target address*/__u32raddr;/* IP next hop address*/__u32seq;/* TCP sequence number*/__u32end_seq;/* seq [+ fin] [+ syn] + datalen*/__u32ack_seq;/* TCP ack sequence number*/unsigned charproto_priv[16]; /* Protocol private data*/volatile char acked,/* Are we acked ?*/used,/* Are we in use ?*/free,/* How to free this buffer*/arp;/* Has IP/ARP resolution finished*/unsigned chartries,/* Times tried*/ lock,/* Are we locked ?*/ localroute,/* Local routing asserted for this frame*/ pkt_type,/* Packet class*/ pkt_bridged,/* Tracker for bridging */ ip_summed;/* Driver fed us an IP checksum*/#define PACKET_HOST0/* To us*/#define PACKET_BROADCAST1/* To all*/#define PACKET_MULTICAST2/* To group*/#define PACKET_OTHERHOST3/* To someone else */unsigned shortusers;/* User count - see datagram.c,tcp.c */unsigned shortprotocol;/* Packet protocol from driver. */unsigned shorttruesize;/* Buffer size */atomic_tcount;/* reference count*/struct sk_buff*data_skb;/* Link to the actual data skb*/unsigned char*head;/* Head of buffer */unsigned char*data;/* Data head pointer*/unsigned char*tail;/* Tail pointer*/unsigned char *end;/* End pointer*/void (*destructor)(struct sk_buff *);/* Destruct function*/__u16redirport;/* Redirect port*/};
封包和解包的本质理解
在以上源码中我们主要关注两个部分:
该字段说明报文用了链表结构来维护,对报文进行操作的本质就是链表的增删改查。
怎么体现不同协议层报文呢?如下字段:
head
data
接收时:从MAC头 → IP头 → TCP(或UDP)头 → 应用数据。
发送时:反向移动。
tail
end
[head,end]:缓冲区大小。
[data,tail]:报文。封装和解包本质:移动data指针在缓冲区的位置,加减对应层协议长度。
非常感谢您能耐心读完这篇文章。倘若您从中有所收获,还望多多支持呀!