linux 网络 sk_buff结构

article/2025/9/25 21:55:26

一、简介

 sk_buff的意思是socket buffer,这是Linux网络子系统中的核心数据结构。

定义在 <include/linux/skbuff.h> 中,它由许多变量组成,目标就是满足所有网络协议的需要。

sk_buff 在不同的网络层被使用(MAC 或其他在 L2 的协议,在 L3 的 IP 协议,在 L4 的 TCP 或 UDP 等),当它从一层传递到另一层时,各个字段也会发生变化。在被传递到 L3 之前,L4 会追加头信息,然后在被传递到 L2 之前,L3 会追加头信息。从一层传递到另一层时,通过追加头信息的方式比将数据在层之间拷贝会更有效率。由于要在 buff 的开头增加空间(与平时常见的在尾部追加空间相比)是一项复杂的操作,内核便提供了 skb_reserve 函数执行这个操作。因此,随着 buffer 从上层到下层的传递,每层协议做的第一件事就是调用 skb_reserve 去为它们的协议头在 buffer 的头部分配空间。在后面,我们将通过一个例子去了解内核如何在当 buffer 在各个层间传递时,确保为每一层保留了足够的空间让它们添加它们自己的协议头。

在接收数据时,buffer 会被从下层到上层传递,在从下到上的过程中,前一层的协议头对于当前层来说已经没有用了。比如:L2 的协议头只会被处理 L2 协议的设备驱动程序使用,L3 并不关心 L2 的头。那么内核怎么做的呢? 内核的实现是:** sk_buff 中有一个指针会指向当前位于的层次的协议的协议头的内存开始地址,于是从 L2 到 L3 时,只需将指向 L2 头部的指针移动到 L3 的头部即可**(又是一步追求效率的操作)。

二、sk_buff的组织结构

Linux 内核把系统中所有的 sk_buff 实例维护在一个双向链表中,sk_buff 链表的每个节点也通过 next 和 prev 分别指向后继和前驱节点。但是 sk_buff 链表还要求:每个节点必须能够很快的找到整个链表的头节点。为了实现这个要求,一个额外的数据结构(sk_buff_head)被添加到链表的头部,作为一个空节点:

struct sk_buff_head {/* These two members must be first. */struct sk_buff	*next;struct sk_buff	*prev;__u32		qlen;spinlock_t	lock;
};
  • len: 表示链表中的节点数
  • lock: 用作多线程同步

sk_buff 和 sk_buff_head 开始的两个节点(next prev)是相同的。即使 sk_buff_head 比 sk_buff 更轻量化,也允许这两种结构在链表中共存。另外,可以使用相同函数来操作 sk_buff 和 sk_buff_head。

为了实现通过每个节点都能快速找到链表头,每个节点都会包含一个指向链表中唯一的 sk_buff_head 的指针(list)。

二、sk_buff的关键成员

2.1、数据区

2.1.1、 线性数据区

unsigned char	*head, *data, *tail, *end;

这一节介绍先行数据区在sk_buff创建过程中的变化,图中暂时省略了非线性数据区:

sk_buff结构数据区刚被申请好,此时 head 指针、data 指针、tail 指针都是指向同一个地方。记住前面讲过的:head 指针和 end 指针指向的位置一直都不变,而对于数据的变化和协议信息的添加都是通过 data 指针和 tail 指针的改变来表现的。

开始准备存储应用层下发过来的数据,通过调用函数 skb_reserve(m) 来使 data 指针和 tail 指针同时向下移动,空出一部分空间来为后期添加协议信息。m一般为最大协议头长度,内核中定义。

开始存储数据了,通过调用函数 skb_put() 来使 tail 指针向下移动空出空间来添加数据,此时 skb->data 和 skb->tail 之间存放的都是数据信息,无协议信息。

这时就开始调用函数 skb_push() 来使 data 指针向上移动,空出空间来添加各层协议信息,添加协议信息也是用skb_put()。直到最后到达二层,添加完帧头然后就开始发包了。

2.1.2、 非线性数据区(skb_shared_info

/*  include/linux/skbuff.h */#if (65536/PAGE_SIZE + 1) < 16
#define MAX_SKB_FRAGS 16UL
#else
#define MAX_SKB_FRAGS (65536/PAGE_SIZE + 1)
#endifstruct skb_shared_info {unsigned char   nr_frags; /*表示有多少分片结构*/__u8        tx_flags;unsigned short  gso_size;/* Warning: this field is not always filled in (UFO)! */unsigned short  gso_segs;unsigned short  gso_type;struct sk_buff  *frag_list; /*一种类型的分配数据*/struct skb_shared_hwtstamps hwtstamps;u32     tskey;__be32          ip6_frag_id;/** Warning : all fields before dataref are cleared in __alloc_skb()*/atomic_t    dataref; /*用于引用计数,克隆一个skb结构体时会增加一个引用计数*//* Intermediate layers must ensure that destructor_arg* remains valid until skb destructor */void *      destructor_arg;/* must be last field, see pskb_expand_head() */skb_frag_t  frags[MAX_SKB_FRAGS];  /*保存分页数据,skb->data_len = 所有数组数据长度之和*/
};

一个skb用于存储一个报文,如果一个报文特别大的话,一个skb存储不下,就会启用非线性数据区作为数据区域的扩展。

从上图中可以看出,skb->end的下一个字节就作为非线性数据区的开始。end指针的下个字节可以作为分片结构的开始,获取end指针的位置要强行转成分片结构,内核中有定义好的宏:

#define skb_shinfo(SKB) ((struct skb_shared_info *)(skb_end_pointer(SKB)))

非线性区域有两种组织方式:

线性存储区放不下就需要多个skb来存储,这就是下面frag_list的作用,保存连续的skb,但是如果内核支持分散聚集技术的话,并且报文长度刚好又不大于mtu,就不必重新分配一个skb来存储,可以使用一些内存碎片来存储,就是下面的frags数组表示的内存页面片段。


(1)用数组存储的分片数据区。

采用是是结构体中的frags[MAX_SKB_FRAGS]。skb_frag_struct结构体如下:

/*  include/linux/skbuff.h */
typedef struct skb_frag_struct skb_frag_t;struct skb_frag_struct {struct {struct page *p; /*指向分片数据区的指针,类似于sk_buff中的data指针*/} page;
#if (BITS_PER_LONG > 32) || (PAGE_SIZE >= 65536)__u32 page_offset;__u32 size;
#else__u16 page_offset; /*偏移量,表示相对开始位置的页偏移量*/__u16 size; /*page中的数据长度*/
#endif
};

下图显示了frags是怎么分配分片数据的:

(2)frag_list指针来指向的分片数据。

2.2、数据区长度

unsigned int len, data_len, mac_len;
unsigned int truesize;

这里要声明两个概念的区别,后续直接用这两个概念,注意区分:
(1)线性区总长度:skb_data_len = skb->end - skb->head;(不包括 skb_shared_info)
(2)线性区有效数据长度:linear_buffer_len = skb->tail - skb->data;不包含线性数据中的头空间和尾空间。


skb->data_len: skb中的分片数据(非线性数据)的长度。
skb->len: skb中的数据块的总长度,数据块包括实际线性数据和非线性数据,非线性数据为data_len,所以skb->len= (tail - data) + data_len。
skb->truesize: skb的总长度,包括sk_buff结构和数据部分,skb=sk_buff控制信息 + 线性数据(包括头空间和尾空间) + skb_shared_info控制信息 + 非线性数据,所以skb->truesize = sizeof(struct sk_buff) + (end - head) + sizeof(struct skb_shared_info) + data_len。

2.3、协议头部指针

依次是传输层、网络层、mac层的头部指针,用union表示是互斥的,只能表示其中的一种

	union {struct tcphdr	*th;struct udphdr	*uh;struct icmphdr	*icmph;struct igmphdr	*igmph;struct iphdr	*ipiph;struct ipv6hdr	*ipv6h;unsigned char	*raw;} h;union {struct iphdr	*iph;struct ipv6hdr	*ipv6h;struct arphdr	*arph;unsigned char	*raw;} nh;union {unsigned char 	*raw;} mac

当接收到数据包时,从底层向顶层传递数据的时候,只需要把对应的skb->data字段指向相应的头部即可。

2.4、路由相关

struct dst_entry dst

	struct  dst_entry	*dst;struct	sec_path	*sp
  • dst_entry指向需要转发包的函数,这个指针在sk_buff在IP层传输前必须是合法的
  • sec_path是一个可选的有关网络安全的成员

2.5、信息控制块

	char	cb[48]

每层协议私有的信息存储空间,由每一层自己维护和使用,并只在本层有效

TCP, for example, uses that space to store a tcp_skb_cb data structure, which is defined in include/net/tcp.h:

struct tcp_skb_cb {... ... ..._ _u32        seq;        /* Starting sequence number */_ _u32        end_seq;    /* SEQ + FIN + SYN + datalen*/_ _u32        when;       /* used to compute rtt's    */_ _u8         flags;      /* TCP header flags.        */... ... ...
};

这是 TCP 代码访问结构的宏。宏仅由一个指针转换组成:

#define TCP_SKB_CB(_ _skb)    ((struct tcp_skb_cb *)&((_ _skb)->cb[0]))
int tcp_v4_rcv(struct sk_buff *skb)
{... ... ...th = skb->h.th;TCP_SKB_CB(skb)->seq = ntohl(th->seq);TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin +skb->len - th->doff * 4);TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq);TCP_SKB_CB(skb)->when = 0;TCP_SKB_CB(skb)->flags = skb->nh.iph->tos;TCP_SKB_CB(skb)->sacked = 0;... ... ...
}

2.6、其他

struct timeval stamp

报文到达或者离开的时间戳,一般表示何时收到报文,一般是在包从驱动中往二层发送的接口函数中设置。它在接收函数 netif_rx (kernel/linux/net/core/dev.c)中设置。

/include/linux/skbuff.hstatic inline void __net_timestamp(struct sk_buff *skb)
{skb->tstamp = ktime_get_real();
}

struct net_device *dev

指向网络设备,作用与该sk_buff是发送包还是接收包有关。在初始化网络设备驱动,分配接收缓存队列时,将该指针指向收到数据包的网络设备

struct net_device *input_dev

This is the device the packet has been received from. It is a NULL pointer when the packet has been generated locally. 指向接收报文的原始网络设备,如果包是本地生成的,则该值为NLL,主要用于流量控制

struct net_device *real_dev

虚拟设备才有效

引用计数

atomic_t		users;
  • 记录有多少引用指向这个sk_buff,该计数器只保护sk_buff描述符,要区别于skb_shared_info结构的dataref成员
  • 通常使用skb_get()和kfree_skb()操作引用计数

附录:v4.9.130版本linux源码

/** *	struct sk_buff - socket buffer*	@next: Next buffer in list*	@prev: Previous buffer in list*	@tstamp: Time we arrived/left*	@rbnode: RB tree node, alternative to next/prev for netem/tcp*	@sk: Socket we are owned by*	@dev: Device we arrived on/are leaving by*	@cb: Control buffer. Free for use by every layer. Put private vars here*	@_skb_refdst: destination entry (with norefcount bit)*	@sp: the security path, used for xfrm*	@len: Length of actual data*	@data_len: Data length*	@mac_len: Length of link layer header*	@hdr_len: writable header length of cloned skb*	@csum: Checksum (must include start/offset pair)*	@csum_start: Offset from skb->head where checksumming should start*	@csum_offset: Offset from csum_start where checksum should be stored*	@priority: Packet queueing priority*	@ignore_df: allow local fragmentation*	@cloned: Head may be cloned (check refcnt to be sure)*	@ip_summed: Driver fed us an IP checksum*	@nohdr: Payload reference only, must not modify header*	@nfctinfo: Relationship of this skb to the connection*	@pkt_type: Packet class*	@fclone: skbuff clone status*	@ipvs_property: skbuff is owned by ipvs*	@peeked: this packet has been seen already, so stats have been*		done for it, don't do them again*	@nf_trace: netfilter packet trace flag*	@protocol: Packet protocol from driver*	@destructor: Destruct function*	@nfct: Associated connection, if any*	@nf_bridge: Saved data about a bridged frame - see br_netfilter.c*	@skb_iif: ifindex of device we arrived on*	@tc_index: Traffic control index*	@tc_verd: traffic control verdict*	@hash: the packet hash*	@queue_mapping: Queue mapping for multiqueue devices*	@xmit_more: More SKBs are pending for this queue*	@pfmemalloc: skbuff was allocated from PFMEMALLOC reserves*	@ndisc_nodetype: router type (from link layer)*	@ooo_okay: allow the mapping of a socket to a queue to be changed*	@l4_hash: indicate hash is a canonical 4-tuple hash over transport*		ports.*	@sw_hash: indicates hash was computed in software stack*	@wifi_acked_valid: wifi_acked was set*	@wifi_acked: whether frame was acked on wifi or not*	@no_fcs:  Request NIC to treat last 4 bytes as Ethernet FCS*	@napi_id: id of the NAPI struct this skb came from*	@secmark: security marking*	@mark: Generic packet mark*	@vlan_proto: vlan encapsulation protocol*	@vlan_tci: vlan tag control information*	@inner_protocol: Protocol (encapsulation)*	@inner_transport_header: Inner transport layer header (encapsulation)*	@inner_network_header: Network layer header (encapsulation)*	@inner_mac_header: Link layer header (encapsulation)*	@transport_header: Transport layer header*	@network_header: Network layer header*	@mac_header: Link layer header*	@tail: Tail pointer*	@end: End pointer*	@head: Head of buffer*	@data: Data head pointer*	@truesize: Buffer size*	@users: User count - see {datagram,tcp}.c*/struct sk_buff {union {struct {/* These two members must be first. */struct sk_buff		*next;struct sk_buff		*prev;union {ktime_t		tstamp;struct skb_mstamp skb_mstamp;};};struct rb_node	rbnode; /* used in netem & tcp stack */};struct sock		*sk;struct net_device	*dev;/** This is the control buffer. It is free to use for every* layer. Please put your private variables there. If you* want to keep them across layers you have to do a skb_clone()* first. This is owned by whoever has the skb queued ATM.*/char			cb[48] __aligned(8);unsigned long		_skb_refdst;void			(*destructor)(struct sk_buff *skb);
#ifdef CONFIG_XFRMstruct	sec_path	*sp;
#endif
#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)struct nf_conntrack	*nfct;
#endif
#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)struct nf_bridge_info	*nf_bridge;
#endifunsigned int		len,data_len;__u16			mac_len,hdr_len;/* Following fields are _not_ copied in __copy_skb_header()* Note that queue_mapping is here mostly to fill a hole.*/kmemcheck_bitfield_begin(flags1);__u16			queue_mapping;/* if you move cloned around you also must adapt those constants */
#ifdef __BIG_ENDIAN_BITFIELD
#define CLONED_MASK	(1 << 7)
#else
#define CLONED_MASK	1
#endif
#define CLONED_OFFSET()		offsetof(struct sk_buff, __cloned_offset)__u8			__cloned_offset[0];__u8			cloned:1,nohdr:1,fclone:2,peeked:1,head_frag:1,xmit_more:1,pfmemalloc:1;kmemcheck_bitfield_end(flags1);/* fields enclosed in headers_start/headers_end are copied* using a single memcpy() in __copy_skb_header()*//* private: */__u32			headers_start[0];/* public: *//* if you move pkt_type around you also must adapt those constants */
#ifdef __BIG_ENDIAN_BITFIELD
#define PKT_TYPE_MAX	(7 << 5)
#else
#define PKT_TYPE_MAX	7
#endif
#define PKT_TYPE_OFFSET()	offsetof(struct sk_buff, __pkt_type_offset)__u8			__pkt_type_offset[0];__u8			pkt_type:3;__u8			ignore_df:1;__u8			nfctinfo:3;__u8			nf_trace:1;__u8			ip_summed:2;__u8			ooo_okay:1;__u8			l4_hash:1;__u8			sw_hash:1;__u8			wifi_acked_valid:1;__u8			wifi_acked:1;__u8			no_fcs:1;/* Indicates the inner headers are valid in the skbuff. */__u8			encapsulation:1;__u8			encap_hdr_csum:1;__u8			csum_valid:1;__u8			csum_complete_sw:1;__u8			csum_level:2;__u8			csum_bad:1;
#ifdef CONFIG_IPV6_NDISC_NODETYPE__u8			ndisc_nodetype:2;
#endif__u8			ipvs_property:1;__u8			inner_protocol_type:1;__u8			remcsum_offload:1;
#ifdef CONFIG_NET_SWITCHDEV__u8			offload_fwd_mark:1;
#endif/* 2, 4 or 5 bit hole */#ifdef CONFIG_NET_SCHED__u16			tc_index;	/* traffic control index */
#ifdef CONFIG_NET_CLS_ACT__u16			tc_verd;	/* traffic control verdict */
#endif
#endifunion {__wsum		csum;struct {__u16	csum_start;__u16	csum_offset;};};__u32			priority;int			skb_iif;__u32			hash;__be16			vlan_proto;__u16			vlan_tci;
#if defined(CONFIG_NET_RX_BUSY_POLL) || defined(CONFIG_XPS)union {unsigned int	napi_id;unsigned int	sender_cpu;};
#endif
#ifdef CONFIG_NETWORK_SECMARK__u32		secmark;
#endifunion {__u32		mark;__u32		reserved_tailroom;};union {__be16		inner_protocol;__u8		inner_ipproto;};__u16			inner_transport_header;__u16			inner_network_header;__u16			inner_mac_header;__be16			protocol;__u16			transport_header;__u16			network_header;__u16			mac_header;/* private: */__u32			headers_end[0];/* public: *//* These elements must be at the end, see alloc_skb() for details.  */sk_buff_data_t		tail;sk_buff_data_t		end;unsigned char		*head,*data;unsigned int		truesize;atomic_t		users;
};

ref:

Linux 内核网络协议栈 ------sk_buff 结构体 以及 完全解释 (2.6.16) - 明明是悟空 - 博客园

Linux SKB结构体中各个长度字段的含义(len, data_len, headlen, pagelen)_mrsonko的博客-CSDN博客_skb_headlen

https://abcdxyzk.github.io/download/kernel/sk_buff%E8%AF%A6%E8%A7%A3.pdf

Linux内核中sk_buff结构详解 - 简书

理解Linux内部网络实现之关键数据结构 sk_buff – Yang Blog

Section 2.1. The Socket Buffer: sk_buff Structure--深入理解linux网络技术内幕--嵌入式linux中文站

Linux内核网络源码解析1——sk_buff结构

http://wiki.dreamrunner.org/public_html/Linux/Networks/sk_buff-structure-analysis.html


http://chatgpt.dhexx.cn/article/dT8VBm7B.shtml

相关文章

梳理50道经典计算机网络面试题

我梳理了50道计算机网络面试题&#xff0c;每一道题目都特别经典&#xff0c;大厂也非常喜欢问。相信大家看完&#xff0c;会有新的收获滴~ 1. 说说HTTP常用的状态码及其含义&#xff1f; 思路: 这道面试题主要考察候选人&#xff0c;是否掌握HTTP状态码这个基础知识点。 不管是…

24 张图总结 TCP 基础知识,看完我飘了。

TCP 是一种面向连接的单播协议&#xff0c;在 TCP 中&#xff0c;并不存在多播、广播的这种行为&#xff0c;因为 TCP 报文段中能明确发送方和接受方的 IP 地址。 在发送数据前&#xff0c;相互通信的双方&#xff08;即发送方和接受方&#xff09;需要建立一条连接&#xff0…

【随机过程】19 - 随机过程的线性预测问题

随机过程的线性预测问题 文章目录 随机过程的线性预测问题1. 随机过程的估计问题概述1.1 预测问题1.2 内插问题1.3 滤波问题 2. 随机过程的可预测性2.1 新息过程2.1.1 信息过程的定义2.1.2 估计的子空间分解2.1.3 新息过程的性质 2.2 随机过程的正则性与奇异性2.2.1 正则性和奇…

计算机网络传输层测试

一 单项选择题 1.下列选项中&#xff0c;&#xff08; D &#xff09;是用于传输层寻址的。 A.MAC地址 B.IPv4地址 C.IPv6地址 D.端口 解析&#xff1a;传输层对主机上的不同网络进程进行了编号&#xff0c;用不同的数字区分不同的网络进程。传输层标识网络进程的数字称为传…

上岸阿里了

大家好&#xff0c;我是老王&#xff0c;收到来自近期成功上岸的粉丝分享的阿里面试真题&#xff0c;分享给大家参考下&#xff0c;希望大家看完成功面试上大厂Offer。 01.薪资体系 新技术用到的也很多&#xff0c;也是很多人想要进入的大厂备选之一。 阿里的薪资结构&#xf…

2W字!梳理50道经典计算机网络面试题(收藏版)

1. 说说HTTP常用的状态码及其含义&#xff1f; 思路: 这道面试题主要考察候选人&#xff0c;是否掌握HTTP状态码这个基础知识点。 不管是不是面试需要&#xff0c;我们都要知道&#xff0c;日常开发中的这几个状态码的含义哈&#xff1a; 2. HTTP 常用的请求方式&#xff0c;区…

Netty 单机百万连接测试

1.Netty框架简介 1.1.Netty简介 netty是jboss提供的一个java开源框架&#xff0c;netty提供异步的、事件驱动的网络应用程序框架和工具&#xff0c;用以快速开发高性能、高可用性的网络服务器和客户端程序。也就是说netty是一个基于nio的编程框架&#xff0c;使用netty可以快…

LPCNET: 通过线性预测改进神经语音合成

LPCNET: 通过线性预测改进神经语音合成 摘要索引词 -- 神经音频合成 参数编码 WaveRNN 1.导言2.WAVERNN3.LPCNET3.1条件参数3.2 预加重和量化3.3 线性预测3.4 输出层3.5 稀疏矩阵3.6 嵌入和代数简化3.7 从概率分布中抽取样本3.8 训练噪声注入 4. 评估4.1 复杂度4.2 实验设置4.3…

TCP拥塞机制学习

TCP拥塞机制学习 写在前面 很早就想总结一下tcp方面的知识了&#xff0c;心动不如行动&#xff0c;这一块面试重点&#xff0c;而其也是coder的必修课。 一、TCP头部报文格式 了解任何一个协议都要从它的协议报文开始&#xff0c;我们先看一下他的格式和一些基本概念。 TC…

3 万字 + 100 张图带你彻底搞懂 TCP 面试题(强烈建议收藏)

大家好&#xff0c;我是小林&#xff0c;一个专为大家图解的工具人。 不管面试 Java 、C/C、Python 等开发岗位&#xff0c; TCP 的知识点可以说是必问的了。 任 TCP 虐我千百遍&#xff0c;我仍待 TCP 如初恋。 过去不会没关系&#xff0c;今天就让我们来消除这份恐惧&…

计算机网络常见知识点总结

网络 1.IP地址分类 网络为全为1的是广播地址&#xff0c;所以要减一&#xff0c;因此127减一为126 A类IP地址 地址范围1.0.0.0到127.255.255.255。可用的A类网络有126个 B类IP地址地址范围128.0.0.0到191.255.255.255。可用的B类网络有16382个 C类IP地址范围从192.0.0.0到223.…

手撸架构,网络 面试36问

TCP 链接 三次握手&#xff1a; 首先服务器端处于LISTEN状态。当客户端想要建立连接时&#xff0c;他将发送一个SYN包&#xff0c;序列号假如为u。客户端进入SYN_SENT状态。当服务器端收到了这个SYN包&#xff0c;如果服务器同意建立连接&#xff0c;他将发送一个SYN&#xf…

Java面试必背八股文[11]:计算机网络

OSI与TCP/IP各层的结构&#xff1f; 答:OSI分层 &#xff08;7层&#xff09;&#xff1a;物理层、数据链路层、网络层、传输层、会话层、表示层、应用层。 TCP/IP分层&#xff08;4层&#xff09;&#xff1a;网络接口层、 网际层、运输层、 应用层。 五层协议 &#xff08;…

深入理解Linux网络——内核是如何发送网络包的

文章目录 一、相关实际问题二、网络包发送过程总览三、网卡启动准备四、数据从用户进程到网卡的详细过程1&#xff09;系统调用实现2&#xff09;传输层处理1. 传输层拷贝2. 传输层发送 3&#xff09;网络层发送处理4&#xff09;邻居子系统5&#xff09;网络设备子系统6&#…

TCP的重传机制、滑动窗口、流量控制、拥塞控制,这一篇就够了

对于TCP 的重传机制、滑动窗口、流量控制、拥塞控制这几个知识点&#xff0c;做了详细介绍&#xff0c;图解形式快速理解。 重传机制 TCP 实现可靠传输的方式之一&#xff0c;是通过序列号与确认应答。 在 TCP 中&#xff0c;当发送端的数据到达接收主机时&#xff0c;接收端…

Symmetric diffeomorphic image registration with cross-correlation

Symmetric diffeomorphic image registration with cross-correlation: Evaluating automated labeling of elderly and neurodegenerative brain 摘要 现代神经影像学最具挑战性的问题之一是对神经变性的详细描述&#xff0c;量化空间和纵向萎缩模式是这一过程的重要组成部分…

非科班秋招面试总结

目录 javaSE方面 HashMap与ConcurrentHashMap(hash冲突&#xff0c;扩容机制&#xff0c;1.7与1.8的区别&#xff0c;锁) 面向对象特点 泛型 String StringBuffer StringBuilder Overload 与Override abstract 与interface final finally finalize 1.8的新特性 JVM方面 类加载机…

TCP详解(WireShark抓包分析TCP三次握手和TCP四次挥手)

TCP和UDP TCP报文格式 TCP首部的报文格式如下&#xff1a; 宏观上来看如下&#xff1a; 此图来源于&#xff1a;https://zhuanlan.zhihu.com/p/144273871 知乎-腾讯技术-TCP拥塞控制详解 来源连接端口&#xff08;16位长&#xff09;&#xff0d;识别发送连接端口 目的连接端…

tcp协议抓包详解

三次握手 握手的目标 抓包 序列号client 和server 是不一样的&#xff0c;也没从0开始 网络报文中报文可能会延迟&#xff0c;会重发&#xff0c;丢失。 为了不影响其他链接&#xff0c;所以是不同的而且是随机的 三次握手中的性能优化与安全问题 超时时间与缓冲队列 fast op…

快速穷举TCP连接欺骗攻击-利用SYN Cookies

TCP 利用 32比特的 Seq/Ack 序列号来确认每一个连接的可靠性. 此外, 这些32位的序列号还能保证服务器不会被会话劫持&#xff0c;伪造一个服务器发出的初始序列号(ISN) 是个难以实现的技术. 因为暴力破解的话需要穷举这个32比特的序列号&#xff0c;在一个千兆比特级别的网卡上…