<?xml version="1.0" encoding="utf-8" ?><rss version="2.0"><channel><title><![CDATA[hfhfhz的博客]]></title><description><![CDATA[]]></description><link>https://blog.youkuaiyun.com/hfhfhz</link><language>zh-cn</language><generator>https://blog.youkuaiyun.com/</generator><copyright><![CDATA[Copyright &copy; hfhfhz]]></copyright><item><title><![CDATA[Linux学习笔记12.2： kv 存储]]></title><link>https://blog.youkuaiyun.com/hfhfhz/article/details/151875222</link><guid>https://blog.youkuaiyun.com/hfhfhz/article/details/151875222</guid><author>hfhfhz</author><pubDate>Sat, 20 Sep 2025 08:30:00 +0800</pubDate><description><![CDATA[本文介绍了KV存储服务器协议解析部分的实现过程，主要包括：1) 定义请求格式和命令枚举；2) 实现字符串分割函数用于解析请求；3) 设计协议处理模块，根据命令类型执行相应操作并生成响应；4) 整合KV引擎初始化与网络I/O管理，使用Reactor模式处理客户端请求。文章详细说明了从请求解析到命令执行、响应返回的完整流程，并提到后续可改进的方向如使用红黑树或哈希实现KV引擎，以及采用Proactor模式替代Reactor。]]></description><category></category></item><item><title><![CDATA[Linux学习笔记12.1：kv存储]]></title><link>https://blog.youkuaiyun.com/hfhfhz/article/details/151867335</link><guid>https://blog.youkuaiyun.com/hfhfhz/article/details/151867335</guid><author>hfhfhz</author><pubDate>Fri, 19 Sep 2025 18:16:01 +0800</pubDate><description><![CDATA[本文介绍了基于顺序数组和哈希表两种数据结构实现的KV存储引擎。KV存储是一种高性能的键值对数据库模型，通过简单的键值映射实现快速数据访问。文章首先展示了基于数组的实现，包括数据结构定义、创建销毁、查找、插入、修改和删除等核心操作。随后简要介绍了更高效的哈希表实现方式，包括哈希函数设计、节点创建和冲突处理方法。这两种实现方式对比展示了KV存储引擎的基本原理，为后续学习更复杂的存储系统奠定了基础。]]></description><category></category></item><item><title><![CDATA[Linux学习笔记11：异步io]]></title><link>https://blog.youkuaiyun.com/hfhfhz/article/details/151788113</link><guid>https://blog.youkuaiyun.com/hfhfhz/article/details/151788113</guid><author>hfhfhz</author><pubDate>Wed, 17 Sep 2025 16:22:48 +0800</pubDate><description><![CDATA[本文介绍了Linux内核中的高性能异步I/O接口io_uring的实现原理和使用方法。io_uring通过共享内存环形缓冲区(SQ和CQ)减少系统调用和数据拷贝，实现高效异步I/O。文章详细讲解了如何利用io_uring构建TCP服务器，包括事件类型定义、服务器初始化、读写事件注册等关键步骤，并展示了通过批量处理完成队列条目来提高性能的方法。代码示例演示了如何实现接受连接、数据读取和发送回传的完整流程。]]></description><category></category></item><item><title><![CDATA[Linux学习笔记10：协程]]></title><link>https://blog.youkuaiyun.com/hfhfhz/article/details/151765237</link><guid>https://blog.youkuaiyun.com/hfhfhz/article/details/151765237</guid><author>hfhfhz</author><pubDate>Wed, 17 Sep 2025 10:53:53 +0800</pubDate><description><![CDATA[以下是 main 函数的实现，也是调度器。简单描述一个调度流程即为：main 函数中第一次调用 swapcontext 时会切换到 ctx[0] 的上下文（即 func1 函数），在 func1 函数中运行到 swapcontext(&ctx[0], &main_ctx) 时会重新回到上次 main 运行到的位置，而当 main 函数第 n 次调用 swapcontext  第二次切换到 ctx[0] 保存的上下文（func1）时，会从 swapcontext(&ctx[0], &main_ctx);]]></description><category></category></item><item><title><![CDATA[Linux学习笔记9：基于 KCP 协议的服务器]]></title><link>https://blog.youkuaiyun.com/hfhfhz/article/details/151268311</link><guid>https://blog.youkuaiyun.com/hfhfhz/article/details/151268311</guid><author>hfhfhz</author><pubDate>Sun, 07 Sep 2025 10:56:24 +0800</pubDate><description><![CDATA[为这样一个流程：调用 recvfrom接收数据包–>调用 ikcp_input 将数据发送给 KCP 协议进行解析–>调用 ikcp_recv 从 KCP 协议中提取排序好的数据–>调用 ikcp_send 将响应数据发送给客户端。需要注意的是，ikcp_update 是 KCP 协议中的一个关键函数，它会更新 KCP 控制块中的当前时间，并计算从上次刷新到现在的逝去时间。后续作为用户数据与 KCP 控制块关联。定义一个KCP协议的输出回调函数，用于将KCP协议生成的数据包通过UDP发送到客户端地址。]]></description><category></category></item><item><title><![CDATA[Linux学习笔记8：Posix API]]></title><link>https://blog.youkuaiyun.com/hfhfhz/article/details/151249340</link><guid>https://blog.youkuaiyun.com/hfhfhz/article/details/151249340</guid><author>hfhfhz</author><pubDate>Sat, 06 Sep 2025 13:53:10 +0800</pubDate><description><![CDATA[需要说明的是，每个数据包的序列号是初始序列号加上该数据包在数据流中的位置，用于确保数据包的顺序和完整性，防止数据包出现重复和乱序问题。这个包的 SYN 和 ACK 位都被设置为 1，表示服务器已经收到客户端的连接请求，并且确认了客户端的初始序列号（ACK number）。这个包的 ACK 位被设置为 1，表示客户端确认了服务器的 SYN-ACK 包。接受一个连接请求，即检查全连接队列是否有待处理的连接，若存在待处理的连接，从其中取出一个连接并创建一个新的 fd ，并将 fd 与对应连接进行映射。]]></description><category></category></item><item><title><![CDATA[Linux学习笔记7：Reactor 模式的网络服务器]]></title><link>https://blog.youkuaiyun.com/hfhfhz/article/details/151236444</link><guid>https://blog.youkuaiyun.com/hfhfhz/article/details/151236444</guid><author>hfhfhz</author><pubDate>Sat, 06 Sep 2025 08:00:00 +0800</pubDate><description><![CDATA[创建接受回调函数（accept，用于获取接入的客户端的fd），接收回调函数（recv，接收来自客户端的数据），发送回调函数（send，向客户端发送数据）。需要强调的是，由于 EPOLLIN 事件实际上会对应两种状况，一种为 sockfd（监听套接字） 触发了可读事件（即有客户端接入，此时应调用 accept_cb），另一种为客户端建立连接后发送数据触发可读事件（应调用recv_cb）。事件设置函数，使用epoll监视fd，将fd注册到epoll实例中，并设置所关注的事件。]]></description><category></category></item><item><title><![CDATA[Linux学习笔记6：TCP服务器]]></title><link>https://blog.youkuaiyun.com/hfhfhz/article/details/150990974</link><guid>https://blog.youkuaiyun.com/hfhfhz/article/details/150990974</guid><author>hfhfhz</author><pubDate>Fri, 29 Aug 2025 17:47:05 +0800</pubDate><description><![CDATA[接着遍历就绪事件，如果监听套接字 sockfd 发生事件（即有连接接入），调用 accept 接受客户端连接，其中client_addr 用于存储客户端地址 ，然后将将客户端文件描述符添加到 epoll 监控列表中（epoll_ctl），监听可读事件，并启用边缘触发模式（即有数据传入就会触发）。如果当前事件不是监听套接字事件，表示是某个客户端文件描述符上的事件（即客户端有数据传入），使用 recv 函数从客户端文件描述符 clientfd 读取数据，存储到 buffer 中，并将数据打印出来。]]></description><category></category></item><item><title><![CDATA[Linux学习笔记5：http请求]]></title><link>https://blog.youkuaiyun.com/hfhfhz/article/details/150989288</link><guid>https://blog.youkuaiyun.com/hfhfhz/article/details/150989288</guid><author>hfhfhz</author><pubDate>Fri, 29 Aug 2025 17:10:14 +0800</pubDate><description><![CDATA[最后如果套接字刻度（即有数据了），使用 recv 接收数据，同时动态分配内存以存储响应内容（realloc 保留原有内存的情况下追加内存空间），并将接收到的数据追加到结果中（strncat 会自动从末尾追加数据）。调用 connect 将套接字连接到指定的地址，并调用 fcntl 设置套接字为非阻塞模式，参数 O_NONBLOCK 表示非阻塞模式。首先需要将将主机名解析为IP地址，传入主机名，使用 gethostbyname 函数将主机名解析为IP地址，返回的是一个指向包含主机名解析信息的结构体的指针。]]></description><category></category></item><item><title><![CDATA[Linux学习笔记4：DNS协议和请求]]></title><link>https://blog.youkuaiyun.com/hfhfhz/article/details/150983972</link><guid>https://blog.youkuaiyun.com/hfhfhz/article/details/150983972</guid><author>hfhfhz</author><pubDate>Fri, 29 Aug 2025 16:18:50 +0800</pubDate><description><![CDATA[DNS报文有固定的形式，如下所示，其中主要包含 Header（头部）、Question（问题部分）、Answer（回答部分）、Authority（权威部分）和 Additional（附加信息部分）共五个部分。而问题部分包含 name（查询名）、type（查询类型）、class（查询类），其中查询名的长度是不固定的，查询名即为要查询的域名，例如 www.example.com，写入查询名中的内容应为 3www7example3com0，数字x表示后面跟着的有x个字母，最后以0结尾。]]></description><category></category></item><item><title><![CDATA[Linux学习笔记3：实现一个线程池]]></title><link>https://blog.youkuaiyun.com/hfhfhz/article/details/150978474</link><guid>https://blog.youkuaiyun.com/hfhfhz/article/details/150978474</guid><author>hfhfhz</author><pubDate>Fri, 29 Aug 2025 13:51:33 +0800</pubDate><description><![CDATA[然后要创建数量为 numWorkers 的工作线程，首先初始化 worker ，设置 manager 指向线程池（线程池就是任务和工作线程的管理者），接着调用 pthread_create 创建线程，创建的线程的 id 会自动存入 worker->threadid 中，nThreadPoolCallback 即之前定义的线程回调函数，worker 为传入回调函数的变量。线程池应中包含任务队列、工作者线程、条件变量（cond）和互斥锁（mutex），线程池用于管理任务和线程。至此，线程学习初步完成。]]></description><category></category></item><item><title><![CDATA[Linux学习笔记2：实现通讯录]]></title><link>https://blog.youkuaiyun.com/hfhfhz/article/details/150967309</link><guid>https://blog.youkuaiyun.com/hfhfhz/article/details/150967309</guid><author>hfhfhz</author><pubDate>Fri, 29 Aug 2025 02:38:49 +0800</pubDate><description><![CDATA[需要注意的点为使用了指向指针的指针（**ppeople）接收了指向联系人链表头部指针的指针，这是因为在LIST_INSERT 中会涉及头部指针变量本身的赋值操作，使用 *ppeople 即可对指针变量原本的内容进行修改。如果 item 不是链表头部节点，则将它的前向节点的 next 指针指向 item 的后向节点，从而跳过 item这个节点；搜索联系人，对链表进行遍历，每次循环调用 strcmp 对传入的联系人姓名和当前链表节点存储的联系人姓名进行比较，如果相等返回0，表示找到了对应的存储节点。]]></description><category></category></item><item><title><![CDATA[Linux学习笔记1：统计文本单词数量]]></title><link>https://blog.youkuaiyun.com/hfhfhz/article/details/150964650</link><guid>https://blog.youkuaiyun.com/hfhfhz/article/details/150964650</guid><author>hfhfhz</author><pubDate>Fri, 29 Aug 2025 01:12:45 +0800</pubDate><description><![CDATA[使用状态机思想计算文本单词数量，当遇到分割符（如 ‘,’，空格）表示当前不在单词中（OUT），如果当前不在单词中且遇到非分隔符（IN），说明进入了一个新单词，单词计数加一（当状态从 OUT → IN 转变时，说明遇到一个新单词）。首先需要打开文件，返回一个 文件指针 fp，指向一个FILE 结构体（里面保存文件缓冲区、文件描述符等信息），可以通过该指针操作文件。批量读取，buf存放读取内容，'1’表示每个元素的字节数为1，也就是你想把文件内容分成多大的“块”来读写，sizeof(buf)为读取的元素个数。]]></description><category></category></item></channel></rss>