P2PClient.cpp
上传用户:zhangjjyh
上传日期:2021-11-11
资源大小:1251k
文件大小:11k
源码类别:

P2P编程

开发平台:

Objective-C

  1. //////////////////////////////////////////////////////
  2. // p2pclient.cpp文件
  3. #include <winsock2.h>
  4. #include <stdio.h>
  5. #include "p2pclient.h"
  6. #pragma comment(lib, "WS2_32") // 链接到WS2_32.lib
  7. CP2PClient::CP2PClient()
  8. {
  9. m_bLogin = FALSE;
  10. m_hThread = NULL;
  11. m_s = INVALID_SOCKET;
  12. memset(&m_ol, 0, sizeof(m_ol));
  13. m_ol.hEvent = ::WSACreateEvent();
  14. ::InitializeCriticalSection(&m_PeerListLock);
  15. // 初始化WS2_32.dll
  16. WSADATA wsaData;
  17. WORD sockVersion = MAKEWORD(2, 2);
  18. ::WSAStartup(sockVersion, &wsaData);
  19. }
  20. CP2PClient::~CP2PClient()
  21. {
  22. Logout();
  23. // 通知接收线程退出
  24. if(m_hThread != NULL)
  25. {
  26. m_bThreadExit = TRUE;
  27. ::WSASetEvent(m_ol.hEvent);
  28. ::WaitForSingleObject(m_hThread, 300);
  29. ::CloseHandle(m_hThread);
  30. }
  31. if(m_s != INVALID_SOCKET)
  32. ::closesocket(m_s);
  33. ::WSACloseEvent(m_ol.hEvent);
  34. ::DeleteCriticalSection(&m_PeerListLock);
  35. ::WSACleanup();
  36. }
  37. BOOL CP2PClient::Init(USHORT usLocalPort)
  38. {
  39. if(m_s != INVALID_SOCKET)
  40. return FALSE;
  41. // 创建用于P2P通信的UDP套节字,进行绑定
  42. m_s = ::WSASocket(AF_INET, 
  43. SOCK_DGRAM , IPPROTO_UDP, NULL, 0, WSA_FLAG_OVERLAPPED);
  44. sockaddr_in localAddr = { 0 };
  45. localAddr.sin_family = AF_INET;
  46. localAddr.sin_port = htons(usLocalPort);
  47. localAddr.sin_addr.S_un.S_addr = INADDR_ANY;
  48. if(::bind(m_s, (LPSOCKADDR)&localAddr, sizeof(localAddr)) == SOCKET_ERROR)
  49. {
  50. ::closesocket(m_s);
  51. m_s = INVALID_SOCKET;
  52. return FALSE;
  53. }
  54. if(usLocalPort == 0)
  55. {
  56. int nLen = sizeof(localAddr);
  57. ::getsockname(m_s, (sockaddr*)&localAddr, &nLen);
  58. usLocalPort = ntohs(localAddr.sin_port);
  59. }
  60. // 获取本地机器的IP地址,得到当前用户的私有终端
  61. char szHost[256];
  62. ::gethostname(szHost, 256);
  63. hostent *pHost = ::gethostbyname(szHost);
  64. memset(&m_LocalPeer, 0, sizeof(m_LocalPeer));
  65. for(int i=0; i<MAX_ADDR_NUMBER - 1; i++)
  66. {
  67. char *p = pHost->h_addr_list[i];
  68. if(p == NULL)
  69. break;
  70. memcpy(&m_LocalPeer.addr[i].dwIp, &p, pHost->h_length);
  71. m_LocalPeer.addr[i].nPort = usLocalPort;
  72. m_LocalPeer.AddrNum ++;
  73. }
  74. // 创建接收服务线程
  75. m_bThreadExit = FALSE;
  76. m_hThread = ::CreateThread(NULL, 0, RecvThreadProc, this, 0, NULL);
  77. return TRUE;
  78. }
  79. BOOL CP2PClient::Login(char *pszUserName, char *pszServerIp)
  80. {
  81. if(m_bLogin || strlen(pszUserName) > MAX_USERNAME - 1)
  82. return FALSE;
  83. // 保存参数
  84. m_dwServerIp = ::inet_addr(pszServerIp);
  85. strncpy(m_LocalPeer.szUserName, pszUserName, strlen(pszUserName));
  86. // 服务器名称
  87. sockaddr_in serverAddr = { 0 };
  88. serverAddr.sin_family = AF_INET;
  89. serverAddr.sin_addr.S_un.S_addr = m_dwServerIp; 
  90. serverAddr.sin_port = htons(SERVER_PORT);
  91. // 向服务发送本用户信息
  92. CP2PMessage logMsg;
  93. logMsg.nMessageType = USERLOGIN;
  94. memcpy(&logMsg.peer, &m_LocalPeer, sizeof(PEER_INFO)); 
  95. for(int i=0; i<MAX_TRY_NUMBER; i++)
  96. {
  97. ::sendto(m_s, (char*)&logMsg, sizeof(logMsg), 0, (sockaddr*)&serverAddr, sizeof(serverAddr));
  98. for(int j=0; j<10; j++)
  99. {
  100. if(m_bLogin)
  101. return TRUE;
  102. ::Sleep(300);
  103. }
  104. }
  105. return FALSE;
  106. }
  107. void CP2PClient::Logout()
  108. {
  109. if(m_bLogin)
  110. {
  111. // 告诉服务器,我们要离开了
  112. CP2PMessage logMsg;
  113. logMsg.nMessageType = USERLOGOUT;
  114. memcpy(&logMsg.peer, &m_LocalPeer, sizeof(PEER_INFO)); 
  115. sockaddr_in serverAddr = { 0 };
  116. serverAddr.sin_family = AF_INET;
  117. serverAddr.sin_addr.S_un.S_addr = m_dwServerIp; 
  118. serverAddr.sin_port = htons(SERVER_PORT);
  119. ::sendto(m_s, (char*)&logMsg, sizeof(logMsg), 0, (sockaddr*)&serverAddr, sizeof(serverAddr));
  120. m_bLogin = FALSE;
  121. }
  122. }
  123. BOOL CP2PClient::SendText(char *pszUserName, char *pszText, int nTextLen)
  124. {
  125. if(!m_bLogin || strlen(pszUserName) > MAX_USERNAME - 1 
  126. || nTextLen > MAX_PACKET_SIZE - sizeof(CP2PMessage))
  127. return FALSE;
  128. // 构建封包
  129. char sendBuf[MAX_PACKET_SIZE];
  130. CP2PMessage *pMsg = (CP2PMessage*)sendBuf;
  131. pMsg->nMessageType = P2PMESSAGE;
  132. memcpy(&pMsg->peer, &m_LocalPeer, sizeof(m_LocalPeer));
  133. memcpy((pMsg + 1), pszText, nTextLen);
  134. m_bMessageACK = FALSE;
  135. for(int i=0; i<MAX_TRY_NUMBER; i++)
  136. {
  137. PEER_INFO *pInfo = m_PeerList.GetAPeer(pszUserName);
  138. if(pInfo == NULL)
  139. return FALSE;
  140. // 如果对方P2P地址不为0,就试图以它为目的地址发送数据,
  141. // 如果发送失败,则认为此P2P地址无效
  142. if(pInfo->p2pAddr.dwIp != 0) 
  143. {
  144. sockaddr_in peerAddr = { 0 };
  145. peerAddr.sin_family = AF_INET;
  146. peerAddr.sin_addr.S_un.S_addr = pInfo->p2pAddr.dwIp;
  147. peerAddr.sin_port = htons(pInfo->p2pAddr.nPort);
  148. ::sendto(m_s, sendBuf, 
  149. nTextLen + sizeof(CP2PMessage), 0, (sockaddr*)&peerAddr, sizeof(peerAddr));
  150. for(int j=0; j<10; j++)
  151. {
  152. if( m_bMessageACK)
  153. return TRUE;
  154. ::Sleep(300);
  155. }
  156. }
  157. // 请求打洞,并且重新设置P2P地址
  158. pInfo->p2pAddr.dwIp = 0;
  159. // 构建封包
  160. char tmpBuf[sizeof(CP2PMessage) + MAX_USERNAME];
  161. CP2PMessage *p = (CP2PMessage *)tmpBuf;
  162. p->nMessageType = P2PCONNECT;
  163. memcpy(&p->peer, &m_LocalPeer, sizeof(m_LocalPeer));
  164. memcpy((char*)(p + 1), pszUserName, strlen(pszUserName) + 1);
  165. // 首先直接发向目标,
  166. sockaddr_in peerAddr = { 0 };
  167. peerAddr.sin_family = AF_INET;
  168. for(int j=0; j<pInfo->AddrNum; j++)
  169. {
  170. peerAddr.sin_addr.S_un.S_addr = pInfo->addr[j].dwIp;
  171. peerAddr.sin_port = htons(pInfo->addr[j].nPort);
  172. ::sendto(m_s, tmpBuf, sizeof(CP2PMessage), 0, (sockaddr*)&peerAddr, sizeof(peerAddr));
  173. }
  174. // 然后通过服务器转发,请求对方向自己打洞
  175. sockaddr_in serverAddr = { 0 };
  176. serverAddr.sin_family = AF_INET;
  177. serverAddr.sin_addr.S_un.S_addr = m_dwServerIp; 
  178. serverAddr.sin_port = htons(SERVER_PORT);
  179. ::sendto(m_s, tmpBuf, 
  180. sizeof(CP2PMessage) + MAX_USERNAME, 0, (sockaddr*)&serverAddr, sizeof(serverAddr));
  181. // 等待对方的P2PCONNECTACK消息
  182. for(j=0; j<10; j++)
  183. {
  184. if(pInfo->p2pAddr.dwIp != 0)
  185. break;
  186. ::Sleep(300);
  187. }
  188. }
  189. return 0;
  190. }
  191. BOOL CP2PClient::GetUserList()
  192. {
  193. // 服务器地址
  194. sockaddr_in serverAddr = { 0 };
  195. serverAddr.sin_family = AF_INET;
  196. serverAddr.sin_addr.S_un.S_addr = m_dwServerIp; 
  197. serverAddr.sin_port = htons(SERVER_PORT);
  198. // 构建封包
  199. CP2PMessage msgList;
  200. msgList.nMessageType = GETUSERLIST;
  201. memcpy(&msgList.peer, &m_LocalPeer, sizeof(m_LocalPeer));
  202. // 删除所有节点
  203. ::EnterCriticalSection(&m_PeerListLock);
  204. m_PeerList.DeleteAllPeers();
  205. ::LeaveCriticalSection(&m_PeerListLock);
  206. // 发送GETUSERLIST请求,等待列表发送完成
  207. m_bUserlistCmp = FALSE;
  208. int nUserCount = 0;
  209. for(int i=0; i<MAX_TRY_NUMBER; i++)
  210. {
  211. ::sendto(m_s, (char*)&msgList, 
  212. sizeof(msgList), 0, (sockaddr*)&serverAddr, sizeof(serverAddr));
  213. do
  214. {
  215. nUserCount = m_PeerList.m_nCurrentSize;
  216. for(int j=0; j<10; j++)
  217. {
  218. if(m_bUserlistCmp)
  219. return TRUE;
  220. ::Sleep(300);
  221. }
  222. }while(m_PeerList.m_nCurrentSize > nUserCount);
  223. }
  224. return FALSE;
  225. }
  226. DWORD WINAPI CP2PClient::RecvThreadProc(LPVOID lpParam)
  227. {
  228. CP2PClient *pThis = (CP2PClient *)lpParam;
  229. char buff[MAX_PACKET_SIZE];
  230. sockaddr_in remoteAddr;
  231. int nAddrLen = sizeof(remoteAddr);
  232. WSABUF wsaBuf;
  233. wsaBuf.buf = buff;
  234. wsaBuf.len = MAX_PACKET_SIZE;
  235. // 接收处理到来的消息
  236. while(TRUE)
  237. {
  238. DWORD dwRecv, dwFlags = 0;
  239. int nRet = ::WSARecvFrom(pThis->m_s, &wsaBuf, 
  240. 1, &dwRecv, &dwFlags, (sockaddr*)&remoteAddr, &nAddrLen, &pThis->m_ol, NULL);
  241. if(nRet == SOCKET_ERROR && ::WSAGetLastError() == WSA_IO_PENDING)
  242. {
  243. ::WSAGetOverlappedResult(pThis->m_s, &pThis->m_ol, &dwRecv, TRUE, &dwFlags);
  244. }
  245. // 首先查看是否要退出
  246. if(pThis->m_bThreadExit)
  247. break;
  248. // 调用HandleIO函数来处理这个消息
  249. pThis->HandleIO(buff, dwRecv, (sockaddr *)&remoteAddr, nAddrLen);
  250. }
  251. return 0;
  252. }
  253. void CP2PClient::HandleIO(char *pBuf, int nBufLen, sockaddr *addr, int nAddrLen)
  254. {
  255. CP2PMessage *pMsg = (CP2PMessage*)pBuf;
  256. if(nBufLen < sizeof(CP2PMessage))
  257. return;
  258. switch(pMsg->nMessageType)
  259. {
  260. case USERLOGACK: // 接收到服务器发来的登陆确认
  261. {
  262. memcpy(&m_LocalPeer, &pMsg->peer, sizeof(PEER_INFO));
  263. m_bLogin = TRUE;
  264. }
  265. break;
  266. case P2PMESSAGE: // 有一个节点向我们发送消息
  267. {
  268. int nDataLen = nBufLen - sizeof(CP2PMessage);
  269. if(nDataLen > 0)
  270. {
  271. // 发送确认消息
  272. CP2PMessage ackMsg;
  273. ackMsg.nMessageType = P2PMESSAGEACK;
  274. memcpy(&ackMsg.peer, &m_LocalPeer, sizeof(PEER_INFO));
  275. ::sendto(m_s, (char*)&ackMsg, sizeof(ackMsg), 0, addr, nAddrLen);
  276. OnRecv(pMsg->peer.szUserName, (char*)(pMsg + 1), nDataLen);
  277. }
  278. }
  279. break;
  280. case P2PMESSAGEACK: // 收到消息的应答
  281. {
  282. m_bMessageACK = TRUE;
  283. }
  284. break;
  285. case P2PCONNECT: // 一个节点请求建立P2P连接(打洞),可能是服务器发来的,也可能是其它节点发来的
  286. {
  287. CP2PMessage ackMsg;
  288. ackMsg.nMessageType = P2PCONNECTACK;
  289. memcpy(&ackMsg.peer, &m_LocalPeer, sizeof(PEER_INFO));
  290. if(((sockaddr_in*)addr)->sin_addr.S_un.S_addr != m_dwServerIp) // 节点发来的消息
  291. {
  292. ::EnterCriticalSection(&m_PeerListLock);
  293. PEER_INFO *pInfo = m_PeerList.GetAPeer(pMsg->peer.szUserName);
  294. if(pInfo != NULL)
  295. {
  296. if(pInfo->p2pAddr.dwIp == 0)
  297. {
  298. pInfo->p2pAddr.dwIp = ((sockaddr_in*)addr)->sin_addr.S_un.S_addr;
  299. pInfo->p2pAddr.nPort = ntohs(((sockaddr_in*)addr)->sin_port);
  300. printf(" Set P2P address for %s -> %s:%ld n", pInfo->szUserName, 
  301. ::inet_ntoa(((sockaddr_in*)addr)->sin_addr), ntohs(((sockaddr_in*)addr)->sin_port));
  302. }
  303. }
  304. ::LeaveCriticalSection(&m_PeerListLock);
  305. ::sendto(m_s, (char*)&ackMsg, sizeof(ackMsg), 0, addr, nAddrLen);
  306. }
  307. else // 服务器转发的消息
  308. {
  309. // 向节点的所有终端发送打洞消息
  310. sockaddr_in peerAddr = { 0 };
  311. peerAddr.sin_family = AF_INET;
  312. for(int i=0; i<pMsg->peer.AddrNum; i++)
  313. {
  314. peerAddr.sin_addr.S_un.S_addr = pMsg->peer.addr[i].dwIp;
  315. peerAddr.sin_port = htons(pMsg->peer.addr[i].nPort);
  316. ::sendto(m_s, (char*)&ackMsg, sizeof(ackMsg), 0, (sockaddr*)&peerAddr, sizeof(peerAddr));
  317. }
  318. }
  319. }
  320. break;
  321. case P2PCONNECTACK: // 接收到节点的打洞消息,在这里设置它的P2P通信地址
  322. {
  323. ::EnterCriticalSection(&m_PeerListLock);
  324. PEER_INFO *pInfo = m_PeerList.GetAPeer(pMsg->peer.szUserName);
  325. if(pInfo != NULL)
  326. {
  327. if(pInfo->p2pAddr.dwIp == 0)
  328. {
  329. pInfo->p2pAddr.dwIp = ((sockaddr_in*)addr)->sin_addr.S_un.S_addr;
  330. pInfo->p2pAddr.nPort = ntohs(((sockaddr_in*)addr)->sin_port);
  331. printf(" Set P2P address for %s -> %s:%ld n", pInfo->szUserName, 
  332. ::inet_ntoa(((sockaddr_in*)addr)->sin_addr), ntohs(((sockaddr_in*)addr)->sin_port));
  333. }
  334. }
  335. ::LeaveCriticalSection(&m_PeerListLock);
  336. }
  337. break;
  338. case USERACTIVEQUERY: // 服务器询问是否存活
  339. {
  340. CP2PMessage ackMsg;
  341. ackMsg.nMessageType = USERACTIVEQUERYACK;
  342. memcpy(&ackMsg.peer, &m_LocalPeer, sizeof(PEER_INFO));
  343. ::sendto(m_s, (char*)&ackMsg, sizeof(ackMsg), 0, addr, nAddrLen);
  344. }
  345. break;
  346. case GETUSERLIST: // 服务器发送的用户列表
  347. {
  348. // 首先清除此用户的P2P地址,再将用户信息保存到本地用户列表中
  349. pMsg->peer.p2pAddr.dwIp = 0;
  350. ::EnterCriticalSection(&m_PeerListLock);
  351. m_PeerList.AddAPeer(&pMsg->peer);
  352. ::LeaveCriticalSection(&m_PeerListLock);
  353. }
  354. break;
  355. case USERLISTCMP: // 用户列表传输结束
  356. {
  357. m_bUserlistCmp = TRUE;
  358. }
  359. break;
  360. }
  361. }