【问题标题】:TCP only doesn't works with public IPTCP 仅不适用于公共 IP
【发布时间】:2012-02-16 08:37:15
【问题描述】:

我写了两个函数,它们应该启动一个 TCP-Server/Client。如果我用 IP“127.0.0.1”(仅用于测试)调用它们,那么一切正常。但是,如果我使用计算机的公共 IP 呼叫他们,我会遇到连接超时。有人知道可能是什么问题吗?

这里是代码:

服务器:

bool fSTARTED = false;
struct timeval tv;

TCP_StartServer (const int iPort, SOCKET *iSOCKET)
{
WSADATA wsa;
SOCKET iSOCKETListen;
SOCKADDR_IN tAdr;

if(!fSTARTED)
{
    if(WSAStartup(MAKEWORD(2,2), &wsa))
    {
        *iSOCKET = -1;
        return;
    }
    tv.tv_sec = 5;
    tv.tv_usec = 0;
    fSTARTED = true;
}

iSOCKETListen = socket(AF_INET, SOCK_STREAM, 0);

memset(&tAdr, 0, sizeof(SOCKADDR_IN));
tAdr.sin_family = AF_INET;
tAdr.sin_port = htons(iPort);
tAdr.sin_addr.s_addr = htonl(INADDR_ANY);
if(bind(iSOCKETListen, (SOCKADDR*) & tAdr, sizeof(SOCKADDR_IN)) == SOCKET_ERROR)
{
    *iSOCKET = 0 - WSAGetLastError();
    return;
}

if(listen(iSOCKETListen, SOMAXCONN) == SOCKET_ERROR)
{
    *iSOCKET =  0 - WSAGetLastError();
    return;
}

*iSOCKET = accept(iSOCKETListen, NULL, NULL);
if(*iSOCKET == INVALID_SOCKET)
{
    *iSOCKET = 0 - WSAGetLastError();
    return;
}

return;
}

客户:

TCP_StartClient (char *sIP, const int iPort, SOCKET *iSOCKET)
{
WSADATA wsa;
SOCKADDR_IN tAdr;

if(!fSTARTED)
{
    if(WSAStartup(MAKEWORD(2,2), &wsa))
    {
        *iSOCKET = -2;
        return;
    }
    tv.tv_sec = 5;
    tv.tv_usec = 0;
    fSTARTED = true;

}

*iSOCKET = socket(AF_INET, SOCK_STREAM, 0);
if(*iSOCKET == INVALID_SOCKET)
{
    *iSOCKET = 0 - WSAGetLastError();
    return;
}

memset(&tAdr, 0, sizeof(SOCKADDR_IN));
tAdr.sin_family = AF_INET;
tAdr.sin_port = htons(iPort);
tAdr.sin_addr.s_addr = inet_addr(sIP);

if(connect(*iSOCKET, (SOCKADDR*) &tAdr, sizeof(SOCKADDR)) == SOCKET_ERROR)
{
    *iSOCKET =  0 - WSAGetLastError();
    return;
}

return;
}

【问题讨论】:

  • 如果超时,StartClient 中的sIP arg 的值是多少?
  • 你打开对应的端口了吗?
  • 取决于操作系统(Windows 2008、Windows 7 等),您可以配置防火墙来防止这种情况...
  • @Yahia 我猜是 Windows,因为WSADATA
  • @VictorSorokin 我同意,但这并不能告诉我们 Windows 版本,而且并非所有 Windows 版本都带有内置防火墙...

标签: c winapi tcp ip


【解决方案1】:

这甚至可能不是您的代码的问题。某些计算机(例如我的计算机)在尝试从外部 IP 访问时看不到自己。尝试为您的外部 IP 设置一个环回适配器,同时检查您的 NAT 规则。

【讨论】:

  • 好的,可以。我将尝试使用环回适配器。我希望它能和它一起工作。
  • 我尝试安装环回适配器,但它不起作用。它无法安装驱动程序。但是我现在用另一台电脑测试了它,它也没有工作。所以它一定是别的东西。
【解决方案2】:

这是典型的家庭计算机网络的外观(简图和说明):

        \     Internet     /
         \/\/\/\/\/\/\/\/\/
                  |
                  | 212.60.44.90 (public IP address)
           +-------------+
           | DSL router  |
           +-------------+
                  | 10.0.0.1 (private network router)
                  |
                  | 10.0.0.2 (private network address)
           +-------------+
           |Your computer|
           +-------------+

在这种情况下,路由器正在从您的本地 10.0.0.x 地址到您的公共 212.60.44.90 地址执行NAT。您的计算机不知道它最终使用的公共 IP 地址,因为该信息仅在 DSL 路由器中。 NAT 的要点是,您本地的 10.0.0.x 网络上可能还有其他计算机,并且它们共享相同的公共 IP 地址(因为只有一个)。

您的路由器可能还充当防火墙,防止来自 Internet 的随机传入连接到达您的本地计算机。通常路由器会阻止所有这样的传入连接。

鉴于上述情况,您应该能够了解为什么无法从您自己的网络连接到您的公共 212.60.44.90 地址。您的计算机将请求发送到路由器,路由器会从防火墙的角度忽略或阻止您的请求。

根据您的路由器,您也许可以将其配置为将传入的请求转发到您的公共 IP 地址到 10.0.0.x 网络上的特定计算机。您必须手动设置,有关如何执行此操作的说明超出了此答案的范围。

此外,您可能会注意到您应该能够通过本地网络地址(图中的 10.0.0.2)连接到本地计算机。但是,这并不比连接到 127.0.0.1 更有趣。

【讨论】:

  • +1 同样,大多数 NAT 路由器在来自内部时不会转发请求。例如,我在内部时无法通过公共 IP 连接到我的服务器,我必须使用私有 IP。如果我已正确设置它,则很难快速测试它,总是必须从另一个连接进行测试。
  • 感谢您提供如此详细的答案。我想我现在明白了。所以我需要在我的网络之外的计算机上尝试一下......
猜你喜欢
  • 2020-04-13
  • 2012-01-12
  • 1970-01-01
  • 1970-01-01
  • 2017-12-31
  • 1970-01-01
  • 1970-01-01
  • 2013-11-28
  • 1970-01-01
相关资源
最近更新 更多