【FileZilla】sftp协议的数据传输上传和下载
基于前面两篇及B站上大牛小方的解析视频:
【1】【Filezilla】 dispatch函数重载的例子-CSDN博客
【2】【C++】【FileZilla】事件调用机制代码解析-CSDN博客
当线程entry()调用process_event()时,通过语句 (*std::get<0>(ev0))(*std::get<1>(ev0))调用operator 方法,当元组 ev0 的第零个元素 event_handler 类型匹配 CSftpControlSocket 时,语句调用重载的 CSftpControlSocket::operator() ,元组 ev0 的第一个元素 event_base 作为形参 ev传入operator(参考【2】),而当 ev 的实际类型匹配 CSftpEvent 时,实际调用下面重载的分发方法中的CSftpControlSocket::OnSftpEvent(参考【1】)。元组 ev 第零个元素的实际类型还有可能是 process_event, CCommandEvent等。
// In event_loop.hpp
typedef std::deque<std::tuple<event_handler*, event_base*, bool>> Events;// Events::value_type ev{};// In sftpcontrolsocket.cpp
void CSftpControlSocket::operator()(fz::event_base const& ev)
{if (fz::dispatch<fz::process_event, CSftpEvent, CSftpListEvent, SftpRateAvailableEvent>(ev, this,&CSftpControlSocket::OnProcessEvent,&CSftpControlSocket::OnSftpEvent,&CSftpControlSocket::OnSftpListEvent,&CSftpControlSocket::OnQuotaRequest)) {return;}CControlSocket::operator()(ev);
}
关注CSftpControlSocket::OnSftpEvent()方法:
void CSftpControlSocket::OnSftpEvent(sftp_message const& message)
{......switch (message.type){......case sftpEvent::Recv:......break;case sftpEvent::Send:......break;case sftpEvent::Transfer:......break;case sftpEvent::io_nextbuf:if (!operations_.empty() && operations_.back()->opId == Command::transfer) {auto & data = static_cast<CSftpFileTransferOpData&>(*operations_.back());data.OnNextBufferRequested(fz::to_integral<uint64_t>(message.text[0]));}break;case sftpEvent::io_open:if (!operations_.empty() && operations_.back()->opId == Command::transfer) {auto & data = static_cast<CSftpFileTransferOpData&>(*operations_.back());data.OnOpenRequested(fz::to_integral<uint64_t>(message.text[0]));}break;case sftpEvent::io_size:if (!operations_.empty() && operations_.back()->opId == Command::transfer) {auto & data = static_cast<CSftpFileTransferOpData&>(*operations_.back());data.OnSizeRequested();}break;case sftpEvent::io_finalize:if (!operations_.empty() && operations_.back()->opId == Command::transfer) {auto & data = static_cast<CSftpFileTransferOpData&>(*operations_.back());data.OnFinalizeRequested(fz::to_integral<uint64_t>(message.text[0]));}break;default:......}......
}
可以注意到其中 case sftpEvent::io_nextbuf 处理了数据的传输。
- 上传:std::tie(r, buffer_) = reader_->get_buffer(*this);
- 下载:auto r = writer_->add_buffer(std::move(buffer_), *this);
void CSftpFileTransferOpData::OnNextBufferRequested(uint64_t processed)
{if (reader_) {fz::aio_result r;std::tie(r, buffer_) = reader_->get_buffer(*this);if (r == fz::aio_result::wait) {return;}if (r == fz::aio_result::error) {controlSocket_.AddToSendBuffer("--1\n");return;}if (buffer_->size()) {controlSocket_.AddToSendBuffer(fz::sprintf("-%d %d\n", buffer_->get() - base_address_, buffer_->size()));}else {controlSocket_.AddToSendBuffer(fz::sprintf("-0\n"));}}else if (writer_) {buffer_->resize(processed);auto r = writer_->add_buffer(std::move(buffer_), *this);if (r == fz::aio_result::ok) {buffer_ = controlSocket_.buffer_pool_->get_buffer(*this);if (!buffer_) {r = fz::aio_result::wait;}}if (r == fz::aio_result::wait) {return;}if (r == fz::aio_result::error) {controlSocket_.AddToSendBuffer("--1\n");return;}controlSocket_.AddToSendBuffer(fz::sprintf("-%d %d\n", buffer_->get() - base_address_, buffer_->capacity()));}else {controlSocket_.AddToSendBuffer("--1\n");return;}
}