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 填写.