Linux C 笔记:BT 项目结构分析 By pluvet 2019年4月22日2020年5月1日 正文 入口函数 入口函数 命令行参数检查 命令行参数检查 设置信号处理的回调函数 设置信号处理的回调函数 set_signal_handler [Not supported by viewer] 对于 SIGPIPE 直接忽略 [Not supported by viewer] 对于中断信号(SIGINT) 和终止信号(SIGTERM) 移交给 process_signal 处理 [Not supported by viewer] 解析 torrent 文件 解析 torrent 文件 初始化未阻塞 peers 初始化未阻塞 peers 创建下载文件 创建下载文件 创建位图 创建位图 创建缓冲 创建缓冲 数据传输 数据传输 收尾工作 收尾工作 退出 退出 process_signal process_signal <br> 直接进行收尾工作 直接进行收尾工作 信号处理模块 信号处理模块 parse_metafile [Not supported by viewer] 读取种子文件到内存 <div><span>读取种子文件到内存</span></div> 获取tracker服务器的地址 <div><span>获取tracker服务器的地址</span></div> 判断是否为多文件种子 <div><span>判断是否为多文件种子</span></div> 获取每个piece的长度 <div><span> 获取每个piece的长度</span></div> 读取各个piece的哈希值 <div><span>读取各个piece的哈希值</span></div> 获取要下载的文件名(或者目录名) <div><span>获取要下载的文件名(或者目录名)</span></div> (多文件种子)获取各个待下载的文件路径和文件长度 <div><span>(多文件种子)获取各个待下载的文件路径和文件长度</span></div> 获取待下载的文件的总长度 <div><span>获取待下载的文件的总长度</span></div> 获得info_hash [Not supported by viewer] 生成peer_id [Not supported by viewer] 种子解析模块 种子解析模块 初始化全局变量unchoke_peers <div><span>初始化全局变量unchoke_peers</span></div> create_files [Not supported by viewer] 获取种子中待下载文件的个数 <div><span>获取种子中待下载文件的个数</span></div> 为每个文件申请描述符 <div>为每个文件申请描述符</div> 否 否 是 是 多文件 多文件 创建与下载文件大小相等的文件并写入空字符 [Not supported by viewer] 创建(多级)目录 <div>创建(多级)目录</div> 遍历链表,创建各个所需文件,并写入空字符 <div>遍历链表,创建各个所需文件,并写入空字符</div> 为 bitmap 结构初始化 为 bitmap 结构初始化 create_bitfield [Not supported by viewer] 是 是 全新下载 全新下载 设置位图的各位为0 设置位图的各位为0 读取现有位图 读取现有位图 设定正确的值给download_piece_num <div><span>设定正确的值给download_piece_num</span></div> 实现了断点续传 实现了断点续传 create_btcache [Not supported by viewer] 1024(缓冲节点数量)次 for 循环 <div><span>1024(缓冲节点数量)次 for 循环</span></div> 初始化当前缓冲节点 <div>初始化当前缓冲节点</div> 循环 循环 连接该节点与下一个节点 <div>连接该节点与下一个节点</div> 连接该节点与下一个节点 <div>连接该节点与下一个节点</div> 初始化最后一个 piece 的缓存空间和index <div>初始化最后一个 piece 的缓存空间和index</div> initialize_btcache_node <div><span>initialize_btcache_node</span></div> 为节点分配内存 <div>为节点分配内存</div> 为节点的 buff 分配内存 <div>为节点的 buff 分配内存</div> 初始化结构体的其它值 <div>初始化结构体的其它值</div> 文件预备模块 文件预备模块 位图管理模块 位图管理模块 缓冲管理模块 缓冲管理模块 download_upload_with_peers <div><span>download_upload_with_peers</span></div> 局部变量初始化 局部变量初始化 进入主循环 进入主循环 每隔10秒重新选择非阻塞peer <div><span>每隔10秒重新选择非阻塞peer</span></div> 每隔30秒重新选择可选非阻塞peer <div><span>每隔30秒重新选择可选非阻塞peer</span></div> 计算各个peer的下载、上传速度 <div><span>计算各个peer的下载、上传速度</span></div> 选择非阻塞的peer <div><span>选择非阻塞的peer</span></div> 将那些在过去10秒已断开连接而又处于unchoke队列中的peer清除出unchoke队列 [Not supported by viewer] 将那些在过去10秒上传速度超过20KB/S而下载速度过小的peer强行阻塞 <div><span>将那些在过去10秒上传速度超过20KB/S而下载速度过小的peer强行阻塞</span></div> 从当前所有Peer中选出下载速度最快的四个peer <div><span>从当前所有Peer中选出下载速度最快的四个peer</span></div> 更新 peer [Not supported by viewer] 对peer的状态值重新赋值 <div><span>对peer的状态值重新赋值</span></div> 创建choke、unchoke消息 <div><span>创建choke、unchoke消息</span></div> create_chock_interested_msg <div><span>create_chock_interested_msg</span></div> select_optunchoke_peer <div><span>select_optunchoke_peer</span></div> 每隔5分钟 或当前peer数为0 连接tracker [Not supported by viewer] 如果要连接新的peer <div><span>如果要连接新的peer</span></div> 创建套接字,向peer发出连接请求 <div><span>创建套接字,向peer发出连接请求</span></div> 状态更新为连接中 <div>状态更新为连接中</div> 开始连接时间改为现在 开始连接时间改为现在 用 FD_ZERO 初始化(清空) 套接字集合 [Not supported by viewer] 如果状态为连接中 <div>如果状态为连接中</div> 将连接tracker的socket加入到待监视的集合中 <div><span>将连接tracker的socket加入到待监视的集合中</span></div> 如果连接tracker超过10秒,则终止连接tracker <div><span>如果连接tracker超过10秒,则终止连接tracker</span></div> 否则连接各个 tracker <div>否则连接各个 <span>tracker</span></div> 如果状态为连接tracker结束 <div>如果状态为连接<span>tracker结束</span></div> 与peer建立连接 <div><span>与peer建立连接</span></div> clear_connect_tracker <div><span>clear_connect_tracker</span></div> 清理连接的 tracker 数量为 0 <div>清理连接的 tracker 数量为 0</div> clear_tracker_response <div><span>clear_tracker_response</span></div> 设置 response_len 为零 <div>设置 <span>response_len 为零</span></div> 设置 response_index 为零 [Not supported by viewer] 如果peer_addr_head不为空,说明可以建立peer链接 设置 connect_peer = -1 [Not supported by viewer] 否则 connect_tracker =1; [Not supported by viewer] 将peer的socket成员加入到待监视的集合中 <div><span>将peer的socket成员加入到待监视的集合中</span></div> 遍历 peer 的链表,初始化各个 socket <div><span>遍历 peer 的链表,初始化各个 socket</span></div> 遍历 peer 的链表,初始化各个 socket <div><span>遍历 peer 的链表,初始化各个 socket</span></div> 设置 select函数的超时时间 <div>设置 <span>select函数的超时时间</span></div> 对各个读写set 进行 select,等待请求到来 <div>对各个读写set 进行 select,等待请求到来</div> 请求到来,执行prepare_ send_have_msg [Not supported by viewer] 向所有的peer发送have消息 <div><span>向所有的peer发送have消息</span></div> 遍历各个 peer 遍历各个 peer 如果状态为未关闭,且为rset <div><span>如果状态为未关闭,且为rset</span></div> 接收消息 [Not supported by viewer] 成功则解析所有的消息 <div><span>成功则解析所有的消息</span></div> 如果状态为未关闭,且为wset <div><span>如果状态为未关闭,且为wset</span></div> 发送各种消息 <div>发送各种消息</div> 如果正在与tracker服务器相连 <div><span>如果正在与tracker服务器相连</span></div> 对于每个 tracker <div>对于每个 tracker</div> 如果建立好了套接字,但是还没有连接 <div><span>如果建立好了套接字,但是还没有连接</span></div> 尝试 getsockopt 获取套接字选项 [Not supported by viewer] 如果已经成功建立了连接 <div><span>如果</span><span>已经成功建立了连接</span></div> 构建 tracker服务器的地址链表 构建 <span>tracker服务器的地址链表</span> 向tracker服务器发送请求消息 <div><span>向tracker服务器发送请求消息</span></div> 如果需要状态主机从tracker服务器中得到数据 [Not supported by viewer] 读取并处理数据 <div>读取并处理数据</div> 如果正在与 peer 建立连接 [Not supported by viewer] 遍历各个 peer <div>遍历各个 peer</div> getsockopt [Not supported by viewer] 添加 peer 到 peer 链表 <div>添加 peer 到 peer 链表</div> 对处于CLOSING状态的peer,将其从peer队列中删除 [Not supported by viewer] 下载完毕的检测 下载完毕的检测 数据传输和消息通信模块 数据传输和消息通信模块 致谢 感谢 Sky,July,Aspire 的帮助。否则我难以短时间掌握这样一个大的系统的原理。