|
SimpleTorrent
|
顶层驱动模块 更多...
#include "butil.h"#include "util.h"#include "peer.h"#include "connect.h"#include <string.h>#include <assert.h>#include <unistd.h>#include <errno.h>#include <sys/epoll.h>#include <arpa/inet.h>#include <sys/timerfd.h>
宏定义 | |
| #define | BUF_SIZE 4096 |
| 报文缓冲区大小 | |
函数 | |
| void | send_handshake (int sfd, struct MetaInfo *mi) |
| 发送握手信息 | |
| void | send_msg_to_tracker (struct MetaInfo *mi, struct Tracker *tracker, const char *event) |
| int | select_piece (struct MetaInfo *mi, struct PeerMsg *msg) |
| 选择需要请求的分片 更多... | |
| struct Peer * | select_peer (struct MetaInfo *mi, struct PeerMsg *msg) |
| 选择可以发送请求的 peer 更多... | |
| void | send_request (struct MetaInfo *mi, struct Peer *peer, struct PeerMsg *msg) |
| 向 peer 发送分片请求,同时更新 peer 和对应子分片的大小 更多... | |
| void | handle_piece (struct MetaInfo *mi, struct Peer *peer, struct PeerMsg *msg) |
| 处理分片消息 更多... | |
| void | handle_msg (struct MetaInfo *mi, struct Peer *peer, struct PeerMsg *msg) |
| 处理 BT 消息 更多... | |
| struct BNode * | handle_tracker_response (int sfd) |
| 处理 tracker 响应的 HTTP 报文,将解析后的语法树返回给上层使用,在内部关闭套接字 更多... | |
| void | handle_peer_list (struct MetaInfo *mi, int efd, struct BNode *bcode) |
| 将 tracker 返回的 peers 异步 connect 并加入 epoll 队列 更多... | |
| void | handle_interval (struct Tracker *tracker, struct BNode *bcode, int efd) |
| 提取 interval 信息并设置定时 更多... | |
| void | handle_error (struct MetaInfo *mi, int error_fd) |
| 处理出错套接字 更多... | |
| void | handle_ready (struct MetaInfo *mi, int sfd) |
| 执行连接建立后的相关操作 更多... | |
| int | finish_handshake (struct MetaInfo *mi, int sfd) |
| 完成握手消息的处理 更多... | |
| void | bt_handler (struct MetaInfo *mi, int efd) |
| 处理所有网络报文 更多... | |
| char * | get_torrent_data_from_file (const char *torrent) |
| 将种子文件完全载入内存 更多... | |
| int | main (int argc, char *argv[]) |
| 入口函数,完成种子文件的解析,全局信息的生成以及进入消息处理逻辑。 | |
顶层驱动模块
| void bt_handler | ( | struct MetaInfo * | mi, |
| int | efd | ||
| ) |
处理所有网络报文
使用 epoll 侦听各个描述符的事件,根据事件属性和描述符的所属采取相应的操作。 主要涉及的描述符类型:
目前只对 peer 的 bt 消息做异步接受,其他报文基本要求同步地完全接受。
最多每 5s 处理一次发送报文的逻辑。目前来看可能出现 write 写满导致的阻塞。
| mi | 种子文件元信息 |
| efd | epoll file descriptor |

| int finish_handshake | ( | struct MetaInfo * | mi, |
| int | sfd | ||
| ) |
| char* get_torrent_data_from_file | ( | const char * | torrent | ) |
将种子文件完全载入内存
| torrent | 种子文件名 |

| void handle_error | ( | struct MetaInfo * | mi, |
| int | error_fd | ||
| ) |
处理出错套接字
程序所使用的描述符主要有两种:socket fd 和 timer fd.
这里的错误处理逻辑针对 socket fd. Timer fd 相对来说并不那么容易出错。 函数会首先判断套接字是 tracker 的还是 peer 的,以输出错误信息并更新对应的队列。
| mi | 全局信息 |
| error_fd | 出错的套接字 |

提取 interval 信息并设置定时
| tracker | 指向发送响应的 tracker |
| bcode | 指向解析后的 B 编码语法树 |
| efd | epoll file descriptor,用于加入 timer fd |

将 tracker 返回的 peers 异步 connect 并加入 epoll 队列
| mi | 全局信息 |
| efd | epoll 描述符 |
| bcode | B 编码数据 |

处理分片消息
收到分片消息后,期望调用者处理字节序。 会将子分片写入到对应的分片文件中,如果一个子分片已经被写入过,则抛弃。 出于简单实现的考虑,子分片采取固定大小,使用位图管理完成进度, 最后一个分片不会在这里进行特殊处理,由发送过程保证最后一个分片长度的正确性。
在这里结算一个子分片的下载速度。

| void handle_ready | ( | struct MetaInfo * | mi, |
| int | sfd | ||
| ) |
执行连接建立后的相关操作
与 tracker 和 peer 通过 connect 方式建立连接后(相对的,还有通过 accept 与 peer 建立连接的情形), 按照协议要求,要主动发送消息(HTTP 请求,握手)。 本函数首先根据套接字确定套接字所属的对象,然后发送对应的消息。
| mi | 全局信息 |
| sfd | 连接套接字 |

| struct BNode* handle_tracker_response | ( | int | sfd | ) |
处理 tracker 响应的 HTTP 报文,将解析后的语法树返回给上层使用,在内部关闭套接字
考虑到 tracker 的响应数据量不大,内部全部使用 recv + MSG_WAITALL 防止 read 读取不足。
| sfd | 与 tracker 的连接套接字 |

选择可以发送请求的 peer
msg 不要转换字节序

选择需要请求的分片
采取最简单的前面的先下载策略。 使用输出参数 msg 是因为这种 msg 一般都是栈上生成的,用完就丢。
| mi | 全局信息 |
| msg | 要发送的请求 |

向 tracker 发送 HTTP GET 请求. 可以通过 event 指定发送的具体时间, 其余信息完全通过 mi 填写.

1.8.11