我有这段代码:
#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(具有主动测试程序的PC) - NAT(家庭路由器) - ... - NAT(互联网提供商) - 互联网 - NAT(另一个互联网提供商) - ... - NAT(另一个家庭路由器) - B(另一台带有主动测试程序的电脑)
也许我做错了什么?..
我在哪里可以找到问题?
答案 0 :(得分:1)
问题在于双NAT。如果您没有配置端口转发,则家庭路由器(来自网络图)拒绝数据包。
按照以下步骤操作双NAT:
选择本地端口接收数据包。
尝试绑定端口。 (如果失败则返回步骤1)
使用NAT-PMP或UPnP IGD在家庭路由器中配置端口转发。
使用STUN获取外部IP和端口
将步骤4中的数据共享到另一个程序实例
发送和/或接收UDP数据包