背景
使用c++開發一個udp連接功能的腳本,可以接收發送數據,而且地址是經過內網穿透到外網的
經過
通常發送數據給目標地址,需要把目的地址結構化,要么使用inet_addr解析ip地址,要么使用inet_pton
sockaddr_in target_addr{};
target_addr.sin_family = AF_INET;
target_addr.sin_addr.s_addr = inet_addr("192.168.x.xxx");
target_addr.sin_port = htons(TARGET_PORT);
sockaddr_in target_addr{};
target_addr.sin_family = AF_INET;
if (inet_pton(AF_INET, "192.168.x.xxx", &target_addr.sin_addr) <= 0) {std::cerr << "Invalid target address" << std::endl;close(server_socket);close(client_socket);return 1;}
target_addr.sin_port = htons(TARGET_PORT);
正常的ip地址是可以的,但是如果是個域名(例如server.natappfree.cc),就會報錯
Failed to send data
Invalid target address
原因
inet_pton 函數主要用于將點分十進制的 IPv4 地址或 IPv6 地址字符串轉換為二進制形式,它只能處理 IP 地址,不能直接處理域名(如 server.natappfree.cc)。當你傳入域名時,它會因為無法識別該字符串為有效的 IP 地址格式而報錯 Invalid target address。
要解決這個問題,
你需要使用 DNS 解析將域名轉換為對應的 IP 地址。
在 C++ 中,可以使用 getaddrinfo 函數來完成這個任務
(如果你用python,是可以直接寫域名的)
示例
#include <iostream>
#include <cstring>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <thread>
#include <errno.h>
#include <netdb.h>#define SERVER_PORT 1001
#define TARGET_PORT 1002
#define BUFFER_SIZE 1024int main() {// 創建服務器套接字int server_socket = socket(AF_INET, SOCK_DGRAM, 0);if (server_socket == -1) {std::cerr << "Failed to create server socket" << std::endl;return 1;}// 綁定服務器地址sockaddr_in server_addr{};server_addr.sin_family = AF_INET;server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");server_addr.sin_port = htons(SERVER_PORT);if (bind(server_socket, reinterpret_cast<sockaddr*>(&server_addr), sizeof(server_addr)) == -1) {std::cerr << "Failed to bind server socket" << std::endl;close(server_socket);return 1;}std::cout << "Listening on " << inet_ntoa(server_addr.sin_addr) << ":" << ntohs(server_addr.sin_port) << std::endl;// 創建客戶端套接字int client_socket = socket(AF_INET, SOCK_DGRAM, 0);if (client_socket == -1) {std::cerr << "Failed to create client socket" << std::endl;close(server_socket);return 1;}// 目標地址addrinfo hints{};hints.ai_family = AF_INET;hints.ai_socktype = SOCK_DGRAM;addrinfo* result;int status = getaddrinfo("server.natappfree.cc", std::to_string(TARGET_PORT).c_str(), &hints, &result);if (status != 0) {std::cerr << "getaddrinfo failed: " << gai_strerror(status) << std::endl;close(server_socket);close(client_socket);return 1;}sockaddr_in* target_addr = reinterpret_cast<sockaddr_in*>(result->ai_addr);const char* message = "i am udp";int i = 10;while (i > 0) {char buffer[BUFFER_SIZE];sockaddr_in client_addr{};socklen_t client_addr_len = sizeof(client_addr);// 接收數據ssize_t recv_len = recvfrom(server_socket, buffer, BUFFER_SIZE, 0, reinterpret_cast<sockaddr*>(&client_addr), &client_addr_len);if (recv_len == -1) {std::cerr << "Failed to receive data" << std::endl;continue;}buffer[recv_len] = '\0';std::cout << "recv " << buffer << " from " << inet_ntoa(client_addr.sin_addr) << ":" << ntohs(client_addr.sin_port) << std::endl;// 發送數據ssize_t send_len = sendto(client_socket, message, strlen(message), 0, reinterpret_cast<sockaddr*>(target_addr), sizeof(*target_addr));if (send_len == -1) {std::cerr << "Failed to send data: " << strerror(errno) << std::endl;}std::this_thread::sleep_for(std::chrono::seconds(1));i--;}// 釋放地址信息freeaddrinfo(result);// 關閉套接字close(server_socket);close(client_socket);return 0;
}