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

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. // TryClient.cpp: implementation of the TryClient class.
  20. //
  21. //////////////////////////////////////////////////////////////////////
  22. #include "stdafx.h"
  23. #include "TryClient.h"
  24. #include "Communicator.h"
  25. namespace NPLayer1 {
  26. //////////////////////////////////////////////////////////////////////
  27. // Construction/Destruction
  28. //////////////////////////////////////////////////////////////////////
  29. TryClient::TryClient(Communicator* c) : comm(c) {}
  30. TryClient::~TryClient() {}
  31. void TryClient::Try() {
  32. // 尝试连接可以连接的Peer,直到没有可供连接的Peer
  33. for(;;) {
  34. // 获取可以连接的Peer地址
  35. ConnectingPeer tryPeer;
  36. if(!comm->p2pMgr.GetPeer4Connect(tryPeer)) {
  37. break; // 无可连接
  38. }
  39. tryPeer.isSameLan = false;
  40. if(tryPeer.IsNAT()) {
  41. if(tryPeer.outerIP.sin_addr.s_addr == comm->localAddress.outerIP.sin_addr.s_addr) {
  42. //与本机在同一个内网中,直接连接其内网IP
  43. tryPeer.isSameLan = true;
  44. }
  45. }
  46. CONNECT_RESULT ret = Connecting(tryPeer, tryPeer.sock);
  47. // 记录连接时间
  48. tryPeer.connectTime = timeGetTime();
  49. if(ret == CR_CONNECTED)
  50. comm->p2pMgr.AddP2PClient(tryPeer);
  51. else if(ret == CR_WOULDBLOCK) {
  52. comm->p2pMgr.AddConnecting(tryPeer);
  53. }
  54. else if(ret == CR_ERROR)
  55. comm->p2pMgr.AddBadAddr(tryPeer);
  56. }
  57. }
  58. CONNECT_RESULT TryClient::Connecting(P2PAddress addr, SOCKET& sock) {
  59. NormalAddress tmpAddr;
  60. tmpAddr.sin_addr.s_addr = addr.outerIP.sin_addr.s_addr; // outer ip
  61. tmpAddr.sin_port = addr.subnetIP.sin_port; // serv Port
  62. if(addr.IsNAT()) {
  63. if(addr.outerIP.sin_addr.s_addr == comm->localAddress.outerIP.sin_addr.s_addr) {
  64. //与本机在同一个内网中,直接连接其内网IP
  65. tmpAddr.sin_addr.s_addr = addr.subnetIP.sin_addr.s_addr; // subnet ip
  66. }
  67. else {
  68. comm->logFile.StatusOut("不能连接其他内网中的客户端。%s", comm->p2pMgr.FormatIPAddress(addr));
  69. return CR_ERROR;
  70. }
  71. }
  72. return Connecting(tmpAddr, sock);
  73. }
  74. CONNECT_RESULT TryClient::Connecting(NormalAddress addr, SOCKET& sock) {
  75. comm->logFile.StatusOut("Connecting to %s:%d.", 
  76. inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
  77. CONNECT_RESULT ret = CR_ERROR;
  78. // Create a TCP/IP socket that is bound to the server.
  79. // Microsoft Knowledge Base: WSA_FLAG_OVERLAPPED Is Needed for Non-Blocking Sockets
  80. // http://support.microsoft.com/default.aspx?scid=kb;EN-US;179942
  81. sock = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED);
  82. if(sock == INVALID_SOCKET) {
  83. comm->logFile.StatusErr("Creating socket", WSAGetLastError());
  84. return ret;
  85. }
  86. // SO_EXCLUSIVEADDRUSE is only supported in 2000/XP/2003 and higher OS.
  87. if(comm->osvi.dwMajorVersion > 5) {
  88. // 独占端口
  89. BOOL bExAddrUse = TRUE;
  90. if(setsockopt(sock, SOL_SOCKET, ((int)(~SO_REUSEADDR)), (const char*)&bExAddrUse, sizeof(bExAddrUse)) == SOCKET_ERROR) {
  91. comm->logFile.StatusErr("Setting socket as SO_EXCLUSIVEADDRUSE", WSAGetLastError());
  92. return ret;
  93. }
  94. }
  95. // 不使用Nagle算法
  96. BOOL bNoDelay = TRUE;
  97. if(setsockopt(sock, SOL_SOCKET, TCP_NODELAY, (const char*)&bNoDelay, sizeof(bNoDelay)) == SOCKET_ERROR) {
  98. comm->logFile.StatusErr("Setting UDP socket as TCP_NODELAY", WSAGetLastError());
  99. return ret;
  100. }
  101. // Set this socket as a Non-blocking socket.
  102. ULONG flag = 1;
  103. if(ioctlsocket(sock, FIONBIO, &flag) == SOCKET_ERROR) {
  104. comm->logFile.StatusErr("Setting socket as non-blocking", WSAGetLastError());
  105. return ret;
  106. }
  107. // Connect to remote address
  108. if(WSAConnect(sock, 
  109. (sockaddr*)&addr, sizeof(sockaddr), 
  110. NULL, NULL, NULL, NULL) == SOCKET_ERROR) {
  111. if(WSAGetLastError() != WSAEWOULDBLOCK) {
  112. comm->logFile.StatusErr("Connecting socket", WSAGetLastError());
  113. return ret;
  114. }
  115. else {
  116. ret = CR_WOULDBLOCK;
  117. comm->logFile.StatusOut("%s:%d is blocking.", 
  118. inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
  119. }
  120. }
  121. else {
  122. ret = CR_CONNECTED;
  123. comm->logFile.StatusOut("%s:%d is connected.", 
  124. inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
  125. }
  126. return ret;
  127. }
  128. }