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

- bind

- listen

- accept

- recv

- send

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;
}

修改一些之前的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;
}

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一样,我们需要实现和系统调用一样的接口来实现我们的tcp server。先来看看我们之前写的unix_tcp使用了哪些接口,这边我加上两个系统调用,分别是接收数据和发送数据。 #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资源下载有问题,可到umlchina.com/url/ap.html。 已排版成适合手机阅读,pdf的排版更好一些。 ★UMLChina为什么叒要翻译《分析模式》? ★[缝合故事]…...
Kafka的消费消息是如何传递的?
大家好,我是锋哥。今天分享关于【Kafka的消费消息是如何传递的?】面试题。希望对大家有帮助; Kafka的消费消息是如何传递的? 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 在Kafka中,消息的消费是通过消费…...
二分查找(Java实现)(1)
二分查找(Java实现)(1) leetcode 34.排序数组中查找元素第一个和最后一个位置 题目描述: 给你一个按照非递减顺序排列的整数数组 nums,和一个目标值 target。请你找出给定目标值在数组中的开始位置和结束位置。 如…...
力扣103.二叉树的锯齿形层序遍历
题目描述 题目链接103. 二叉树的锯齿形层序遍历 给你二叉树的根节点 root ,返回其节点值的 锯齿形层序遍历 。(即先从左往右,再从右往左进行下一层遍历,以此类推,层与层之间交替进行)。 示例 1ÿ…...
Search with Orama
1.前言 在不久之前,我把 DevNow 的搜索组件通过 Lunr 进行了重构,从前端角度实现了对文章内容的搜索,但是在使用体验上,感觉不是特别好,大概有如下几个原因: 社区的文章数量比较少,项目的 Com…...
一万台服务器用saltstack还是ansible?
一万台服务器用saltstack还是ansible? 选择使用 SaltStack 还是 Ansible 来管理一万台服务器,取决于几个关键因素,如性能、扩展性、易用性、配置管理需求和团队的熟悉度。以下是两者的对比分析,帮助你做出决策: SaltStack&…...
计算机类大厂实习春招秋招开发算法面试问答练习题
计算机类大厂实习春招秋招开发算法面试问答练习题 下面有十个非常重要且常问,面试者却注意不到的问题,我们一个个来看,一个个来学。 线程创建到删除过程中,底层是怎么实现的 1.线程创建 线程创建是线程生命周期的起点。在操作系统中,线程可以通过多种方式创建,但无论哪…...
【热门主题】000068 筑牢网络安全防线:守护数字世界的坚实堡垒
前言:哈喽,大家好,今天给大家分享一篇文章!并提供具体代码帮助大家深入理解,彻底掌握!创作不易,如果能帮助到大家或者给大家一些灵感和启发,欢迎收藏关注哦 💕 目录 【热…...
RPC与HTTP调用模式的架构差异
RPC(Remote Procedure Call,远程过程调用)和 HTTP 调用是两种常见的通信模式,它们在架构上有以下一些主要差异: 协议层面 RPC:通常使用自定义的二进制协议,对数据进行高效的序列化和反序列化&am…...
计算机网络之传输层协议UDP
个人主页:C忠实粉丝 欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 C忠实粉丝 原创 计算机网络之传输层协议UDP 收录于专栏【计算机网络】 本专栏旨在分享学习计算机网络的一点学习笔记,欢迎大家在评论区交流讨论💌 目…...
Uniapp 微信小程序内打开web网页
技术栈:Uniapp Vue3 简介 实际业务中有时候会需要在本微信小程序内打开web页面,这时候可以封装一个路由页面专门用于此场景。 在路由跳转的时候携带路由参数,拼接上web url,接收页面进行参数接收即可。 实现 webview页面 新…...
阅读方法论
选择固有缺陷,选项是对比出来的...
373. 查找和最小的 K 对数字
参考的这个博客: https://zhuanlan.zhihu.com/p/457239781 然后看这个代码我想到了另外一种方法,就是一步一步往里加元组 ( i , j ) (i,j) (i,j),看代码就知道了,不过需要做一步去重,去重不能用 i n t [ ] int[] int…...
常用函数的使用错题汇总
目录 new/delete malloc/free1. 语言和类型2. 内存分配3. 内存释放4. 安全性和类型安全5. 其他特性总结 线程停止文件流 new/delete malloc/free malloc/free 和 new/delete 是 C/C 中用于动态内存管理的两种方式,它们有一些重要的区别。以下是这两种方式的比较&…...
uniapp手机端一些坑记录
关于 z-paging-x 组件,在ios上有时候通过弹窗去粗发它reload时会触发闪退,可能是弹框插入进去导致的DOM 元素已经被移除或者不可用,解决办法是加上他自带属性 :showRefresherWhenReload"true" 加上showRefresherWhe…...
2024学习之前端微信小程序开发教程,从入门到精通-含基础+实战+源码code
目录 一、简单介绍 二、课程需知 三、内容编排 1、小程序基础 起步式 目录结构 小程序框架 场景值 逻辑层 视图层 组件 视图容器 基础内容 表单组件 导航 媒体组件 Api 路由 界面 交互 网络 数据缓存 自定义组件 2、项目实战 …...
netconf 代码架构
NETCONF(Network Configuration Protocol)是一种基于 XML 的网络配置管理协议,主要用于在网络设备之间进行配置管理、状态监控和操作。它被设计为一种可扩展的协议,并且在自动化网络管理中扮演着重要角色。NETCONF 通过安全的通信…...
linux之kylin系统nginx的安装
一、nginx的作用 1.可做高性能的web服务器 直接处理静态资源(HTML/CSS/图片等),响应速度远超传统服务器类似apache支持高并发连接 2.反向代理服务器 隐藏后端服务器IP地址,提高安全性 3.负载均衡服务器 支持多种策略分发流量…...
工业安全零事故的智能守护者:一体化AI智能安防平台
前言: 通过AI视觉技术,为船厂提供全面的安全监控解决方案,涵盖交通违规检测、起重机轨道安全、非法入侵检测、盗窃防范、安全规范执行监控等多个方面,能够实现对应负责人反馈机制,并最终实现数据的统计报表。提升船厂…...
iPhone密码忘记了办?iPhoneUnlocker,iPhone解锁工具Aiseesoft iPhone Unlocker 高级注册版分享
平时用 iPhone 的时候,难免会碰到解锁的麻烦事。比如密码忘了、人脸识别 / 指纹识别突然不灵,或者买了二手 iPhone 却被原来的 iCloud 账号锁住,这时候就需要靠谱的解锁工具来帮忙了。Aiseesoft iPhone Unlocker 就是专门解决这些问题的软件&…...
剑指offer20_链表中环的入口节点
链表中环的入口节点 给定一个链表,若其中包含环,则输出环的入口节点。 若其中不包含环,则输出null。 数据范围 节点 val 值取值范围 [ 1 , 1000 ] [1,1000] [1,1000]。 节点 val 值各不相同。 链表长度 [ 0 , 500 ] [0,500] [0,500]。 …...
从零实现STL哈希容器:unordered_map/unordered_set封装详解
本篇文章是对C学习的STL哈希容器自主实现部分的学习分享 希望也能为你带来些帮助~ 那咱们废话不多说,直接开始吧! 一、源码结构分析 1. SGISTL30实现剖析 // hash_set核心结构 template <class Value, class HashFcn, ...> class hash_set {ty…...
DBAPI如何优雅的获取单条数据
API如何优雅的获取单条数据 案例一 对于查询类API,查询的是单条数据,比如根据主键ID查询用户信息,sql如下: select id, name, age from user where id #{id}API默认返回的数据格式是多条的,如下: {&qu…...
网络编程(UDP编程)
思维导图 UDP基础编程(单播) 1.流程图 服务器:短信的接收方 创建套接字 (socket)-----------------------------------------》有手机指定网络信息-----------------------------------------------》有号码绑定套接字 (bind)--------------…...
Java多线程实现之Thread类深度解析
Java多线程实现之Thread类深度解析 一、多线程基础概念1.1 什么是线程1.2 多线程的优势1.3 Java多线程模型 二、Thread类的基本结构与构造函数2.1 Thread类的继承关系2.2 构造函数 三、创建和启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程 四、Thread类的核心…...
零基础在实践中学习网络安全-皮卡丘靶场(第九期-Unsafe Fileupload模块)(yakit方式)
本期内容并不是很难,相信大家会学的很愉快,当然对于有后端基础的朋友来说,本期内容更加容易了解,当然没有基础的也别担心,本期内容会详细解释有关内容 本期用到的软件:yakit(因为经过之前好多期…...
《C++ 模板》
目录 函数模板 类模板 非类型模板参数 模板特化 函数模板特化 类模板的特化 模板,就像一个模具,里面可以将不同类型的材料做成一个形状,其分为函数模板和类模板。 函数模板 函数模板可以简化函数重载的代码。格式:templa…...
