手写TCP/IP协议栈——TCP数据接收

一、理论部分

使用接收缓冲区来缓存对方发来的数据

二、代码实现部分

在tcp控制块添加接收缓冲区字段

cpp 复制代码
struct _xtcp_t
{
	xtcp_state_t state;
	uint16_t local_port, remote_port;
	xipaddr_t remote_ip;
	uint32_t unack_seq, next_seq;
	uint32_t ack;
	uint16_t remote_mss;
	uint16_t remote_win;
	xtcp_handler_t handler;
	xtcp_buf_t tx_buf, rx_buf;
};

在tcp_alloc函数中初始化rx_buf

cpp 复制代码
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;
			tcp->remote_win = XTCP_MSS_DEFAULT;
			tcp->remote_mss = XTCP_MSS_DEFAULT;
			tcp->unack_seq = tcp->next_seq = tcp_get_init_seq();
			tcp->ack = 0;
			tcp_buf_init(&tcp->tx_buf);
			tcp_buf_init(&tcp->rx_buf);
			return tcp;
		}
	}

	return (xtcp_t*)0;
}

在http_handler当中测试TCP对于数据的收发功能

cpp 复制代码
static uint8_t rx_buffer[1024];

static xnet_err_t http_handler(xtcp_t* tcp, xtcp_conn_state_t state)
{
	static char* num = "0123456789ABCDEF";

	if (state == XTCP_CONN_CONNECTED)
	{
		printf("http connected.\n");
	}
	else if (state == XTCP_CONN_CLOSED)
	{
		printf("http closed.\n");
	}
	else if (state == XTCP_CONN_DATA_RECV)
	{
		uint8_t* data = rx_buffer;

		uint16_t read_size = xtcp_read(tcp, rx_buffer, sizeof(rx_buffer));
		while (read_size)
		{
			uint16_t curr_size = xtcp_write(tcp, data, read_size);
			data += curr_size;
			read_size -= curr_size;
		}
	}

	return XNET_ERR_OK;
}

xtcp_read函数实现:

cpp 复制代码
uint16_t xtcp_read(xtcp_t* tcp, uint8_t* data, uint16_t size)
{
	return tcp_buf_read(&tcp->rx_buf, data, size);
}

tcp_buf_read函数实现:

cpp 复制代码
static uint16_t tcp_buf_read(xtcp_buf_t* tcp_buf, uint8_t* to, uint16_t size)
{
	int i;

	size = min(size, tcp_buf->data_count);
	for (i = 0; i < size; i++)
	{
		*to++ = tcp_buf->data[tcp_buf->tail++];
		if (tcp_buf->tail >= XTCP_CFG_RTX_BUF_SIZE)
		{
			tcp_buf->tail = 0;
		}
	}
	tcp_buf->data_count -= size;

	return size;
}

在xtcp_in当中添加TCP数据接收部分的处理

1)首先通过tcp_recv函数将packet->data当中的数据读取到接收缓冲区rx_buf

2)收到数据,回复ack,并处理接收的数据

cpp 复制代码
else if (read_size)
{
	tcp_send(tcp, XTCP_FLAG_ACK);
	tcp->handler(tcp, XTCP_CONN_DATA_RECV);
}

完整处理TCP数据接收的代码:

cpp 复制代码
case XTCP_STATE_ESTABLISHED:
	{
		if (tcp_hdr->hdr_flags.flags & (XTCP_FLAG_ACK | XTCP_FLAG_FIN))
		{
			if (tcp_hdr->hdr_flags.flags & XTCP_FLAG_ACK)
			{
				if ((tcp_hdr->ack > tcp->unack_seq) && (tcp_hdr->ack <= tcp->next_seq))
				{
					uint16_t curr_ack_size = tcp_hdr->ack - tcp->unack_seq;
					tcp_buf_add_acked_count(&tcp->tx_buf, curr_ack_size);
					tcp->unack_seq += curr_ack_size;
				}
			}

			read_size = tcp_recv(tcp, (uint8_t*)tcp_hdr->hdr_flags.flags, packet->data, packet->size);

			if (tcp_hdr->hdr_flags.flags & XTCP_FLAG_FIN)
			{
				tcp->state = XTCP_STATE_LAST_ACK;
				tcp->ack++;
				tcp_send(tcp, XTCP_FLAG_FIN | XTCP_FLAG_ACK);
			}
			else if (read_size)
			{
				tcp_send(tcp, XTCP_FLAG_ACK);
				tcp->handler(tcp, XTCP_CONN_DATA_RECV);
			}
			else if (tcp_buf_wait_send_count(&tcp->tx_buf))
			{
				tcp_send(tcp, XTCP_FLAG_ACK);
			}
			
		}
		break;
	}

其中tcp_recv函数实现:

cpp 复制代码
static uint16_t tcp_recv(xtcp_t* tcp, uint8_t flags, uint8_t* from, uint16_t size)
{
	uint16_t read_size = tcp_buf_write(&tcp->rx_buf, from, size);
	tcp->ack += read_size;

	return read_size;
}

最后在tcp_send函数当中,把发送窗口的大小动态调整一下:

cpp 复制代码
tcp_hdr->window = swap_order16(tcp_buf_free_count(&tcp->rx_buf));

三、测试部分

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

相关推荐
极客范儿9 小时前
华为HCIP网络工程师认证—DHCP、NAT和 PPPOE
网络·华为
不会就选b9 小时前
Linux之http会话
服务器·网络协议·http
码匠许师傅9 小时前
【C++三方组件】Asio 下篇:C++20 协程版 TCP 客户端与服务端
c++·tcp/ip·c++20
z20348315209 小时前
计算机网络:网络层(二)——IPv4编址、CIDR与路由选择
网络·计算机网络
ACP广源盛139246256739 小时前
接口适配方案选型|GSV6125@ACP HDMI2.0 转 Type‑C/DP1.4 桥接芯片工程评估
大数据·c语言·开发语言·硬件架构·硬件工程·国产芯片
Etincelle10 小时前
【计算机网络 | 课程自存】【其十】通过ICS共享Internet连接
计算机网络·电脑·ics
z落落10 小时前
C#UDP 广播服务端+客户端
网络·网络协议·udp
gnsnswa10 小时前
回归岗位价值:CAIE 认证适合人群与能力定位
人工智能·网络协议·职场和发展·产品经理·创业创新·信息与通信·ai写作
故乡dee云10 小时前
2026年华为云国际账号开通避坑:IP自动跳转中国站,选错地区只能重新注册
服务器·tcp/ip·华为云
北冥有鱼被烹10 小时前
NVIDIA DGX/HGX 服务器全景深度解析:从 H100 到 GB300,专业算力选型必读
运维·服务器·网络·python