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 通过安全的通信…...
R语言AI模型部署方案:精准离线运行详解
R语言AI模型部署方案:精准离线运行详解 一、项目概述 本文将构建一个完整的R语言AI部署解决方案,实现鸢尾花分类模型的训练、保存、离线部署和预测功能。核心特点: 100%离线运行能力自包含环境依赖生产级错误处理跨平台兼容性模型版本管理# 文件结构说明 Iris_AI_Deployme…...
【Linux】C语言执行shell指令
在C语言中执行Shell指令 在C语言中,有几种方法可以执行Shell指令: 1. 使用system()函数 这是最简单的方法,包含在stdlib.h头文件中: #include <stdlib.h>int main() {system("ls -l"); // 执行ls -l命令retu…...
mongodb源码分析session执行handleRequest命令find过程
mongo/transport/service_state_machine.cpp已经分析startSession创建ASIOSession过程,并且验证connection是否超过限制ASIOSession和connection是循环接受客户端命令,把数据流转换成Message,状态转变流程是:State::Created 》 St…...
【HTTP三个基础问题】
面试官您好!HTTP是超文本传输协议,是互联网上客户端和服务器之间传输超文本数据(比如文字、图片、音频、视频等)的核心协议,当前互联网应用最广泛的版本是HTTP1.1,它基于经典的C/S模型,也就是客…...
Linux nano命令的基本使用
参考资料 GNU nanoを使いこなすnano基础 目录 一. 简介二. 文件打开2.1 普通方式打开文件2.2 只读方式打开文件 三. 文件查看3.1 打开文件时,显示行号3.2 翻页查看 四. 文件编辑4.1 Ctrl K 复制 和 Ctrl U 粘贴4.2 Alt/Esc U 撤回 五. 文件保存与退出5.1 Ctrl …...
负载均衡器》》LVS、Nginx、HAproxy 区别
虚拟主机 先4,后7...
13.10 LangGraph多轮对话系统实战:Ollama私有部署+情感识别优化全解析
LangGraph多轮对话系统实战:Ollama私有部署+情感识别优化全解析 LanguageMentor 对话式训练系统架构与实现 关键词:多轮对话系统设计、场景化提示工程、情感识别优化、LangGraph 状态管理、Ollama 私有化部署 1. 对话训练系统技术架构 采用四层架构实现高扩展性的对话训练…...
2025 后端自学UNIAPP【项目实战:旅游项目】7、景点详情页面【完结】
1、获取景点详情的请求【my_api.js】 // 引入公共的请求封装 import http from ./my_http.js// 登录接口(适配服务端返回 Token) export const login async (code, avatar) > {const res await http(/login/getWXSessionKey, {code,avatar}); };//…...
Python爬虫(52)Scrapy-Redis分布式爬虫架构实战:IP代理池深度集成与跨地域数据采集
目录 一、引言:当爬虫遭遇"地域封锁"二、背景解析:分布式爬虫的两大技术挑战1. 传统Scrapy架构的局限性2. 地域限制的三种典型表现 三、架构设计:Scrapy-Redis 代理池的协同机制1. 分布式架构拓扑图2. 核心组件协同流程 四、技术实…...
SQLSERVER-DB操作记录
在SQL Server中,将查询结果放入一张新表可以通过几种方法实现。 方法1:使用SELECT INTO语句 SELECT INTO 语句可以直接将查询结果作为一个新表创建出来。这个新表的结构(包括列名和数据类型)将与查询结果匹配。 SELECT * INTO 新…...
