资讯动态

dpdk实现tcp回显

发布时间:2026/10/20 10:45:48 来源:尧图企业网站定制
在ESTABLISHED状态双方发送数据时候不管是客户端还是服务端发送数据后对方都需要回复一个ack。这个ack可以是单独的包也可以和需要发送的数据包放在一起发送。我们需要实现的是回显那么接收到客户端的数据后需要组织三个包第一个包是接收客户端的数据第二个包是构造ack第三个包是构造发送的数据包。全面梳理ackseq的流程。两个结构体tcp_socket_entrytcp_datagram一个全局变量tcp_table。struct tcp_socket_entry{ int fd; //unsigned int status; // 阻塞 非阻塞 uint32_t dip; uint32_t sip; uint16_t dport; uint16_t sport; uint8_t localmac[RTE_ETHER_ADDR_LEN]; uint8_t protocol; uint32_t seq_next; uint32_t ack_next; NG_TCP_STATUS status; struct rte_ring *recvbuf; struct rte_ring *sendbuf; struct tcp_socket_entry *prev; struct tcp_socket_entry *next; pthread_cond_t cond; pthread_mutex_t mutex; }; struct tcp_table{ struct tcp_socket_entry *tcpList; int count; }; struct tcp_datagram{ uint16_t sport; uint16_t dport; uint32_t seqnum; uint32_t acknum; uint8_t hdrlen_off; // 高四位头部长度 低四位保留位 uint8_t tcp_flags; uint16_t windows; uint16_t cksum; uint16_t tcp_urp; // 紧急指针 /* 头部长度 4bit 最大为15. 1bit代表4Byte 所以tcp头最多15*460Byte 前面固定20B,选项最多40B uint32 4B TCP_OPTION_LENGTH10 正好40B */ int optlen; // 表示option的真实长度 uint32_t option[TCP_OPTION_LENGTH]; unsigned char *data; int datalenth; };tcp_socket_entry是面向连接的一个连接一个tcp_socket_entry里面有两个参数uint32_t seq_next;uint32_t ack_next;存储的是下一次发送所需要的ackseq。tcp_datagram是组织tcp数据包用的里面也有两个参数uint32_t seqnum;uint32_t acknum;里面存储的是这一次组织数据包需要的seq和ack。在tcp pkt process时根据sip,dip,sport,dport查找entry如果没有就创建一个entry指明seq_next为一个随机数。// 返回时间戳秒,距离UTC1970 uint32_t seqnum time(NULL); entry-seq_next rand_r(seqnum) % TCP_MAX_SEQ;在listen时候再设置ack_nextntohl(tcphdr-sent_seq) 1;在listen的时候也需要组织数据包这里指定datatcp-seqnum entrytcp-seq_next; datatcp-acknum ntohl(tcphdr-sent_seq) 1;因为客户端发来一个syn所以要回复这里的acknum对方的seq1因为syn占用一个序号。但是对于tcphdr-sent_seq是需要转换字节序的。在组织服务端ack包时有如下代码。printf(tcp_handle_established\n); printf(entrytcp-ack_next: %u, entrytcp-seq_next %u\n, entrytcp-ack_next,entrytcp-seq_next); printf(tcphdr-sent_seq: %u, ntohs(tcphdr-sent_seq):%u\n,tcphdr-sent_seq, ntohl(tcphdr-sent_seq)); printf(tcphdr-recv_ack: %u, ntohs(tcphdr-recv_ack):%u\n,tcphdr-recv_ack, ntohl(tcphdr-recv_ack)); entrytcp-ack_next entrytcp-ack_next payloadlen; entrytcp-seq_next ntohl(tcphdr-recv_ack); ackdata-seqnum entrytcp-seq_next; ackdata-acknum entrytcp-ack_next; printf(ackdata-seqnum: %u, ackdata-acknum :%u\n,ackdata-seqnum, ackdata-acknum ); tcp_handle_established entrytcp-ack_next: 2835143939, entrytcp-seq_next 146615313 tcphdr-sent_seq: 64879784, ntohl(tcphdr-sent_seq):2835143939 tcphdr-recv_ack: 825015560, ntohl(tcphdr-recv_ack):146615345 ackdata-seqnum: 146615345, ackdata-acknum :2835143971可以看出entrytcp-ack_next ntohl(tcphdr-sent_seq)与上文设置的ack_next正好相符。entrytcp-seq_next ntohl(tcphdr-recv_ack)entrytcp-ack_next ntohl(tcphdr-sent_seq)payloadlen; // entrytcp-ack_next entrytcp-ack_next payloadlen;两条语句都可以。判断接收的数据包合不合法时就可以通过判断源ntohl(tcphdr-sent_seq)与entrytcp-ack_next是不是相等来判断相等则合法。本端ack 对端seq对端发送的数据长度。entrytcp-ack_next ntohl(tcphdr-sent_seq)payloadlen;本端seq 对端的ack。entrytcp-seq_next ntohl(tcphdr-recv_ack);对端的seq 与 本端的上一次发送的ack相等。entrytcp-ack_next ntohl(tcphdr-sent_seq)组织的接收数据用的recvdata加入entrytcp的recvbuf。组织ack包的时候需要更新entrytcp的ack_next与seq_next。然后把组织好的数据包加入entrytcp的sendbuf。组织的发送数据的包的ack与seq和ack包的这两个参数相等。因为ACK不占用序号。然后加入到sendbuf。static int fun_tcp_handle_established_rcvd(struct tcp_socket_entry* entrytcp,struct rte_tcp_hdr * tcphdr,int tcplen){ if(tcphdr-tcp_flags RTE_TCP_SYN_FLAG){ } if(tcphdr-tcp_flags RTE_TCP_PSH_FLAG){ /****************************** recv datagram ******************************/ struct tcp_datagram *recvdata rte_malloc(tcp recv datagram,sizeof(struct tcp_datagram),0); if(recvdata NULL){ rte_exit(EXIT_FAILURE,tcp recv datagram malloc fail\n); } memset(recvdata,0,sizeof(struct tcp_datagram)); recvdata-sport ntohs(tcphdr-src_port); recvdata-dport ntohs(tcphdr-dst_port); uint8_t hdrlen tcphdr-data_off 4; // payload有效载荷,协议中的数据部分 int payloadlen tcplen - hdrlen*4; if(payloadlen 0){ uint8_t *payload (uint8_t *)tcphdr hdrlen * 4; recvdata-data rte_malloc(tcp recv data,payloadlen1,0); if(recvdata-data NULL){ rte_free(recvdata); rte_exit(EXIT_FAILURE,recv data malloc fail\n); } memset(recvdata-data,0,payloadlen1); rte_memcpy(recvdata-data,payload,payloadlen); recvdata-datalenth payloadlen; printf(tcp recv data:%s len:%d\n,recvdata-data,payloadlen); } rte_ring_mp_enqueue(entrytcp-recvbuf,recvdata); /****************************** ack datagram ******************************/ struct tcp_datagram *ackdata rte_malloc(tcp ack data,sizeof(struct tcp_datagram),0); if(ackdata NULL){ rte_exit(EXIT_FAILURE,tcp ack data malloc fail\n); } memset(ackdata,0,sizeof(struct tcp_datagram)); ackdata-sport tcphdr-dst_port; ackdata-dport tcphdr-src_port; printf(tcp_handle_established\n); printf(entrytcp-ack_next: %u, entrytcp-seq_next %u\n, entrytcp-ack_next,entrytcp-seq_next); printf(tcphdr-sent_seq: %u, ntohl(tcphdr-sent_seq):%u\n,tcphdr-sent_seq, ntohl(tcphdr-sent_seq)); printf(tcphdr-recv_ack: %u, ntohl(tcphdr-recv_ack):%u\n,tcphdr-recv_ack, ntohl(tcphdr-recv_ack)); entrytcp-ack_next ntohl(tcphdr-sent_seq)payloadlen; // entrytcp-ack_next entrytcp-ack_next payloadlen; entrytcp-seq_next ntohl(tcphdr-recv_ack); ackdata-seqnum entrytcp-seq_next; ackdata-acknum entrytcp-ack_next; printf(ackdata-seqnum: %u, ackdata-acknum :%u\n,ackdata-seqnum, ackdata-acknum ); ackdata-hdrlen_off 0x50; ackdata-tcp_flags RTE_TCP_ACK_FLAG; ackdata-windows TCP_INITIAL_WINDOW; ackdata-data NULL; ackdata-datalenth 0; rte_ring_mp_enqueue(entrytcp-sendbuf,ackdata); /****************************** send datagram ******************************/ struct tcp_datagram *senddata rte_malloc(tcp send data,sizeof(struct tcp_datagram),0); if(senddata NULL){ rte_exit(EXIT_FAILURE,tcp send data malloc fail\n); } memset(senddata,0,sizeof(struct tcp_datagram)); senddata-sport tcphdr-dst_port; senddata-dport tcphdr-src_port; senddata-seqnum entrytcp-seq_next; senddata-acknum entrytcp-ack_next; senddata-hdrlen_off 0x50; senddata-tcp_flags RTE_TCP_ACK_FLAG | RTE_TCP_PSH_FLAG; senddata-windows TCP_INITIAL_WINDOW; uint8_t *payload (uint8_t *)tcphdr hdrlen * 4; senddata-data rte_malloc(tcp send data,payloadlen1,0); if(senddata-data NULL){ rte_free(senddata); rte_exit(EXIT_FAILURE,recv data malloc fail\n); } memset(senddata-data,0,payloadlen1); rte_memcpy(senddata-data,payload,payloadlen); senddata-datalenth payloadlen; printf(tcp recv data:%s\n,senddata-data); rte_ring_mp_enqueue(entrytcp-sendbuf,senddata); } if(tcphdr-tcp_flags RTE_TCP_ACK_FLAG){ } if(tcphdr-tcp_flags RTE_TCP_FIN_FLAG){ } return 0; }文章参考零声教育的C/Clinux服务期高级架构系统教程学习:0voice · GitHub

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑