一个简单的BitTorrent客户端实现(六):peer manager和peer实现
来源:互联网 发布:sql嵌套select语句 编辑:程序博客网 时间:2024/06/08 01:18
peer manager和peer
peer是整个BT通信中最复杂的部分,主要是里面各种消息的发送和一些choke和unchoke策略,piece选择策略等等。peer manager用于管理peer,本程序中维护多个peer进行远程通信。
peer实现
本程序中peer是由CPeerLink类实现的。CPeerLink类中某些重要成员说明如下:
m_bAmChoking:我是否阻塞peer,true表示choke,否则unchoke。
m_bAmInterested:我是否对peer感兴趣,true表示感兴趣,否则不感兴趣。
m_bPeerChoking:peer是否阻塞我,true表示choke,否则unchoke。
m_bPeerInterested:peer是否对我感兴趣,true表示感兴趣,否则不感兴趣。
m_clPieceRequest:保存了我向peer请求的某个piece详情。
m_lstPeerPieceRequest:保存了peer向我请求的piece详情。
整个peer的通信流程如下:
(1)连接peer,并将其套接字加入到同步事件分离器的监视的描述符集中供其监视。
void CPeerLink::Connect(const char *IpAddr, int nPort){ CSocket::CreateTCPSocket(); CSocket::SetReactor(m_pPeerManager->GetTorrentTask()->GetSocketReactor()); m_strIPAddr = IpAddr; m_nPort = nPort; CSocket::SetHandleMask(WRITE_MASK); CSocket::Connect(IpAddr, nPort); m_nPeerState = PS_CONNECTING; m_nConnTimeoutID = GetReactor()->AddTimer(this, 10000, true);}
(2)同步事件分离器不断的轮询描述符集。
nRet = select(m_nMaxSocketFd + 1, &m_rSet, &m_wSet, NULL, &tmval);
(3)同步事件分离器检测到套接字可写,表示已经连接peer成功。调用并设置套接字可读,也就是将套接字加入到读描述符集中。
if (FD_ISSET((*it)->GetHandle(), &m_wSet)) { int nRes = (*it)->HandleWrite(); if (nRes == -1) { (*it)->HandleClose(); (*it)->SetReactor(NULL); (*it)->Close(); continue; } }
int CPeerLink::HandleWrite(){ if (m_nPeerState == PS_CONNECTING) { m_nPeerState = PS_ESTABLISHED; RemoveHandleMask(WRITE_MASK); OnConnect(); return 0; } m_bCanWrite = true; return 0;}void CPeerLink::OnConnect(){ SetHandleMask(READ_MASK); m_strSendBuffer.clear(); m_strRecvBuffer.clear(); m_bHandShaked = false; m_clPieceRequest.CreatePieceRequestList(-1, 0, 0); m_bAmChoking = true; m_bAmInterested = false; m_bPeerChoking = true; m_bPeerInterested = false; m_nDownloadCount = 0; m_nUploadCount = 0; m_nLastDownloadCount = 0; m_nLastUploadCount = 0; m_nLastUploadCount = 0; m_nDownloadSpeed = 0; m_nUploadSpeed = 0; m_llLastCountSpeedTime = GetTickCount(); m_bCanRead = false; m_bCanWrite = true; m_pPeerManager->GetTorrentTask()->GetRateMeasure()->AddClient(this); SendHandShake();}
(4)发送handshake消息。
void CPeerLink::SendHandShake(){ char szBuff[68]; memset(szBuff, 0, sizeof(szBuff)); szBuff[0] = 19; strncpy(szBuff + 1, "BitTorrent protocol", 19); strncpy(szBuff + 28, (const char *) m_pPeerManager->GetTorrentTask()->GetTorrentFile()->GetInfoHash(), 20); strncpy(szBuff + 48, (const char *) m_pPeerManager->GetTorrentTask()->GetPeerID().c_str(), 20); SendData(szBuff, sizeof(szBuff));}
(5)同步事件分离器监测到套接字可读,处理各种消息,如handshake、choke、unchoke、piece等等。
if (FD_ISSET((*it)->GetHandle(), &m_rSet)) { int nRes = (*it)->HandleRead(); if (nRes == -1) { (*it)->HandleClose(); (*it)->SetReactor(NULL); (*it)->Close(); continue; } }
int CPeerLink::DoRead(long long llCount){ int nReadCount = 0; char *pBuff = new char[RECV_BUFFER_SIZE]; for (; nReadCount < llCount;) { int nReadSize = RECV_BUFFER_SIZE; if (nReadSize > llCount - nReadCount) { nReadSize = llCount - nReadCount; } int nRet = recv(GetHandle(), pBuff, nReadSize, 0); if (nRet == 0) { CloseLink(); delete[] pBuff; return nReadCount; } if (nRet == -1) { if (errno == EAGAIN) { m_bCanRead = false; break; } if (errno == EINTR) { continue; } CloseLink(); delete[] pBuff; return nReadCount; } if (nRet > 0) { nReadCount += nRet; m_nDownloadCount += nRet; m_pPeerManager->GetTorrentTask()->AddDownloadCount(nRet); m_strRecvBuffer.append((const char *) pBuff, nRet); } } delete[] pBuff; ProcRecvData(); if (m_bCanRead) { if (GetHandleMask() & READ_MASK) { RemoveHandleMask(READ_MASK); } } else { if (!(GetHandleMask() & READ_MASK)) { SetHandleMask(READ_MASK); } } return nReadCount;}
关于消息的处理,以request消息为例进行介绍:
request:
int CPeerLink::ProcCmdRequest(void *pData, int nDataLen){ if (nDataLen != 12) { return -1; } if (m_bAmChoking) { return 0; } int nIndex = *((int *) pData); nIndex = ntohl(nIndex); int nOffset = *((int *) ((char *) pData + 4)); nOffset = ntohl(nOffset); int nLen = *((int *) ((char *) pData + 8)); nLen = ntohl(nLen); list<PeerPieceRequest>::iterator it = m_lstPeerPieceRequest.begin(); for (; it != m_lstPeerPieceRequest.end(); ++it) { if (it->nIndex == nIndex && it->nOffset == nOffset) { break; } } if (it == m_lstPeerPieceRequest.end()) { PeerPieceRequest stRequst; stRequst.nIndex = nIndex; stRequst.nOffset = nOffset; stRequst.nLen = nLen; m_lstPeerPieceRequest.push_back(stRequst); } DoPieceSend(); return 0;}
这里使用m_lstPeerPieceRequest来保存peer已请求的piece,每次收到该消息后,将其保存下来。便于后面发送数据。如果消息已经发送或者收到peer发送来的cancel消息,则移除该项。
peer manager实现
peer manager由CPeerManager类实现,主要做了以下两件事情:
(1)启动时添加两个定时器,一个用于检查peer的连接状况。另一个用于choke和unchoke peer。
bool CPeerManager::Startup(){ pthread_mutexattr_t attr; pthread_mutexattr_init(&attr); pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE_NP); pthread_mutex_init(&m_MutexUnusedPeer, &attr); pthread_mutexattr_destroy(&attr); m_nConnectTimerID = m_pTorrentTask->GetSocketReactor()->AddTimer(this, 2000, false); m_nChokeTimerID = m_pTorrentTask->GetSocketReactor()->AddTimer(this, 10000, false); return true;}
(2)添加peer到peer列表中。
void CPeerManager::AddPeerInfo(const char *pIpAddr, int nPort){ string strPeerLinkID = GenPeerLinkID(pIpAddr, nPort); if (PeerExists(strPeerLinkID)) { return; } PeerInfo stPeerInfo; stPeerInfo.strLinkID = strPeerLinkID; stPeerInfo.strIPAddr = pIpAddr; stPeerInfo.nPort = nPort; stPeerInfo.pPeerLink = NULL; pthread_mutex_lock(&m_MutexUnusedPeer); m_mapUnusedPeer[strPeerLinkID] = stPeerInfo; pthread_mutex_unlock(&m_MutexUnusedPeer);}
peer和peer manager的介绍就到此为止,大家可以去看看代码。写得比较简单,也不算很复杂的。
- 一个简单的BitTorrent客户端实现(六):peer manager和peer实现
- 一个简单的BitTorrent客户端实现(五):tracker manager和tracker实现
- 一个简单的BitTorrent客户端实现(四):PeerAcceptor实现
- 一个简单的BitTorrent客户端实现(一):概述
- Peer管理模块的设计和实现
- Peer管理模块的设计和实现
- 一个简单的BitTorrent客户端实现(二):种子文件解析及信息保存
- 一个简单的BitTorrent客户端实现(三):同步事件分离器
- OpenVPN关于push-peer-info的实现
- Linux平台下基于BitTorrent应用层协议的下载软件开发--peer模块(peer.c)
- Linux平台下基于BitTorrent应用层协议的下载软件开发--peer模块(peer.h)
- 通过smack client + openfire server 实现 peer to peer communication
- Linux BT下载(16)-与peer交换数据模块的设计和实现
- BitTorrent协议标准之Peer状态
- (一)Peer的安装
- Linux平台下基于BitTorrent应用层协议的下载软件开发--peer交互模块(torrent.c)
- Linux平台下基于BitTorrent应用层协议的下载软件开发--peer交互模块(torrent.h)
- Peer.js Based Video Share Among Connected Peers (基于Peer.js实现的对等端间视频共享)
- Git配置SSH非默认端口(22)
- C语言学习之数组及指针
- Android Bluetooth蓝牙开发:Bluetooth蓝牙设备之间数据传输(4)
- anible包模块管理
- dp[组号][个数] 模型
- 一个简单的BitTorrent客户端实现(六):peer manager和peer实现
- 应用程序池“*******”将被自动禁用,原因是为此应用程序池提供服务的进程中出现一系列错误
- Android实现一个记住密码的登陆界面
- 流苏岛之雾失楼
- HBase 在HDFS 上的目录树
- LeetCode(7) - Reverse Integer
- android资源目录---assets与res/raw区别
- Windows2008 R2下,DCOM配置里的属性灰色不可用的解决方法
- eclipse中安装mybatis快捷进入插件