P2PClient.h
上传用户:liguizhu
上传日期:2015-11-01
资源大小:2422k
文件大小:8k
源码类别:

P2P编程

开发平台:

Visual C++

  1. /*
  2.  *  Openmysee
  3.  *
  4.  *  This program is free software; you can redistribute it and/or modify
  5.  *  it under the terms of the GNU General Public License as published by
  6.  *  the Free Software Foundation; either version 2 of the License, or
  7.  *  (at your option) any later version.
  8.  *
  9.  *  This program is distributed in the hope that it will be useful,
  10.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.  *  GNU General Public License for more details.
  13.  *
  14.  *  You should have received a copy of the GNU General Public License
  15.  *  along with this program; if not, write to the Free Software
  16.  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  17.  *
  18.  */
  19. #pragma once
  20. namespace NPLayer1 {
  21. class Communicator;
  22. enum {
  23. // P2P 缓冲区的大小,比BLOCK稍大
  24. P2P_BUF_SIZE = BLOCK_SIZE+1024, 
  25. };
  26. // TCP传输的数据包
  27. class TCPPacket {
  28. public:
  29. TCPPacket() : size(0), sent(0) {};
  30. ~TCPPacket() {};
  31. char GetMsgType() {return buf[4];};
  32. UINT* GetBlockID() {return reinterpret_cast<UINT*>(buf+5);};
  33. UINT* GetBlockSize() {return reinterpret_cast<UINT*>(buf+9);};
  34. void Init() {};
  35. void Uninit() {};
  36. char buf[P2P_BUF_SIZE];
  37. // 要发送的消息大小
  38. int size;
  39. // 已经发送的大小
  40. int sent;
  41. };
  42. enum MSG_STATE {
  43. MSG_COMPLETE, MSG_UNCOMPLETE, MSG_ERR_SIZE, MSG_ERR_TYPE, 
  44. MSG_DIFF_CHNL, MSG_NOMORE_CONS, MSG_ERR_LIST_SIZE, 
  45. MSG_SEND_ERR, MSG_SAVEDATA_ERR, MSG_UNMATCH_BLOCKID, 
  46. MSG_NOSUCH_RES_HERE, MSG_REMOTE_ERR, MSG_CHNL_CLOSED, 
  47. MSG_NOSUCH_RES_SP, MSG_CHNL_END, MSG_LOW_VERSION
  48. };
  49. // 正在连接的Peer
  50. class P2PClient : public TransferCalculator {
  51. public:
  52. P2PClient();
  53. virtual ~P2PClient();
  54. bool IsValid() { return valid;};
  55. BOOL SetValid(Communicator*, const ConnectingPeer& peer);
  56. void SetInvalid();
  57. BOOL SendHello();
  58. BOOL SendSPUpdate(const SPUpdate& spUpdate, UINT8 selfLayer, BYTE sum);
  59. BOOL SendReport(const CorePeerInfo&, bool bRefresh);
  60. BOOL SendNearPeers();
  61. BOOL SendReqMedia(UINT blockID);
  62. BOOL IsIdleTooLong();
  63. BOOL BaseRecv();
  64.     // 清除发送媒体类型区间的记录
  65.     void ClearSentMediaArray() {sentMediaArray.Clear();};
  66. // 发送push列表中的第一个块
  67. BOOL SendFirstPushBlock();
  68. // 查找连接对方是否有此块
  69. bool FindRemoteBlock(const UINT blockID) const {
  70. return remoteInterval.FindBlock(blockID);
  71. };
  72. bool AddPushBlock(UINT blockID, bool bRefreshing); // 添加一个PushList中的块
  73. bool FindPushBlock(const UINT blockID) const; // 查找一个PushList中的块
  74. bool DelPushBlock(UINT blockID); // 删除一个PushList中的块
  75. bool IsPushListFull(); // Push List是否已满
  76. UINT8 GetTotalPushSize(); // 取得Pushlist大小
  77. void ClearPush(); // 清空PushList
  78. void SendPush(); // 发送整个PushList,因为之前重新分配了所有连接的块
  79. void ReloadPushList(); // 重新加载PushList,只有在普通的下载时才会被调用
  80. // 获取第一个Packet进行发送
  81. void GetPacket(TCPPacket*& packet) {
  82. if(m_sendList.empty()) {
  83. packet = NULL;
  84. }
  85. else {
  86. packet = m_sendList.front();
  87. m_sendList.pop_front();
  88. }
  89. };
  90. // 将Packet放回首部
  91. void PutPacketBack(TCPPacket* packet) {
  92. if(packet)
  93. m_sendList.push_front(packet);
  94. };
  95. P2PAddress GetAddress() {return remotePeer;};
  96. PeerInfoWithAddr GetPeerInfo() {return remotePeer;};
  97. SOCKET GetSocket() {return m_Socket;};
  98. bool GetIsIncoming() {return isIncoming;};
  99. bool GetIsForFree() {return isForFree;};
  100. bool GetIsCachePeer() {return remotePeer.isCachePeer;};
  101. bool GetIsSameLan() {return isSameLan;};
  102. bool GetIsSameRes() {return isSameRes;};
  103. DWORD GetElapsedTime() {return timeGetTime()-connectionBeginTime;};
  104. UINT8 GetLayer() {
  105. if(!valid)
  106. return 0xff;
  107. // 避免从0xff回到0
  108. if(remotePeer.layer != 0xff)
  109. return static_cast<UINT8>(remotePeer.layer)+1;
  110. return remotePeer.layer;
  111. };
  112. double GetBandWidth() {
  113. if(!valid || m_transUsedTime == 0)
  114. return 0.0f;
  115. return (static_cast<double>(totalDownBytes/1024)/m_transUsedTime)*1000;// 单位 kilo bytes per second
  116. };
  117. private:
  118. // 解析消息
  119. MSG_STATE ParseMsg();
  120. // 发送消息的函数
  121. BOOL SendPushList(UINT blockID, bool bAdd);
  122. BOOL SendResponse(UINT blockID, bool tryGetData);
  123. BOOL SendMsg();
  124. BOOL SendMediaType(UINT blockID);
  125. // 响应消息的函数
  126. MSG_STATE OnHello();
  127. MSG_STATE OnSPUpdate();
  128. MSG_STATE OnReport();
  129. MSG_STATE OnNearPeers();
  130. MSG_STATE OnPushList();
  131. MSG_STATE OnResponse();
  132. MSG_STATE OnMsg();
  133. MSG_STATE OnReqMedia();
  134. MSG_STATE OnMediaType();
  135. // 每次编制发送消息时,第一步的操作
  136. BOOL SendBegin(TCPPacket*& packet, UINT8 msgType);
  137. // 每次编制发送消息时,最后一步的操作
  138. void SendEnd(TCPPacket*& packet);
  139. // 检查发送列表中是否已经有准备发送的块
  140. // 1. 如果没有,那么返回FALSE;
  141. // 2. 如果有正在发送的块,返回TRUE
  142. BOOL CheckSendingBlock();
  143. // 从发送列表中查找一个块,如果此块准备发送(packet->send == 0),则删除并返回TRUE;
  144. // 如果此块已经开始发送,则直接返回TRUE。如未找到,则返回FALSE
  145. // 如果blockID是UINT_MAX,则删除任意一个准备发送的块
  146. BOOL DeleteSendingBlock(UINT blockID);
  147. private:
  148. enum {
  149. // 连上CP以后,如果一段时间内没有收到第一条消息,就断开连接
  150. MAX_CP_FIRST_MSG_IDLE = 10000,
  151. // 连上NP以后,如果一段时间内没有收到第一条消息,就断开连接
  152. MAX_NP_FIRST_MSG_IDLE = 10000,
  153. // 连入连接如果一段时间内不发送数据,就会被断开
  154. MAX_INCOMING_SENDDATA_IDLE = 25000, 
  155. // 连出连接如果一段时间内不接受数据,就会被断开
  156. MAX_OUTGOING_RECVDATA_IDLE = 25000, 
  157. // 如果push list非空,但是一段时间却没有收到数据头部,就断开连接
  158. MAX_RESPONSE_IDLE = 10000,
  159. MAX_P2P_ERRMSG = 64, 
  160. };
  161. enum {
  162. P2P_LOW_PUSH = 1,   // 给较慢( < bitRate/6)的连接每次分配的块数
  163. P2P_MID_PUSH = 3, // 给中等( < bitRate/2)的连接每次分配的块数
  164. P2P_HIGH_PUSH = 5,  // 给较快( > birRate/2)的连接每次分配的块数
  165. };
  166. SOCKET m_Socket; // 此连接的SOCKET,初始值是INVALID_SOCKET
  167. char recvBuf[P2P_BUF_SIZE]; // 接收数据的缓冲区
  168. UINT recvOff; // 缓冲区中数据的长度
  169. char *recvPointer; // 从接收到的数据包读取数据的移动指针
  170. char *sendPointer; // 向被发送的数据包写入数据的移动指针
  171. char errStr[MAX_P2P_ERRMSG]; // 出错信息
  172. UINT msgSize;
  173. PeerInfoWithAddr remotePeer; // 当前连接Peer的简单信息和IP地址
  174. IntervalArray remoteInterval; // 当前连接Peer所拥有块的区间列表
  175. PushList remotePush; // 需要对方发给本方数据的Push List
  176. PushList localPush; // 需要本方发给对方数据的Push List
  177. MediaArray sentMediaArray; // 曾经发送过媒体类型的的区间
  178. bool isIncoming; // 是否连入连接
  179. bool isForFree; // 是否free连接
  180. bool isPassive; // 是否被动连接
  181. bool isSameRes; // 双方当前资源是否相同
  182. bool isSameLan; // 双方是否相同子网
  183. float remoteVersion; // 对方的版本
  184. bool bGotFirstMsg; // 是否已经收到第一条消息
  185. bool valid; // 是否有效连接
  186. // 用于计算Idle时间,单位是毫秒
  187. DWORD lastSendDataTime; // 上次发送数据的时间
  188. DWORD lastRecvDataTime; // 上次接收数据的时间
  189. DWORD lastRecvDataHdTime; // 上次接收到数据头的时间
  190. DWORD lastRequestStartTime; // 最近一次请求开始的时间
  191. DWORD lastRequestBytes; // 最近一次请求的数据大小
  192. DWORD connectionBeginTime; // 本次连接开始的时间
  193. // 为了统计真实的传输速度,需要知道传输数据的具体时间
  194. // 又因为传输是pushlist而非一个接一个的方式,所以需要统计两种时间段:
  195. // 一种是remotePush从0变成非零的时刻起,收到第一个Block的数据止
  196. // 一种是收到Block的数据起,收到下一个Block的数据止。
  197. // 两种情况不会并发进行,所以可以用一个变量进行记录。
  198. DWORD m_reqStartTime; // 需要记录的请求起始时间
  199. DWORD m_transUsedTime; // 用在传输数据上的时间
  200. Communicator *comm; // 主类指针
  201. list<TCPPacket*> m_sendList; // 即将被发送的Packet列表
  202. typedef list<TCPPacket*>::iterator TCPPackIt;
  203. };
  204. }