当前位置: 首页 > news >正文

DPDK用户态协议栈-Tcp Posix API 1

和udp一样,我们需要实现和系统调用一样的接口来实现我们的tcp server。先来看看我们之前写的unix_tcp使用了哪些接口,这边我加上两个系统调用,分别是接收数据和发送数据。

#include <stdio.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <string.h>int main(int argc, char* argv) {int sock = socket(AF_INET, SOCK_STREAM, 0);struct sockaddr_in servaddr;servaddr.sin_addr.s_addr = htonl(INADDR_ANY);servaddr.sin_family = AF_INET;servaddr.sin_port = htons(9999);bind(sock, (struct sockaddr*)&servaddr, sizeof(struct sockaddr));listen(sock, 10);struct sockaddr_in clientaddr;socklen_t len = sizeof(clientaddr);char buffer[64] = {0};int fd = accept(sock, (struct sockaddr*)&clientaddr, &len);while (1) {int nb_recv = recv(fd, buffer, 64, 0);if (nb_recv > 0) {printf("tcp recv : %s\n", buffer);send(fd, buffer, nb_recv, 0);memset(buffer, 0, 64);}}return 0;
}
  • socket

https://imagehyj.oss-cn-hangzhou.aliyuncs.com/blog/20240809084354.png

  • bind

https://imagehyj.oss-cn-hangzhou.aliyuncs.com/blog/20240809084428.png

  • listen

https://imagehyj.oss-cn-hangzhou.aliyuncs.com/blog/20240809084444.png

  • accept

https://imagehyj.oss-cn-hangzhou.aliyuncs.com/blog/20240809084509.png

  • recv

https://imagehyj.oss-cn-hangzhou.aliyuncs.com/blog/20240809084532.png

  • send

https://imagehyj.oss-cn-hangzhou.aliyuncs.com/blog/20240809084601.png

tcp的posix实现

bitmap

static struct localhost* get_host_fromfd(int sockfd) {struct localhost* htp = get_lhost_instance();struct localhost* host;for(host = htp; host != NULL; host = host->next) {if (host->fd == sockfd) {return host;}}struct ln_tcp_stream* stream;struct ln_tcp_table* table = get_tcp_table_instance();for(stream = table->streams; stream != NULL; stream = stream->next) {if (stream->fd == sockfd) {return stream;}}return NULL;
}

根据sockfd来搜索对应的控制块(tcp和udp同一个函数)。在之前的udp api实现的过程中实现了一个伪bitmap(后续会完善的)。现在加上了tcp,在函数中加上tcp控制块相关的遍历条件。

tcp server的最后两个状态

static int ln_tcp_handle_close_wait(struct ln_tcp_stream* stream, struct rte_tcp_hdr* tcphdr) {if (tcphdr->tcp_flags & RTE_TCP_FIN_FLAG) {if (stream->status == LN_TCP_STATUS_CLOSE_WAIT) {//}}return 0;
}static int ln_tcp_handle_last_ack(struct ln_tcp_stream* stream, struct rte_tcp_hdr* tcphdr) {if (tcphdr->tcp_flags & RTE_TCP_ACK_FLAG) {if (stream->status == LN_TCP_STATUS_LAST_ACK) {stream->status = LN_TCP_STATUS_CLOSED;struct ln_tcp_table* table = get_tcp_table_instance();LL_REMOVE(stream, table->streams);table->count--;rte_ring_free(stream->recvbuf);rte_ring_free(stream->sendbuf);rte_free(stream);}}return 0;
}

https://imagehyj.oss-cn-hangzhou.aliyuncs.com/blog/20240809100144.png

修改一些之前的API

由于tcp和udp都有创建套接字,绑定等通用的部分,所以我们要在之前写的api上做一些增加和修改,让TCP和UDP都可以使用他们。

socket创建套接字
static struct localhost* get_host_fromip_port(uint32_t ip, uint16_t port, uint8_t proto) {struct localhost* htp = get_lhost_instance();struct localhost* host;for(host = htp; host != NULL; host = host->next) {if (host->localip == ip && host->localport == port && host->protocol == proto) {return host;}}return NULL;
}int nsocket(__attribute__((unused)) int domain, int type, __attribute__((unused)) int protocol) {int fd = get_fd_frombitmap();if (type == SOCK_DGRAM) {struct localhost* host = rte_malloc("localhost", sizeof(struct localhost), 0);if (host == NULL) {return -1;}memset(host, 0, sizeof(struct localhost));host->fd = fd;if (type == SOCK_DGRAM) {host->protocol = IPPROTO_UDP;}host->recvbuf = rte_ring_create("recv buf", RING_SIZE, rte_socket_id(), RING_F_SC_DEQ | RING_F_SP_ENQ);if (host->recvbuf == NULL) {rte_free(host);return -1;}host->sendbuf = rte_ring_create("send buf", RING_SIZE, rte_socket_id(), RING_F_SC_DEQ | RING_F_SP_ENQ);if (host->sendbuf == NULL) {rte_ring_free(host->recvbuf);rte_free(host);return -1;}pthread_cond_t blank_cond = PTHREAD_COND_INITIALIZER;pthread_mutex_t blank_mutex = PTHREAD_MUTEX_INITIALIZER;rte_memcpy(&host->mutex, &blank_mutex, sizeof(pthread_mutex_t));rte_memcpy(&host->cond, &blank_cond, sizeof(pthread_cond_t));struct localhost* lhp = get_lhost_instance();LL_ADD(host, lhp);}else if (type == SOCK_STREAM) {struct ln_tcp_stream* stream = rte_malloc("ln_tcp_stream", sizeof(struct ln_tcp_stream), 0);if (stream == NULL) {return -1;}stream->fd = fd;stream->proto = IPPROTO_TCP;stream->next = stream->prev = NULL;stream->recvbuf = rte_ring_create("tcp recv buf", RING_SIZE, rte_socket_id(), RING_F_SC_DEQ | RING_F_SP_ENQ);if (stream->recvbuf == NULL) {rte_free(stream);return -1;}stream->sendbuf = rte_ring_create("tcp send buf", RING_SIZE, rte_socket_id(), RING_F_SC_DEQ | RING_F_SP_ENQ);if (stream->sendbuf == NULL) {rte_ring_free(stream->sendbuf);rte_free(stream);return -1;}pthread_cond_t blank_cond = PTHREAD_COND_INITIALIZER;pthread_mutex_t blank_mutex = PTHREAD_MUTEX_INITIALIZER;rte_memcpy(&stream->cond, &blank_cond, sizeof(pthread_cond_t));rte_memcpy(&stream->mutex, &blank_mutex, sizeof(pthread_mutex_t));struct ln_tcp_table* table - get_tcp_table_instance();LL_ADD(stream, table->streams);table->count++;}return fd;
}

https://imagehyj.oss-cn-hangzhou.aliyuncs.com/blog/20240813175727.png

bind绑定
int nbind(int sockfd, const struct sockaddr *addr, __attribute__((unused)) socklen_t addrlen) {void* hostinfo = get_host_fromfd(sockfd);if (hostinfo == NULL) {return -1;}struct localhost* host = (struct localhost*)hostinfo;if (host->protocol == IPPROTO_UDP) {if (host == NULL) {return -1;}const struct sockaddr_in* laddr = (const struct sockaddr_in*)addr;host->localport = laddr->sin_port;rte_memcpy(&host->localip, &laddr->sin_addr.s_addr, sizeof(uint32_t));rte_memcpy(host->localmac, nSrcMac, RTE_ETHER_ADDR_LEN);}else {struct ln_tcp_stream* stream = (struct ln_tcp_stream*)hostinfo;const struct sockaddr_in* laddr = (const struct sockaddr_in*)addr;stream->dport = laddr->sin_port;rte_memcpy(&stream->dip, &laddr->sin_addr.s_addr, sizeof(uint32_t));rte_memcpy(&stream->localmac, nSrcMac, RTE_ETHER_ADDR_LEN);stream->status = LN_TCP_STATUS_CLOSED;}return 0;
}
close
int nclose(int fd) {void* hostinfo = get_host_fromfd(fd);if (hostinfo == NULL) {return -1;}struct localhost* host = (struct localhost*)hostinfo;if (host->protocol == IPPROTO_UDP) {struct localhost* lhp = get_lhost_instance();LL_REMOVE(host, lhp);if (host->recvbuf) {rte_ring_free(host->recvbuf);}if (host->sendbuf) {rte_ring_free(host->sendbuf);}rte_free(host);set_fd_frombitmap(fd);}else if (host->protocol == IPPROTO_TCP){struct ln_tcp_stream* stream = (struct ln_tcp_stream*)hostinfo;if (stream->status != LN_TCP_STATUS_LISTEN) {struct ln_tcp_fragment* fragment = rte_malloc("close frag", sizeof(struct ln_tcp_fragment), 0);if (fragment == NULL) {return -1;}memset(fragment, 0, sizeof(struct ln_tcp_stream));fragment->sport = stream->dport;fragment->dport = stream->sport;fragment->acknum = stream->recv_next;fragment->seqnum = stream->recv_next;fragment->windows = LN_TCP_INITIAL_WINDOWS;fragment->hdr_off = 0x50;fragment->tcp_flags = RTE_TCP_FIN_FLAG | RTE_TCP_ACK_FLAG;rte_ring_mp_enqueue(stream->sendbuf, (void*)fragment);stream->status = LN_TCP_STATUS_LAST_ACK;set_fd_frombitmap(fd);}else {struct ln_tcp_table* tb = get_tcp_table_instance();LL_REMOVE(stream, tb->streams);rte_free(stream);}}return 0;
}

tcp的专有API

listen监听
int nlisten(int sockfd, __attribute__((unused))int backlog) {void* hostinfo = get_host_fromfd(sockfd);if (hostinfo == NULL) {return -1;}struct ln_tcp_stream* stream = (struct ln_tcp_stream*)hostinfo;if (stream->proto == IPPROTO_TCP) {stream->status = LN_TCP_STATUS_LISTEN;}return 0;
}
accept建立连接
int naccept(int sockfd, struct sockaddr *addr, __attribute__((unused))socklen_t *addrlen) {void* hostinfo = get_host_fromfd(sockfd);if (hostinfo == NULL) {return -1;}struct ln_tcp_stream* stream = (struct ln_tcp_stream*)hostinfo;if (stream->proto == IPPROTO_TCP) {struct ln_tcp_stream* apt = NULL;pthread_mutex_lock(&stream->mutex);while ((apt = ln_get_accept_stream(stream->dport)) == NULL) {pthread_cond_wait(&stream->cond, &stream->mutex);}pthread_mutex_unlock(&stream->mutex);struct sockaddr_in* addri = (struct sockaddr_in*)addr;addri->sin_port = apt->sport;rte_memcpy(&addri->sin_addr.s_addr, &apt->sip, sizeof(uint32_t));return apt->fd;}return -1;
}

参考资料:https://github.com/0voice

相关文章:

DPDK用户态协议栈-Tcp Posix API 1

和udp一样&#xff0c;我们需要实现和系统调用一样的接口来实现我们的tcp server。先来看看我们之前写的unix_tcp使用了哪些接口&#xff0c;这边我加上两个系统调用&#xff0c;分别是接收数据和发送数据。 #include <stdio.h> #include <arpa/inet.h> #include …...

【人工智能-科普】图神经网络(GNN):与传统神经网络的区别与优势

文章目录 图神经网络(GNN):与传统神经网络的区别与优势什么是图神经网络?图的基本概念GNN的工作原理GNN与传统神经网络的不同1. 数据结构的不同2. 信息传递方式的不同3. 模型的可扩展性4. 局部与全局信息的结合GNN的应用领域总结图神经网络(GNN):与传统神经网络的区别与…...

LabVIEW实现UDP通信

目录 1、UDP通信原理 2、硬件环境部署 3、云端环境部署 4、UDP通信函数 5、程序架构 6、前面板设计 7、程序框图设计 8、测试验证 本专栏以LabVIEW为开发平台,讲解物联网通信组网原理与开发方法,覆盖RS232、TCP、MQTT、蓝牙、Wi-Fi、NB-IoT等协议。 结合实际案例,展示如何利…...

[pdf,epub]228页《分析模式》漫谈合集01-45提供下载

《分析模式》漫谈合集01-45的pdf、epub文件提供下载。已上传至本号的CSDN资源。 如果CSDN资源下载有问题&#xff0c;可到umlchina.com/url/ap.html。 已排版成适合手机阅读&#xff0c;pdf的排版更好一些。 ★UMLChina为什么叒要翻译《分析模式》&#xff1f; ★[缝合故事]…...

Kafka的消费消息是如何传递的?

大家好&#xff0c;我是锋哥。今天分享关于【Kafka的消费消息是如何传递的&#xff1f;】面试题。希望对大家有帮助&#xff1b; Kafka的消费消息是如何传递的&#xff1f; 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 在Kafka中&#xff0c;消息的消费是通过消费…...

二分查找(Java实现)(1)

二分查找&#xff08;Java实现&#xff09;&#xff08;1&#xff09; leetcode 34.排序数组中查找元素第一个和最后一个位置 题目描述: 给你一个按照非递减顺序排列的整数数组 nums&#xff0c;和一个目标值 target。请你找出给定目标值在数组中的开始位置和结束位置。 如…...

力扣103.二叉树的锯齿形层序遍历

题目描述 题目链接103. 二叉树的锯齿形层序遍历 给你二叉树的根节点 root &#xff0c;返回其节点值的 锯齿形层序遍历 。&#xff08;即先从左往右&#xff0c;再从右往左进行下一层遍历&#xff0c;以此类推&#xff0c;层与层之间交替进行&#xff09;。 示例 1&#xff…...

Search with Orama

1.前言 在不久之前&#xff0c;我把 DevNow 的搜索组件通过 Lunr 进行了重构&#xff0c;从前端角度实现了对文章内容的搜索&#xff0c;但是在使用体验上&#xff0c;感觉不是特别好&#xff0c;大概有如下几个原因&#xff1a; 社区的文章数量比较少&#xff0c;项目的 Com…...

一万台服务器用saltstack还是ansible?

一万台服务器用saltstack还是ansible? 选择使用 SaltStack 还是 Ansible 来管理一万台服务器&#xff0c;取决于几个关键因素&#xff0c;如性能、扩展性、易用性、配置管理需求和团队的熟悉度。以下是两者的对比分析&#xff0c;帮助你做出决策&#xff1a; SaltStack&…...

计算机类大厂实习春招秋招开发算法面试问答练习题

计算机类大厂实习春招秋招开发算法面试问答练习题 下面有十个非常重要且常问,面试者却注意不到的问题,我们一个个来看,一个个来学。 线程创建到删除过程中,底层是怎么实现的 1.线程创建 线程创建是线程生命周期的起点。在操作系统中,线程可以通过多种方式创建,但无论哪…...

【热门主题】000068 筑牢网络安全防线:守护数字世界的坚实堡垒

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;今天给大家分享一篇文章&#xff01;并提供具体代码帮助大家深入理解&#xff0c;彻底掌握&#xff01;创作不易&#xff0c;如果能帮助到大家或者给大家一些灵感和启发&#xff0c;欢迎收藏关注哦 &#x1f495; 目录 【热…...

RPC与HTTP调用模式的架构差异

RPC&#xff08;Remote Procedure Call&#xff0c;远程过程调用&#xff09;和 HTTP 调用是两种常见的通信模式&#xff0c;它们在架构上有以下一些主要差异&#xff1a; 协议层面 RPC&#xff1a;通常使用自定义的二进制协议&#xff0c;对数据进行高效的序列化和反序列化&am…...

计算机网络之传输层协议UDP

个人主页&#xff1a;C忠实粉丝 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 C忠实粉丝 原创 计算机网络之传输层协议UDP 收录于专栏【计算机网络】 本专栏旨在分享学习计算机网络的一点学习笔记&#xff0c;欢迎大家在评论区交流讨论&#x1f48c; 目…...

Uniapp 微信小程序内打开web网页

技术栈&#xff1a;Uniapp Vue3 简介 实际业务中有时候会需要在本微信小程序内打开web页面&#xff0c;这时候可以封装一个路由页面专门用于此场景。 在路由跳转的时候携带路由参数&#xff0c;拼接上web url&#xff0c;接收页面进行参数接收即可。 实现 webview页面 新…...

阅读方法论

选择固有缺陷,选项是对比出来的...

373. 查找和最小的 K 对数字

参考的这个博客&#xff1a; https://zhuanlan.zhihu.com/p/457239781 然后看这个代码我想到了另外一种方法&#xff0c;就是一步一步往里加元组 ( i , j ) (i,j) (i,j)&#xff0c;看代码就知道了&#xff0c;不过需要做一步去重&#xff0c;去重不能用 i n t [ ] int[] int…...

常用函数的使用错题汇总

目录 new/delete malloc/free1. 语言和类型2. 内存分配3. 内存释放4. 安全性和类型安全5. 其他特性总结 线程停止文件流 new/delete malloc/free malloc/free 和 new/delete 是 C/C 中用于动态内存管理的两种方式&#xff0c;它们有一些重要的区别。以下是这两种方式的比较&…...

uniapp手机端一些坑记录

关于 z-paging-x 组件&#xff0c;在ios上有时候通过弹窗去粗发它reload时会触发闪退&#xff0c;可能是弹框插入进去导致的DOM 元素已经被移除或者不可用&#xff0c;解决办法是加上他自带属性 :showRefresherWhenReload"true" 加上showRefresherWhe…...

2024学习之前端微信小程序开发教程,从入门到精通-含基础+实战+源码code

目录 一、简单介绍 二、课程需知 三、内容编排 1、小程序基础  起步式 目录结构 小程序框架 场景值  逻辑层 视图层 组件 视图容器 基础内容 表单组件 导航 媒体组件 Api 路由 界面 交互 网络 数据缓存 自定义组件 2、项目实战 …...

netconf 代码架构

NETCONF&#xff08;Network Configuration Protocol&#xff09;是一种基于 XML 的网络配置管理协议&#xff0c;主要用于在网络设备之间进行配置管理、状态监控和操作。它被设计为一种可扩展的协议&#xff0c;并且在自动化网络管理中扮演着重要角色。NETCONF 通过安全的通信…...

【力扣数据库知识手册笔记】索引

索引 索引的优缺点 优点1. 通过创建唯一性索引&#xff0c;可以保证数据库表中每一行数据的唯一性。2. 可以加快数据的检索速度&#xff08;创建索引的主要原因&#xff09;。3. 可以加速表和表之间的连接&#xff0c;实现数据的参考完整性。4. 可以在查询过程中&#xff0c;…...

3.3.1_1 检错编码(奇偶校验码)

从这节课开始&#xff0c;我们会探讨数据链路层的差错控制功能&#xff0c;差错控制功能的主要目标是要发现并且解决一个帧内部的位错误&#xff0c;我们需要使用特殊的编码技术去发现帧内部的位错误&#xff0c;当我们发现位错误之后&#xff0c;通常来说有两种解决方案。第一…...

土地利用/土地覆盖遥感解译与基于CLUE模型未来变化情景预测;从基础到高级,涵盖ArcGIS数据处理、ENVI遥感解译与CLUE模型情景模拟等

&#x1f50d; 土地利用/土地覆盖数据是生态、环境和气象等诸多领域模型的关键输入参数。通过遥感影像解译技术&#xff0c;可以精准获取历史或当前任何一个区域的土地利用/土地覆盖情况。这些数据不仅能够用于评估区域生态环境的变化趋势&#xff0c;还能有效评价重大生态工程…...

Java入门学习详细版(一)

大家好&#xff0c;Java 学习是一个系统学习的过程&#xff0c;核心原则就是“理论 实践 坚持”&#xff0c;并且需循序渐进&#xff0c;不可过于着急&#xff0c;本篇文章推出的这份详细入门学习资料将带大家从零基础开始&#xff0c;逐步掌握 Java 的核心概念和编程技能。 …...

蓝桥杯 冶炼金属

原题目链接 &#x1f527; 冶炼金属转换率推测题解 &#x1f4dc; 原题描述 小蓝有一个神奇的炉子用于将普通金属 O O O 冶炼成为一种特殊金属 X X X。这个炉子有一个属性叫转换率 V V V&#xff0c;是一个正整数&#xff0c;表示每 V V V 个普通金属 O O O 可以冶炼出 …...

Aspose.PDF 限制绕过方案:Java 字节码技术实战分享(仅供学习)

Aspose.PDF 限制绕过方案&#xff1a;Java 字节码技术实战分享&#xff08;仅供学习&#xff09; 一、Aspose.PDF 简介二、说明&#xff08;⚠️仅供学习与研究使用&#xff09;三、技术流程总览四、准备工作1. 下载 Jar 包2. Maven 项目依赖配置 五、字节码修改实现代码&#…...

Java求职者面试指南:Spring、Spring Boot、MyBatis框架与计算机基础问题解析

Java求职者面试指南&#xff1a;Spring、Spring Boot、MyBatis框架与计算机基础问题解析 一、第一轮提问&#xff08;基础概念问题&#xff09; 1. 请解释Spring框架的核心容器是什么&#xff1f;它在Spring中起到什么作用&#xff1f; Spring框架的核心容器是IoC容器&#…...

Java编程之桥接模式

定义 桥接模式&#xff08;Bridge Pattern&#xff09;属于结构型设计模式&#xff0c;它的核心意图是将抽象部分与实现部分分离&#xff0c;使它们可以独立地变化。这种模式通过组合关系来替代继承关系&#xff0c;从而降低了抽象和实现这两个可变维度之间的耦合度。 用例子…...

深度学习水论文:mamba+图像增强

&#x1f9c0;当前视觉领域对高效长序列建模需求激增&#xff0c;对Mamba图像增强这方向的研究自然也逐渐火热。原因在于其高效长程建模&#xff0c;以及动态计算优势&#xff0c;在图像质量提升和细节恢复方面有难以替代的作用。 &#x1f9c0;因此短时间内&#xff0c;就有不…...

MySQL 部分重点知识篇

一、数据库对象 1. 主键 定义 &#xff1a;主键是用于唯一标识表中每一行记录的字段或字段组合。它具有唯一性和非空性特点。 作用 &#xff1a;确保数据的完整性&#xff0c;便于数据的查询和管理。 示例 &#xff1a;在学生信息表中&#xff0c;学号可以作为主键&#xff…...