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

P2P编程

开发平台:

Objective-C

  1. ///////////////////////////////////////
  2. // P2PServer.cpp文件
  3. #include "../common/InitSock.h"
  4. #include "../comm.h"
  5. #include <stdio.h>
  6. DWORD WINAPI IOThreadProc(LPVOID lpParam);
  7. CInitSock theSock;
  8. CPeerList  g_PeerList; // 客户列表
  9. CRITICAL_SECTION g_PeerListLock; // 同步对客户列表的访问
  10. SOCKET g_s; // UDP套节字
  11. void main()
  12. {
  13. // 创建套节字,绑定到本地端口
  14. g_s = ::WSASocket(AF_INET, 
  15. SOCK_DGRAM , IPPROTO_UDP, NULL, 0, WSA_FLAG_OVERLAPPED);
  16. sockaddr_in sin;
  17. sin.sin_family = AF_INET;
  18. sin.sin_port = htons(SERVER_PORT);
  19. sin.sin_addr.S_un.S_addr = INADDR_ANY;
  20. if(::bind(g_s, (LPSOCKADDR)&sin, sizeof(sin)) == SOCKET_ERROR)
  21. {
  22. printf(" bind() failed %d n", ::WSAGetLastError());
  23. return;
  24. }
  25. ///////////////////////////////////////////////////////
  26. // 下面这段代码用来显示服务器绑定的终端
  27. char szHost[256];
  28. ::gethostname(szHost, 256);
  29. hostent *pHost = ::gethostbyname(szHost);
  30. in_addr addr;
  31. for(int i = 0; ; i++)
  32. {
  33. char *p = pHost->h_addr_list[i];
  34. if(p == NULL)
  35. break;
  36. memcpy(&addr.S_un.S_addr, p, pHost->h_length);
  37. printf(" bind to local address -> %s:%ld n", ::inet_ntoa(addr), SERVER_PORT);
  38. }
  39. // 开启服务
  40. printf(" P2P Server starting... nn");
  41. ::InitializeCriticalSection(&g_PeerListLock);
  42. HANDLE hThread = ::CreateThread(NULL, 0, IOThreadProc, NULL, 0, NULL);
  43. // 定时向客户方发送“询问”消息,删除不响应的用户
  44. while(TRUE)
  45. {
  46. int nRet = ::WaitForSingleObject(hThread, 15*1000);
  47. if(nRet == WAIT_TIMEOUT)
  48. {
  49. CP2PMessage queryMsg;
  50. queryMsg.nMessageType = USERACTIVEQUERY;
  51. DWORD dwTick = ::GetTickCount();
  52. for(int i=0; i<g_PeerList.m_nCurrentSize; i++)
  53. {
  54. if(dwTick - g_PeerList.m_pPeer[i].dwLastActiveTime >= 2*15*1000 + 600) 
  55. {
  56. printf(" delete a non-active user: %s n", g_PeerList.m_pPeer[i].szUserName);
  57. ::EnterCriticalSection(&g_PeerListLock);
  58. g_PeerList.DeleteAPeer(g_PeerList.m_pPeer[i].szUserName);
  59. ::LeaveCriticalSection(&g_PeerListLock);
  60. // 因为删了当前遍历到的用户,所以i值就不应该加1了
  61. i--;
  62. }
  63. else
  64. {
  65. // 注意,地址列表中的最后一个地址是客户的公共地址,询问消息应该发向这个地址
  66. sockaddr_in peerAddr = { 0 };
  67. peerAddr.sin_family = AF_INET;
  68. peerAddr.sin_addr.S_un.S_addr = 
  69. g_PeerList.m_pPeer[i].addr[g_PeerList.m_pPeer[i].AddrNum - 1].dwIp;
  70. peerAddr.sin_port = 
  71. htons(g_PeerList.m_pPeer[i].addr[g_PeerList.m_pPeer[i].AddrNum - 1].nPort);
  72. ::sendto(g_s, (char*)&queryMsg, sizeof(queryMsg), 0, (sockaddr*)&peerAddr, sizeof(peerAddr));
  73. }
  74. }
  75. else
  76. {
  77. break;
  78. }
  79. }
  80. printf(" P2P Server shutdown. n");
  81. ::DeleteCriticalSection(&g_PeerListLock);
  82. ::CloseHandle(hThread);
  83. ::closesocket(g_s);
  84. }
  85. DWORD WINAPI IOThreadProc(LPVOID lpParam)
  86. {
  87. char buff[MAX_PACKET_SIZE];
  88. CP2PMessage *pMsg = (CP2PMessage*)buff;
  89. sockaddr_in remoteAddr;
  90. int nRecv, nAddrLen = sizeof(remoteAddr);
  91. while(TRUE)
  92. {
  93. nRecv = ::recvfrom(g_s, buff, MAX_PACKET_SIZE, 0, (sockaddr*)&remoteAddr, &nAddrLen);
  94. if(nRecv == SOCKET_ERROR)
  95. {
  96. printf(" recvfrom() failed n");
  97. continue;
  98. }
  99. if(nRecv < sizeof(CP2PMessage))
  100. continue;
  101. // 防止用户发送错误的用户名
  102. pMsg->peer.szUserName[MAX_USERNAME] = ''; 
  103. switch(pMsg->nMessageType)
  104. {
  105. case USERLOGIN: // 有用户登陆
  106. {
  107. // 设置用户的公共终端信息,记录用户的活动时间
  108. pMsg->peer.addr[pMsg->peer.AddrNum].dwIp = remoteAddr.sin_addr.S_un.S_addr;
  109. pMsg->peer.addr[pMsg->peer.AddrNum].nPort = ntohs(remoteAddr.sin_port);
  110. pMsg->peer.AddrNum ++;
  111. pMsg->peer.dwLastActiveTime = ::GetTickCount();
  112. // 将用户信息保存到用户列表中
  113. ::EnterCriticalSection(&g_PeerListLock);
  114. BOOL bOK = g_PeerList.AddAPeer(&pMsg->peer);
  115. ::LeaveCriticalSection(&g_PeerListLock);
  116. if(bOK)
  117. {
  118. // 发送确认消息,将用户的公共地址传递过去
  119. pMsg->nMessageType = USERLOGACK;
  120. ::sendto(g_s, (char*)pMsg, sizeof(CP2PMessage), 0, (sockaddr*)&remoteAddr, sizeof(remoteAddr));
  121. printf(" has a user login : %s (%s:%ld) n", 
  122. pMsg->peer.szUserName, ::inet_ntoa(remoteAddr.sin_addr), ntohs(remoteAddr.sin_port));
  123. }
  124. }
  125. break;
  126. case USERLOGOUT: // 有用户登出
  127. {
  128. ::EnterCriticalSection(&g_PeerListLock);
  129. g_PeerList.DeleteAPeer(pMsg->peer.szUserName);
  130. ::LeaveCriticalSection(&g_PeerListLock);
  131. printf(" has a user logout : %s (%s:%ld) n", 
  132. pMsg->peer.szUserName, ::inet_ntoa(remoteAddr.sin_addr), ntohs(remoteAddr.sin_port));
  133. }
  134. break;
  135. case GETUSERLIST: // 有用户请求发送用户列表
  136. {
  137. printf(" sending user list information to %s (%s:%ld)... n",
  138. pMsg->peer.szUserName, ::inet_ntoa(remoteAddr.sin_addr), ntohs(remoteAddr.sin_port));
  139. CP2PMessage peerMsg;
  140. peerMsg.nMessageType = GETUSERLIST;
  141. for(int i=0; i<g_PeerList.m_nCurrentSize; i++)
  142. {
  143. memcpy(&peerMsg.peer, &g_PeerList.m_pPeer[i], sizeof(PEER_INFO));
  144. ::sendto(g_s, (char*)&peerMsg, sizeof(CP2PMessage), 0, (sockaddr*)&remoteAddr, sizeof(remoteAddr));
  145. }
  146. // 发送结束封包
  147. peerMsg.nMessageType = USERLISTCMP;
  148. ::sendto(g_s, (char*)&peerMsg, sizeof(CP2PMessage), 0, (sockaddr*)&remoteAddr, sizeof(remoteAddr));
  149. }
  150. break;
  151. case P2PCONNECT: // 有用户请求让另一个用户向它发送打洞消息
  152. {
  153. char *pszUser = (char*)(pMsg + 1);
  154. printf(" %s wants to connect to %s n", pMsg->peer.szUserName, pszUser);
  155. ::EnterCriticalSection(&g_PeerListLock);
  156. PEER_INFO *pInfo = g_PeerList.GetAPeer(pszUser);
  157. ::LeaveCriticalSection(&g_PeerListLock);
  158. if(pInfo != NULL)
  159. {
  160. remoteAddr.sin_addr.S_un.S_addr = pInfo->addr[pInfo->AddrNum -1].dwIp;
  161. remoteAddr.sin_port = htons(pInfo->addr[pInfo->AddrNum -1].nPort);
  162. ::sendto(g_s, (char*)pMsg, 
  163. sizeof(CP2PMessage), 0, (sockaddr*)&remoteAddr, sizeof(remoteAddr));
  164. }
  165. }
  166. break;
  167. case USERACTIVEQUERYACK: // 用户对“询问”消息的应答
  168. {
  169. printf(" recv active ack message from %s (%s:%ld) n",
  170. pMsg->peer.szUserName, ::inet_ntoa(remoteAddr.sin_addr), ntohs(remoteAddr.sin_port));
  171. ::EnterCriticalSection(&g_PeerListLock);
  172. PEER_INFO *pInfo = g_PeerList.GetAPeer(pMsg->peer.szUserName);
  173. if(pInfo != NULL)
  174. {
  175. pInfo->dwLastActiveTime = ::GetTickCount();
  176. }
  177. ::LeaveCriticalSection(&g_PeerListLock);
  178. }
  179. break;
  180. }
  181. }
  182. return 0;
  183. }