2014-12-23 232 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