一、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,今天的你就到此为止吧,明天还要接着🐺啊!