TCP:传输控制协议(一)

相关协议分析参考tcp/ip协议学习笔记(8)TCP传输控制协议

TCP传输控制块的管理、套接口选项、ioctl、差错处理以及缓存管理涉及以下文件:

include/linux/tcp.h 定义TCP段的格式、TCP传输控制块等结构、宏和函数原型

include/net/sock.h 定义基本的传输控制块结构、宏和函数原型

include/net/inet_connection_sock.h 定义连接请求块等相关接口、宏和函数

include/net/inet_hashtables.h 定义管理传输控制块的散列表

net/ipv4/af_inet.c 网络层和传输层接口

net/ipv4/tcp_ipv4.c 传输控制块与网络层之间的接口实现

net/ipv4/tcp.c 传输控制块与应用层之间的接口实现

net/core/stream.c TCP中流内存管理的实现

TCP传输控制块

TCP传输控制块在TCP整个过程中起着核心的作用,包括建立连接、数据的传输、拥塞的控制以及连接的终止。在TCP连接的整个过程中,按顺序分别使用以下三种类型的TCP传输控制块:

1、第一种类型是tcp_request_sock,在建立连接的过程中使用,存在的时间是比较短的

2、第二种类型是tcp_sock,在连接建立之后终止之前使用,TCP状态为ESTABLISHED。这种传输控制块声明周期最长,发送和接收段都需要它进行控制

3、第三种类型是tcp_timewait_sock,在终止连接的过程中使用,其存在的过程也比较短

inet_connection_sock_af_ops

封装了一组与传输层相关的操作集,包括向网络层发送的接口、传输层的setsockopt接口等,TCP中的实例为ipv4_specific

tcp_options_received

主要用来保存接收到的TCP选项信息,如时间戳、SACK等,同时标志对端支持的特性,如对端是否支持窗口扩大因子、是否支持ACK等。

tcp_skb_cb

TCP层在SKB区中有一个私有信息控制块,即skb_buff结构的cb成员,TCP利用这个字段存储了一个tcp_skb_cb结构。在TCP层,用宏TCP_SKB_CB实现访问该信息块,以增强代码的可读性。对这个私有信息控制块的赋值一般在本层接收到段或发送段之前进行。例如tcp_v4_rcv()是TCP层接收入口函数,当接收到TCP段并对其进行必要校验后,就会对此段的tcp_skb_cb进行设置。而发送过程中,大多数是在生成TCP段时,或是在对TCP段进行分段时设置。

TCP的初始化

传输层TCP模块的初始化函数tcp_init()由IPv4协议族的初始化函数inet_init()调用

void __init tcp_init(void)
{
	struct sk_buff *skb = NULL;
	unsigned long nr_pages, limit;
	int i, max_share, cnt;

	BUILD_BUG_ON(sizeof(struct tcp_skb_cb) > sizeof(skb->cb));

	percpu_counter_init(&tcp_sockets_allocated, 0);
	percpu_counter_init(&tcp_orphan_count, 0);
	tcp_hashinfo.bind_bucket_cachep =
		kmem_cache_create("tcp_bind_bucket",
				  sizeof(struct inet_bind_bucket), 0,
				  SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);

	/* Size and allocate the main established and bind bucket
	 * hash tables.
	 *
	 * The methodology is similar to that of the buffer cache.
	 */
	tcp_hashinfo.ehash =
		alloc_large_system_hash("TCP established",
					sizeof(struct inet_ehash_bucket),
					thash_entries,
					(totalram_pages >= 128 * 1024) ?
					13 : 15,
					0,
					&tcp_hashinfo.ehash_size,
					NULL,
					thash_entries ? 0 : 512 * 1024);
	tcp_hashinfo.ehash_size = 1 << tcp_hashinfo.ehash_size;
	for (i = 0; i < tcp_hashinfo.ehash_size; i++) {
		INIT_HLIST_NULLS_HEAD(&tcp_hashinfo.ehash[i].chain, i);
		INIT_HLIST_NULLS_HEAD(&tcp_hashinfo.ehash[i].twchain, i);
	}
	if (inet_ehash_locks_alloc(&tcp_hashinfo))
		panic("TCP: failed to alloc ehash_locks");
	tcp_hashinfo.bhash =
		alloc_large_system_hash("TCP bind",
					sizeof(struct inet_bind_hashbucket),
					tcp_hashinfo.ehash_size,
					(totalram_pages >= 128 * 1024) ?
					13 : 15,
					0,
					&tcp_hashinfo.bhash_size,
					NULL,
					64 * 1024);
	tcp_hashinfo.bhash_size = 1 << tcp_hashinfo.bhash_size;
	for (i = 0; i < tcp_hashinfo.bhash_size; i++) {
		spin_lock_init(&tcp_hashinfo.bhash[i].lock);
		INIT_HLIST_HEAD(&tcp_hashinfo.bhash[i].chain);
	}

	cnt = tcp_hashinfo.ehash_size;

	tcp_death_row.sysctl_max_tw_buckets = cnt / 2;
	sysctl_tcp_max_orphans = cnt / 2;
	sysctl_max_syn_backlog = max(128, cnt / 256);

	/* Set the pressure threshold to be a fraction of global memory that
	 * is up to 1/2 at 256 MB, decreasing toward zero with the amount of
	 * memory, with a floor of 128 pages, and a ceiling that prevents an
	 * integer overflow.
	 */
	nr_pages = totalram_pages - totalhigh_pages;
	limit = min(nr_pages, 1UL<<(28-PAGE_SHIFT)) >> (20-PAGE_SHIFT);
	limit = (limit * (nr_pages >> (20-PAGE_SHIFT))) >> (PAGE_SHIFT-11);
	limit = max(limit, 128UL);
	limit = min(limit, INT_MAX * 4UL / 3 / 2);
	sysctl_tcp_mem[0] = limit / 4 * 3;
	sysctl_tcp_mem[1] = limit;
	sysctl_tcp_mem[2] = sysctl_tcp_mem[0] * 2;

	/* Set per-socket limits to no more than 1/128 the pressure threshold */
	limit = ((unsigned long)sysctl_tcp_mem[1]) << (PAGE_SHIFT - 7);
	max_share = min(4UL*1024*1024, limit);

	sysctl_tcp_wmem[0] = SK_MEM_QUANTUM;
	sysctl_tcp_wmem[1] = 16*1024;
	sysctl_tcp_wmem[2] = max(64*1024, max_share);

	sysctl_tcp_rmem[0] = SK_MEM_QUANTUM;
	sysctl_tcp_rmem[1] = 87380;
	sysctl_tcp_rmem[2] = max(87380, max_share);

	printk(KERN_INFO "TCP: Hash tables configured "
	       "(established %d bind %d)\n",
	       tcp_hashinfo.ehash_size, tcp_hashinfo.bhash_size);

	tcp_register_congestion_control(&tcp_reno);
}

TCP传输控制块的管理

在成功创建一个TCP传输控制块后,就需要对其进行合理的管理。TCP存在多个状态,有些状态存在的时间比较短暂,在TCP两端交互的过程中,这些状态很快会迁移到另一种状态。相比之下,LISTEN和ESTABLISHED这两种状态是一种常态。为了能对处于不同状态的传输控制块进行合理的管理和访问,TCP根据状态将传输控制块存储到多个不同的散列表中。

inet_hashinfo

struct inet_hashinfo {
	/* This is for sockets with full identity only.  Sockets here will
	 * always be without wildcards and will have the following invariant:
	 *
	 *          TCP_ESTABLISHED <= sk->sk_state < TCP_CLOSE
	 *
	 * TIME_WAIT sockets use a separate chain (twchain).
	 */
	struct inet_ehash_bucket	*ehash;
	spinlock_t			*ehash_locks;
	unsigned int			ehash_size;
	unsigned int			ehash_locks_mask;

	/* Ok, let's try this, I give up, we do need a local binding
	 * TCP hash as well as the others for fast bind/connect.
	 */
	struct inet_bind_hashbucket	*bhash;

	unsigned int			bhash_size;
	/* 4 bytes hole on 64 bit */

	struct kmem_cache		*bind_bucket_cachep;

	/* All the above members are written once at bootup and
	 * never written again _or_ are predominantly read-access.
	 *
	 * Now align to a new cache line as all the following members
	 * might be often dirty.
	 */
	/* All sockets in TCP_LISTEN state will be in here.  This is the only
	 * table where wildcard'd TCP sockets can exist.  Hash function here
	 * is just local port number.
	 */
	struct inet_listen_hashbucket	listening_hash[INET_LHTABLE_SIZE]
					____cacheline_aligned_in_smp;

	atomic_t			bsockets;
};

struct inet_ehash_bucket *ehash;

unsigned int ehash_size;

ehash指向一个大小为ehash_size的inet_ehash_bucket结构类型的散列表,用来管理TCP状态除LISTEN之外的传输控制块的散列表

struct inet_ehash_bucket {

struct hlist_nulls_head chain;

struct hlist_nulls_head twchain;

};

chain、twchain用于链接传输控制块

struct inet_bind_hashbucket *bhash;

unsigned int bhash_size;

大小为bhash_size的bhash散列表主要用来存储已绑定端口的信息

struct inet_bind_hashbucket {

spinlock_t
lock;

struct hlist_headchain;

};

chain用于建立端口绑定信息块

struct inet_listen_hashbucket listening_hash[INET_LHTABLE_SIZE];

用来存储管理LISTEN状态的传输控制块的散列表

在成功创建一个传输控制块之后,就会调用传输接口层的hash接口,将该传输控制块添加到ehash散列表中,直至释放该传输控制块为止。在TCP中,实现hash接口的函数为tcp_v4_hash()。

当不需要某个传输控制块时,就会调用传输接口层的unhash接口,将该传输控制块从ehash散列表中删除。在TCP中,实现hash接口的函数为tcp_unhash()。

在调用listen系统调用之后,套接口就会进入LISTEN状态,此时会调用__inet_hash(),将该传输控制块添加到listening_hash散列表中,以便快速地查找处于侦听状态的套接口。

时间: 2024-08-10 19:17:41

TCP:传输控制协议(一)的相关文章

读书笔记 --TCP :传输控制协议(二)

TCP建立连接 请求端(客户端)发送一个SYN指明客户端打算连接的服务器端口号,以及初始序列号. 服务端发回包含服务器的初始序号的SYN报文段作为应答.同时,将确认序号设置为客户的ISN加1以对客户的SYN报文段进行确认.一个SYN占用一个序号. 客户端必须将确认序号设置为服务端的ISN加1以对服务器的SYN报文段进行确认. TCP连接终止 建立一个连接需要三次握手,而终止一个连接要经过4次握手.这是由TCP的半关闭造成的.既然一个TCP连接是全双工(即数据在两个方向上能同时传递),因此每个方向

读书笔记 --TCP :传输控制协议(一)

TCP提供一种面向连接的,可靠的字节流服务. TCP 通过如下方式来提供可靠性: 应用数据被分割成TCP认为最适合发送的数据块. 超时重传机制.TCP发出一个段后,启动一个定时器,等待目的端确认收到这个报文段.如果不能及时收到确认,将重发报文段. TCP收到数据后,将发送一个确认.这个确认不是立即发送,通常推迟几分之一秒. TCP将保持首部和数据的校验和.用于差错检验,如果收到的数据出现差错,TCP将丢掉这个报文段并且不确认.(希望超时重传) 既然TCP作为IP数据报来传输,而IP数据报的到达可

TCP/IP详解 卷一(第十七章 TCP:传输控制协议)

与UDP协议相比,TCP提供一种面向连接的.可靠的字节流服务. TCP首部 跟UDP一样,TCP数据被封装在一个IP数据报中,下面显示TCP的首部数据格式 每个TCP段都包含源端和目的端的端口号,用于寻找发送端和接收端应用程序. 序号用来标识从TCP发送端向TCP接收端发送的数据字节流,确认序号包含发送确认的一段所期望收到的下一个序号. 在TCP首部中由6个标志比特.它们中的多个可同时设置为1,下面简单介绍一下它们的用法: URG    紧急指针有效 ACK    确认序号有效 PSH    接

《TCP/IP详解卷1:协议》第17、18章 TCP:传输控制协议(2)-读书笔记

章节回顾: <TCP/IP详解卷1:协议>第1章 概述-读书笔记 <TCP/IP详解卷1:协议>第2章 链路层-读书笔记 <TCP/IP详解卷1:协议>第3章 IP:网际协议(1)-读书笔记 <TCP/IP详解卷1:协议>第3章 IP:网际协议(2)-读书笔记 <TCP/IP详解卷1:协议>第4章 ARP:地址解析协议-读书笔记 <TCP/IP详解卷1:协议>第5章 RARP:逆地址解析协议-读书笔记 <TCP/IP详解卷1:协

《TCP/IP详解卷1:协议》第17、18章 TCP:传输控制协议(1)-读书笔记

章节回顾: <TCP/IP详解卷1:协议>第1章 概述-读书笔记 <TCP/IP详解卷1:协议>第2章 链路层-读书笔记 <TCP/IP详解卷1:协议>第3章 IP:网际协议(1)-读书笔记 <TCP/IP详解卷1:协议>第3章 IP:网际协议(2)-读书笔记 <TCP/IP详解卷1:协议>第4章 ARP:地址解析协议-读书笔记 <TCP/IP详解卷1:协议>第5章 RARP:逆地址解析协议-读书笔记 <TCP/IP详解卷1:协

传输控制协议(TCP) -- 连接建立及终止过程

本文摘录自<UNIX网络编程 卷1>. 1. TCP特性 相对于不可靠.无连接的用户数据报协议(User Datagram Protocol, UDP),传输控制协议(Transmission Control Protocol, TCP)是可靠的.面向连接的协议.除此之外,TCP还提供了以下特性: 1)TCP含有用于动态估算客户和服务器之间的往返时间(round-trip time, RTT),以便它知道等待一个确认需要多长时间. 2)TCP通过给其中每个字节关联一个序列号对所发送的数据进行排

TCP:传输控制协议简单讲解(八)

(参考文献)TCP/IP详解,卷1:协议 TCP的服务 尽管TCP和UDP都使用相同的网络层(IP层),TCP却向应用层提供与UDP完全不同的服务.TCP提供一种面向连接的.可靠的字节流服务. 面向连接意味着,两个使用TCP的应用(通常是一个客户和一个服务器)在彼此交换数据之前必须先建立一个TCP连接.这一过程与打电话很相似,先拨号振铃,等待对方摘机说"喂",然后才说明是谁.TCP通信,本质上是两个线程之间的通信(客户端与服务端):而TCP连接的建立,本质上是可以说是服务端和客户端通过

传输控制协议(TCP) -- TCP状态转换图

本文参考自: <UNIX网络编程 卷1> 在<UNIX网络编程 卷1>一书中,作者给出了TCP状态转换图(如下).本文也将围绕此图进行阐释.

七LWIP学习笔记之传输控制协议(TCP)

一.协议简介 1.TCP的必要性 2.TCP的特性 3.连接的定义 4.数据流编号 5.滑动窗口 二.TCP报文 1.报文格式 2.TCP选项 3.紧急数据 4.强迫数据交互 5.报文首部数据结构 三.TCP连接 1.建立连接 2.断开连接 3.复位连接 4.TCP状态转换图 5.特殊的状态转换 四.TCP控制块 1.控制块数据结构 2.控制块链表 3.接收窗口 4.发送窗口 五.TCP编程函数 1.控制块新建 2.控制块绑定 3.控制块监听 4.控制块连接 5.发送数据 6.关闭连接 7.其他