2014-12-23 230 views
0

我一直堅持這個問題的年齡...連接到外部IP失敗

所以我編碼與多人使用BSD插座/ Winsock 2 TCP的遊戲。我的服務器已啓動並正在運行,我可以在本地連接到它(間接地通過填寫我自己的外部IP)。一切似乎都很好。我使用canyouseeme.org進行了測試,無論我的IP和服務器端口是否正確轉發端口,並且完全正常工作。然後,我將我的客戶端發送給朋友,通過連接到服務器進行測試,並且一直失敗。我期望他能夠連接,但我在服務器端看不到任何東西(雖然canyouseenme.org甚至彈出爲無效客戶端)。我不明白,是否需要爲TCP中的外部連接做些特別的事情?

這裏是我的連接功能:

int CConnectSocket(CSocket s, unsigned short port, char* ipaddress) 
{ 
    SOCKADDR_IN target; 
    target.sin_family = AF_INET; 
    target.sin_port = htons(port); 
    target.sin_addr.s_addr = htonl(inet_addr(ipaddress)); 
    if (connect(s, (SOCKADDR*)&target, sizeof(target)) == SOCKET_ERROR) 
    { 
     if (WSAGetLastError() == WSAEISCONN) 
      return CTCP_DONE; 
     else if (WSAGetLastError() != WSAEWOULDBLOCK && WSAGetLastError() != WSAEALREADY) 
     { 
      strcpy(inerr, "CConnectSocket: Failed to connect the socket. Error "); 
      char f[6]; 
      sprintf(f, "%d", WSAGetLastError()); 
      strcat(inerr, f); 
      return CTCP_ERROR; 
     } 
     return CTCP_WAIT; 
    } 
    return CTCP_DONE; 
} 

,直到返回CTCP_DONE(意思是我連)我一直循環這個功能。我的朋友報告他超時(所以它返回CTCP_WAIT的時間太長了)。再次,我確信客戶端是錯誤的,因爲我的服務器能夠接受來自canyouseeme.org的外部連接。因爲我可以在本地連接,所以IP地址和端口填寫工作。如果我更改端口,本地連接不再工作(證明它是一個正確的參數)。更改IP確實會產生相同的結果。

我感謝任何幫助!希望我能解決這個問題並開始多人遊戲。

編輯

void CEngine::CSetSockAddr(CSockAddr* address, unsigned short port, char* ipaddress) 
{ 
    memset(address, 0, sizeof(CSockAddr)); 
    address->sin_family = AF_INET; 
    address->sin_port = htons(port); 
    address->sin_addr.s_addr = htonl(inet_addr(ipaddress)); 
} 

這是我的套接字地址的功能。當我刪除htonl函數時,它在我的朋友那邊工作,但不再在我身邊(我也託管服務器)。我的朋友BTW使用XP,但因爲我打電話使用2.2 WinSock應該沒有問題。至少我希望如果WinSock的設置函數返回true,它將保證2.2實現。

EDIT 2

好傢伙,

我已經得到了一切了,現在的工作。看來,如果我添加htonl我可以作爲主機與外部IP連接,而不是連接到環回127.0.0.0.1或者那樣。所以現在我想知道,如何檢測我是否連接到我託管的服務器?這將是一個很好的竅門。新年快樂!

+2

也許你的朋友有防火牆,阻止連接。 –

+0

不可能他沒有檢查,而另一個朋友和人也發生了同樣的情況......所以我不知道。 – user209347

+2

我不確定,但不是已經按網絡字節順序返回的'inet_addr()'?如果是這樣,那麼放下'htonl()'。也就是說,有一個'FormatString()'函數可以用來將錯誤代碼轉換爲文本(然後應該用來引發異常)。順便說一句,你是否嘗試連接不同的工具,如一個瀏覽器?遠程講HTTP,無關緊要,只是爲了測試連接。最後,錯誤也可能在CSocket中,不管是什麼...... –

回答

1

是非常困難的,幫助你沒有一個控制檯...但你可以與你的朋友交談,試試這個:

  • 從你朋友的電腦,讓對您的服務器ping命令。
  • 如果您收到答案,請使用tracert或traceroute找出問題所在
  • 您朋友的路線模型是什麼?可能它有一個系統事件日誌,您可以在其中檢查被拒絕的連接。

好運!

0

您需要在致電inet_addr()時刪除htonl()呼叫。 connect()預計IP將處於網絡字節順序,並且inet_addr()以網絡字節順序返回IP,因此不需要在任何平臺上交換字節。

試試這個:

int CConnectSocket(CSocket s, unsigned short port, char* ipaddress) 
{ 
    SOCKADDR_IN target = {0}; 
    target.sin_family = AF_INET; 
    target.sin_port = htons(port); 
    target.sin_addr.s_addr = inet_addr(ipaddress); 

    if (connect(s, (SOCKADDR*)&target, sizeof(target)) == SOCKET_ERROR) 
    { 
     int err = WSAGetLastError(); 
     switch (err) 
     { 
      case WSAEISCONN: 
       return CTCP_DONE; 

      case WSAEWOULDBLOCK: 
      case WSAEALREADY: 
       return CTCP_WAIT; 

      default: 
       sprintf(inerr, "CConnectSocket: Failed to connect the socket. Error %d", err); 
       return CTCP_ERROR; 
     } 
    } 

    return CTCP_DONE; 
} 
+0

只是一個簡單的問題:is target = {0}在c/C++中將結構初始化爲零的方式嗎? – user209347

+0

這是執行此操作的幾種方法之一。在這個例子中,'= {0}'明確地將第一個成員初始化爲0,然後將剩下的成員初始化爲默認值。也可以使用'= {}'來賦值初始化第一個成員。 –

+0

我不得不讓我們失望:它不起作用。我的朋友仍然無法連接。 – user209347