手写TCP/IP协议栈——TCP结构定义与基本接口实现

一、TCP理论部分讲解

应用程序的工作量减少很多,可靠性都通过传输层直接实现了

TCP连接管理:三次握手&&四次挥手

确认数据包是否收到,如果丢失,就会重传

二、TCP控制块结构定义

xnet_tinny.h

cpp 复制代码
#define XTCP_CFG_MAX_TCP			40

typedef enum _xtcp_state_t
{
	XTCP_STATE_FREE,
	XTCP_STATE_CLOSED,
	XTCP_STATE_LISTEN,
}xtcp_state_t;

typedef enum _xtcp_conn_state_t
{
	XTCP_CONN_CONNECTED,
	XTCP_CONN_DATA_RECV,
	XTCP_CONN_CLOSED,
}xtcp_conn_state_t;

typedef struct _xtcp_t xtcp_t;
typedef xnet_err_t(*xtcp_handler_t)(xtcp_t* tcp, xtcp_conn_state_t event);
struct _xtcp_t
{
	xtcp_state_t state;
	uint16_t local_port, remote_port;
	xipaddr_t remote_ip;
	xtcp_handler_t handler;
};

void xtcp_init(void);

xnet_tinny.c

cpp 复制代码
static xtcp_t tcp_socket[XTCP_CFG_MAX_TCP];

static xtcp_t* tcp_alloc(void)
{
	xtcp_t* tcp, * end;
	for (tcp = tcp_socket, end = tcp_socket + XTCP_CFG_MAX_TCP; tcp < end; tcp++)
	{
		if (tcp->state == XTCP_STATE_FREE)
		{
			tcp->state = XTCP_STATE_CLOSED;
			tcp->local_port = 0;
			tcp->remote_port = 0;
			tcp->remote_ip.addr = 0;
			tcp->handler = (xtcp_handler_t)0;
			return tcp;
		}
	}

	return (xtcp_t*)0;
}

static void tcp_free(xtcp_t* tcp)
{
	tcp->state = XTCP_STATE_FREE;
}

void xtcp_init(void)
{
	memset(tcp_socket, 0, sizeof(tcp_socket));
}

在xnet_init中调用xtcp_init函数:

cpp 复制代码
void xnet_init(void)
{
	ethernet_init();
	xarp_init();
	xip_init();
	xicmp_init();
	xudp_init();
	xtcp_init();
}

三、TCP基本操作接口实现

xnet_tinny.h

cpp 复制代码
xtcp_t* xtcp_open(xtcp_handler_t* handler);
xnet_err_t xtcp_bind(xtcp_t* tcp, uint16_t local_port);
xnet_err_t xtcp_listen(xtcp_t* tcp);
xnet_err_t xtcp_close(xtcp_t* tcp);

xnet_tinny.c

cpp 复制代码
static xtcp_t* tcp_find(xipaddr_t* remote_ip, uint16_t remote_port, uint16_t local_port)
{
	xtcp_t* tcp, * end;
	xtcp_t* founded_tcp = (xtcp_t*)0;

	for (tcp = tcp_socket, end = tcp_socket + XTCP_CFG_MAX_TCP; tcp < end; tcp++)
	{
		if ((tcp->state == XTCP_STATE_FREE) || (tcp->local_port != local_port))
			continue;

		if (xipaddr_is_equal(remote_ip, &tcp->remote_ip) && (tcp->remote_port == remote_port))
			return tcp;

		if (tcp->state == XTCP_STATE_LISTEN)
			founded_tcp = tcp;
	}

	return founded_tcp;
}

xtcp_t* xtcp_open(xtcp_handler_t* handler)
{
	xtcp_t* tcp = tcp_alloc();
	if (!tcp) return (xtcp_t*)0;

	tcp->state = XTCP_STATE_CLOSED;
	tcp->handler = handler;

	return tcp;
}

xnet_err_t xtcp_bind(xtcp_t* tcp, uint16_t local_port)
{
	xtcp_t* curr, * end;
	for (curr = tcp_socket, end = &tcp_socket[XTCP_CFG_MAX_TCP]; curr < end; curr++)
	{
		if ((curr != tcp) && (curr->local_port == local_port))
			return XNET_ERR_BINDED;
	}

	tcp->local_port = local_port;

	return XNET_ERR_OK;
}

xnet_err_t xtcp_listen(xtcp_t* tcp)
{
	tcp->state = XTCP_STATE_LISTEN;
	return XNET_ERR_OK;
}

xnet_err_t xtcp_close(xtcp_t* tcp)
{
	tcp_free(tcp);
	return XNET_ERR_OK;
}

四、TCP基本输入处理

TCP数据包的基本结构

定义TCP头部数据结构

cpp 复制代码
typedef struct _xtcp_hdr_t
{
	uint16_t src_port, dst_port;
	uint32_t seq;
	uint32_t ack;
	union 
	{
		struct
		{

#define XTCP_FLAG_FIN	(1 << 0)
#define XTCP_FLAG_SYN	(1 << 1)
#define XTCP_FLAG_RST	(1 << 2)
#define XTCP_FLAG_ACK	(1 << 4)

			uint16_t flags : 6;
			uint16_t reserved : 6;
			uint16_t hdr_len : 4;
		};
		uint16_t all;
	}hdr_flags;
	uint16_t window;
	uint16_t checksum;
	uint16_t urgent_ptr;
}xtcp_hdr_t;

添加TCP协议字段

cpp 复制代码
typedef enum _xnet_protocol_t
{
	XNET_PROTOCOL_ARP = 0x0806,
	XNET_PROTOCOL_IP = 0x0800,
	XNET_PROTOCOL_ICMP = 1,
	XNET_PROTOCOL_UDP = 17,
	XNET_PROTOCOL_TCP = 6,
}xnet_protocol_t;

添加错误码:

cpp 复制代码
typedef enum _xnet_err_t
{
	XNET_ERR_OK = 0,
	XNET_ERR_IO = -1,
	XNET_ERR_NONE = -2,
	XNET_ERR_BINDED = -3,
	XNET_ERR_PARAM = -4,
	XNET_ERR_MEM = -5,
	XNET_ERR_STATE = -6,
}xnet_err_t;

TCP输入函数xtcp_in实现

cpp 复制代码
void xtcp_in(xipaddr_t* remote_ip, xnet_packet_t* packet)
{
	xtcp_hdr_t* tcp_hdr = (xtcp_hdr_t*)packet->data;
	xtcp_t* tcp;
	uint16_t pre_checksum;

	if (packet->size < sizeof(xtcp_hdr_t))
		return;

	pre_checksum = tcp_hdr->checksum;
	tcp_hdr->checksum = 0;
	if (pre_checksum != 0)
	{
		uint16_t checksum = checksum_peso(remote_ip, &netif_ipaddr, 
			XNET_PROTOCOL_TCP, (uint16_t*)tcp_hdr, packet->size);
		checksum = (checksum == 0) ? 0xFFFF : checksum;
		if (checksum != pre_checksum)
			return;
	}
	tcp_hdr->src_port = swap_order16(tcp_hdr->src_port);
	tcp_hdr->dst_port = swap_order16(tcp_hdr->dst_port);
	tcp_hdr->hdr_flags.all = swap_order16(tcp_hdr->hdr_flags.all);
	tcp_hdr->seq = swap_order32(tcp_hdr->seq);
	tcp_hdr->ack = swap_order32(tcp_hdr->ack);
	tcp_hdr->window = swap_order16(tcp_hdr->window);

	tcp = tcp_find(remote_ip, tcp_hdr->src_port, tcp_hdr->dst_port);
	if (tcp == (xtcp_t*)0)
	{
		tcp_send_reset(tcp_hdr->seq + 1, tcp_hdr->dst_port, remote_ip, tcp_hdr->src_port);
		return;
	}
}

其中swap_order32函数实现:

为了提高可读性写成函数形式,如果想要执行效率高,可以写成宏函数方式(读者可自行尝试)

cpp 复制代码
uint32_t swap_order32(uint32_t v)
{
	uint32_t r_v;
	uint8_t* src = (uint8_t*)&v;
	uint8_t* dst = (uint8_t*)&r_v;

	dst[0] = src[3];
	dst[1] = src[2];
	dst[2] = src[1];
	dst[3] = src[0];

	return r_v;
}

tcp_send_reset函数实现:

复位时Flags的RST和ACK设置为1,seq特殊设置

cpp 复制代码
static xnet_err_t tcp_send_reset(uint32_t remote_ack, uint16_t local_port, 
	xipaddr_t* remote_ip, uint16_t remote_port)
{
	xnet_packet_t* packet = xnet_alloc_for_send(sizeof(xtcp_hdr_t));
	xtcp_hdr_t* tcp_hdr = (xtcp_hdr_t*)packet->data;

	tcp_hdr->src_port = swap_order16(local_port);
	tcp_hdr->dst_port = swap_order16(remote_port);
	tcp_hdr->seq = 0;
	tcp_hdr->ack = swap_order32(remote_ack);
	tcp_hdr->hdr_flags.all = 0;
	tcp_hdr->hdr_flags.hdr_len = sizeof(xtcp_hdr_t) / 4;
	tcp_hdr->hdr_flags.flags = XTCP_FLAG_RST | XTCP_FLAG_ACK;
	tcp_hdr->hdr_flags.all = swap_order16(tcp_hdr->hdr_flags.all);
	tcp_hdr->window = 0;
	tcp_hdr->urgent_ptr = 0;
	tcp_hdr->checksum = 0;
	tcp_hdr->checksum = checksum_peso(&netif_ipaddr, remote_ip, XNET_PROTOCOL_TCP, (uint16_t*)packet->data, packet->size);
	tcp_hdr->checksum = tcp_hdr->checksum ? tcp_hdr->checksum : 0xFFFF;

	return xip_out(XNET_PROTOCOL_TCP, remote_ip, packet);
}

xtcp_in函数调用部分:

在ip层的输入函数内部,多路复用的switch分支添加对TCP段的处理

cpp 复制代码
xipaddr_from_buf(&src_ip, iphdr->src_ip);
	switch (iphdr->protocol)
	{
	case XNET_PROTOCOL_ICMP:
		remove_header(packet, header_size);
		xicmp_in(&src_ip, packet);
	case XNET_PROTOCOL_UDP:
		if (packet->size >= sizeof(xudp_hdr_t))
		{
			xudp_hdr_t* udp_hdr = (xudp_hdr_t*)(packet->data + header_size);
			xudp_t* udp = xudp_find(swap_order16(udp_hdr->dst_port));
			if (udp)
			{
				truncate_packet(packet, total_size);
				remove_header(packet, header_size);
				xudp_in(udp, &src_ip, packet);
			}
			else
				xicmp_dest_unreach(XICMP_CODE_PORT_UNREACH, iphdr);
		}
		break;
	case XNET_PROTOCOL_TCP:
		truncate_packet(packet, total_size);
		remove_header(packet, header_size);
		xtcp_in(&src_ip, packet);
        break;
	default:
		xicmp_dest_unreach(XICMP_CODE_PRO_UNREACH, iphdr);
		break;
	}

五、测试部分

全速运行协议栈,在浏览器中输入:http://192.168.254.2

Flags和checksum都没有问题,钩子代表回复的哪一个TCP段

ok,今天的你就到此为止吧,明天还要接着🐺啊!

相关推荐
Helibo442 小时前
2025年12月gesp3级题解
数据结构·c++·算法
benjiangliu2 小时前
STM32教程-02-STM32复习C语言
c语言·stm32·嵌入式硬件
西幻凌云2 小时前
初始——正则表达式
c++·正则表达式·1024程序员节
少云清2 小时前
【接口测试】4_PyMySQL模块 _操作数据库
服务器·网络·数据库
海清河晏1112 小时前
Linux进阶篇:网络编程
linux·运维·网络
沧澜sincerely3 小时前
蓝桥杯101 拉马车
c++·蓝桥杯·stl
一颗青果3 小时前
Socket编程实例(UDP)
网络·网络协议·udp
潇氡3 小时前
C语言“指针变量“在初始化和做函数参数时的注意事项
c语言
真上帝的左手3 小时前
7. 网络安全-等保
网络·安全·web安全