【问题标题】:UDP over NAT failUDP over NAT 失败
【发布时间】:2018-02-07 23:52:54
【问题描述】:

我有这个代码:

#include <cstring>
#include <cstdio>
#include <cerrno>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string>

#include <stdlib.h>
#include <unistd.h>

#include <cstdlib>
#include <iostream>

#include <thread>
#include "STUN.h"

bool do_work = true;
using namespace std;

void receiver(int sock) {
    //boost::asio::io_service& s
    sockaddr_in from_adr;
    std::cout << "START: receiver\n";
    size_t blen = 2048;
    char * buf = new char[blen];
    unsigned slen = sizeof(from_adr);

    if (recvfrom(sock, (void *) buf, blen, 0, (sockaddr*) &from_adr, &slen)
            < 0) {
        std::cout << "Recv problem\n";
        exit(0);
    }
    do_work = false;
    std::cout << "STOP: receiver\n";
}

void sender(sockaddr_in * to, int sock) {
    std::cout << "START: sender\n";

    while (do_work) {
        if (sendto(sock, "OK", 3, 0, (sockaddr*) to, sizeof(sockaddr)) < 0) {
            std::cout << "SEND PROBLEM\n";
            return;
        }
        sleep(1);
    }
    std::cout << "RECEIVED!!!\n\n\n";
    exit(0);
}

int main(int argc, char* argv[]) {
    if (argc != 2) {
        std::cerr << "Usage: udp-flood-test <port>\n";
        return 1;
    }
    ippd stun_adr;
    stun_adr.addr = "64.233.161.127";
    stun_adr.port = 19302;
    STUN stun(stun_adr);

    std::string eip;
    uint16_t epp;

    uint16_t lp = std::atoi(argv[1]);

    ippd sti = stun.getSTUN(lp);
    std::cout << "External address: " << sti.addr << ":" << sti.port << "\n";
    std::cout << "Internal address: " << "127.0.0.1:" << lp << "\n";
    std::cout << "Write external ip: ";
    std::cin >> eip;
    std::cout << "\n";
    std::cout << "Write external port: ";
    std::cin >> epp;
    std::cout << "\n";
    std::cout << "OK. I'll send data to " << eip << ":" << epp << "\n";

    int m_sock;                     // дескриптор сокета
    sockaddr_in m_addr;             // переменная адреса интерфейса
    std::string my_addr = "0.0.0.0";             // Адрес локального интерфейса

    /* Создание сокета и присвоение значения дескриптору сокета для UDP пакетов
     * PF_INET    - IP protocol family
     * SOCK_DGRAM - Raw protocol interface */
    if ((m_sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
        perror("socket");
        return -1;
    }

    /* Обнуляем переменную m_addr и забиваем её нужными значениями */
    memset(&m_addr, 0, sizeof(m_addr));
    m_addr.sin_family = AF_INET;  // обязательно AF_INET!
    m_addr.sin_port = htons(lp); // 0 - выдать порт автоматом
    /* Переводим адрес в нужный нам формат */
    if (inet_aton(my_addr.c_str(), &m_addr.sin_addr) == 0) {
        perror("inet_aton");
        close(m_sock);
        return -1;
    }

    /* Биндим сокет */
    if (bind(m_sock, (struct sockaddr*) &m_addr, sizeof(m_addr)) < 0) {
        perror("bind");
        close(m_sock);
        return -1;
    }
    sockaddr_in to_addr;
    memset(&to_addr, 0, sizeof(to_addr));
    to_addr.sin_family = AF_INET;
    to_addr.sin_port = htons(epp);
    if (inet_aton(eip.c_str(), &to_addr.sin_addr) == 0) {
        perror("inet_aton");
        close(m_sock);
        return -1;
    }

    std::thread inp(receiver, m_sock);
    std::thread oup(sender, &to_addr, m_sock);

    oup.detach();
    inp.detach();
    while (1) {
        sleep(1);
    }

    return 0;
}

这是一个简单的测试程序,通过 STUN 获取外部 ip 和端口并将数据从对等点 A 发送到对等点 B(以及从 B 到 A)。

如果我将 IP 和端口设置为 127.0.0.1:port 或 local_network_ip:port,程序可以正常工作。

如果我设置从 STUN 服务器接收到的 IP,对等体 A 将向对等体 B 发送 UDP 数据包。B 将向 A 发送数据包。但 A 和 B 没有任何传入数据包。在 Wireshark 中我也可以看到传出的数据包,但没有传入。

网络连接图:

A(带有活动测试程序的电脑) - NAT(家庭路由器) - ... - NAT(互联网供应商) - 互联网 - NAT(另一个互联网供应商) - ... - NAT(另一个家庭路由器) - B (另一台带有活动测试程序的电脑)

也许我做错了什么?..

我在哪里可以找到问题?

【问题讨论】:

  • 我很确定双 NAT 正在杀死你。
  • @RonMaupin,是的,你是对的。解决方案:在尝试接受数据之前,在家庭路由器中进行端口转发。

标签: c++ sockets networking udp p2p


【解决方案1】:

问题在于双重 NAT。如果您没有配置端口转发,家庭路由器(来自网络图)会拒绝数据包。

按照以下步骤在双 NAT 上工作:

  1. 选择本地端口接收数据包。

  2. 尝试绑定端口。 (如果失败则返回步骤 1)

  3. 使用 NAT-PMP 或 UPnP IGD 在家庭路由器中配置端口转发。

  4. 使用 STUN 获取您的外部 IP 和端口

  5. 将步骤 4 中的数据共享到另一个程序实例

  6. 发送和/或接收 UDP 数据包

【讨论】:

  • 你应该研究打孔
猜你喜欢
  • 2017-08-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-13
相关资源
最近更新 更多