天天看点

Rasterbar Libtorrent 的简单分析storage_interfacetorrent_handle

  最近在做的一个P2P项目需要使用到一些基础的IO,网络通信的模块,自己写的话短时间内很难达到产品级的健壮性,所以就从现有的开源项目里面抽取模块了,看了看eMule的,这东西和MFC结合紧密,而且整个项目大的可怕,要编译成功都很麻烦,更不要说去抽取它的模块了。不大靠谱。于是就研究了一下LibTorrent,不过这东西有两个。我研究的是Rasterbar的版本。现在的版本是0.15.0。不过这东西整了个openssl的功能。openssl在windows下编译麻烦死了,关键还得装个perl还是python忘了,代码也复杂了。所以我花了点时间把openssl给剥离出去。还好作者写的代码思路清晰,都用宏定义划分了不同功能的分支。

  libtorrent的类结构中最大的一个结构就是alert结构了(点击看大图).

alert

Rasterbar Libtorrent 的简单分析storage_interfacetorrent_handle

  对于外部程序来说,libtorrent的pop_alert()函数正是外部程序用来从libtorrent中获取各种消息、警告、错误等信息的接口。按照官方文档的说明,如果没有任何可用的这些信息的话,就自动返回一个默认构造的auto_ptr对象。由此可见。这个alert的继承树中的各种具体的对象,就分别代表了不同的信息了。对于libtorrent来说,它内部维护了一个alert的队列。此外,libtorrent默认是只保存错误消息的。可以使用set_alert_mask来设置。当然,获得了一个auto_ptr对象的话自然还必须知道具体是哪一个,所以libtorrent就使用alert_cast<>来获得具体的详细类型。alert的具体类型都定义在libtorrent/alert_types.hpp文件中。

  alert的代码是这样的:

class TORRENT_EXPORT alert

{

public:

// only here for backwards compatibility

enum severity_t { debug, info, warning, critical, fatal, none };

enum category_t

{

error_notification = 0x1,

peer_notification = 0x2,

port_mapping_notification = 0x4,

storage_notification = 0x8,

tracker_notification = 0x10,

debug_notification = 0x20,

status_notification = 0x40,

progress_notification = 0x80,

ip_block_notification = 0x100,

performance_warning = 0x200,

dht_notification = 0x400,

stats_notification = 0x800,

all_categories = 0xffffffff

};

alert();

virtual ~alert();

// a timestamp is automatically created in the constructor

ptime timestamp() const;

virtual char const* what() const = 0;

virtual std::string message() const = 0;

virtual int category() const = 0;

#ifndef TORRENT_NO_DEPRECATE

TORRENT_DEPRECATED_PREFIX

severity_t severity() const TORRENT_DEPRECATED { return warning; }

#endif

virtual std::auto_ptr<alert> clone() const = 0;

private:

ptime m_timestamp;

}; 

   关于每个alert的具体描述,官方文档这里有说明。

libtorrent_exception

  libtorrent中的不少函数有两个版本,一个会抛出异常,一个是接受一个引用,返回异常代码。因为直接使用了boost的error code来表示错误,所以结构比较简单。

Rasterbar Libtorrent 的简单分析storage_interfacetorrent_handle

storage_interface

  storage_interface是libtorrent中我最关心的一部分了,这个接口是个纯虚函数,目的是可以让开发者定制特定的种子对应的文件保存位置,默认使用一个代表存储在本地磁盘的文件的实现。storage_interface是基于槽实现的,每个槽有piece_size个字节。所有对磁盘的读写都是基于完整的或者部分的槽。

struct TORRENT_EXPORT storage_interface

{

storage_interface(): m_disk_pool(0), m_settings(0) {}

// create directories and set file sizes

// if allocate_files is true.

// allocate_files is true if allocation mode

// is set to full and sparse files are supported

// false return value indicates an error

virtual bool initialize(bool allocate_files) = 0;

// 此函数在第一次检查(重检查)种子所对应的文件时调用,如果文件已存在应该返回true。

// 并且,这种情况下这个文件已有的片段应该在下载开始前被检查

virtual bool has_any_file() = 0;

// 以下两个函数用于从给定的offset处的给定的slot中读写数据。此方法将连续读写

// num_bufs个buffer的内容,其中每个buffer的大小都将在bufs数组中定义。

// file::iovec_t类型是这样定义的:

// struct iovec_t

// {

// void* iov_base;

// size_t iov_len;

// };

// 返回值则是实际读写的字节数。或者返回-1表示失败。

// 每个bufs中的buffer都能被假定为是按页及页大小对准的,当然,除了种子中的最后一个buffer。

virtual int readv(file::iovec_t const* bufs, int slot, int offset, int num_bufs);

virtual int writev(file::iovec_t const* bufs, int slot, int offset, int num_bufs);

// negative return value indicates an error

virtual int read(char* buf, int slot, int offset, int size) = 0;

// negative return value indicates an error

virtual int write(const char* buf, int slot, int offset, int size) = 0;

virtual size_type physical_offset(int slot, int offset) = 0;

// returns the end of the sparse region the slot 'start'

// resides in i.e. the next slot with content. If start

// is not in a sparse region, start itself is returned

virtual int sparse_end(int start) const { return start; }

// non-zero return value indicates an error

virtual bool move_storage(fs::path save_path) = 0;

// verify storage dependent fast resume entries

virtual bool verify_resume_data(lazy_entry const& rd, error_code& error) = 0;

// write storage dependent fast resume entries

virtual bool write_resume_data(entry& rd) const = 0;

// moves (or copies) the content in src_slot to dst_slot

virtual bool move_slot(int src_slot, int dst_slot) = 0;

// swaps the data in slot1 and slot2

virtual bool swap_slots(int slot1, int slot2) = 0;

// swaps the puts the data in slot1 in slot2, the data in slot2

// in slot3 and the data in slot3 in slot1

virtual bool swap_slots3(int slot1, int slot2, int slot3) = 0;

// this will close all open files that are opened for

// writing. This is called when a torrent has finished

// downloading.

// non-zero return value indicates an error

virtual bool release_files() = 0;

// this will rename the file specified by index.

virtual bool rename_file(int index, std::string const& new_filename) = 0;

// this will close all open files and delete them

// non-zero return value indicates an error

virtual bool delete_files() = 0;

disk_buffer_pool* disk_pool() { return m_disk_pool; }

session_settings const& settings() const { return *m_settings; }

void set_error(boost::filesystem::path const& file, error_code const& ec) const

{

m_error_file = file.string();

m_error = ec;

}

error_code const& error() const { return m_error; }

std::string const& error_file() const { return m_error_file; }

void clear_error() { m_error = error_code(); m_error_file.clear(); }

mutable error_code m_error;

mutable std::string m_error_file;

virtual ~storage_interface() {}

disk_buffer_pool* m_disk_pool;

session_settings* m_settings;

}; 

  文件是分片了,但是关于文件分片在程序中的读取优先级,则主要在torrent_handle中处理

torrent_handle

torrent_handle中对文件下载顺序影响最大的一个函数就是set_piece_deadline()函数了,这个函数给每个片段设置一个截止期限,libtorrent会在截止期限终止之前去尝试下载这个片段.而piece_priority() prioritize_pieces() piece_priorities()则设置了每个片段的优先级(注意是和其available有关的).