UDP服务器绑定到错误的端口号



我正在尝试制作一个非常简单的UDP客户端/服务器设置。我已经将问题隔离到服务器没有绑定到所请求的端口号,而是任意地绑定到一个(尽管它似乎始终是同一端口(。

是否可以请求特定的端口号?

我试图不适合IPv4或IPv6。因此,如果我不在乎IP地址,我不确定是否需要使用getaddrinfo,但是我认为这样它会找到可用的东西,或者更好的是,请听所有进入此端口的IP地址?但这是在报告::,如果我以后告诉客户,这会使我有问题。

#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <Ws2tcpip.h>
#include <cstring>
#include <iostream>
#include <chrono>
#include <iomanip>
#include <sstream>
static uint16_t SERVER_PORT = 56000;
std::wstring get_error_string(const DWORD error)
{
    std::wstring returnResult = L"";
    LPWSTR errorText = NULL;
    FormatMessageW(
        FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_IGNORE_INSERTS,
        NULL,
        error,
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
        (LPWSTR)&errorText,
        0,
        NULL);
    if(NULL != errorText)
    {
        returnResult = errorText;
        LocalFree(errorText);
        errorText = NULL;
    }
    std::time_t t = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
    std::tm tm = *std::localtime(&t);
    std::wstringstream sstr;
    sstr << std::put_time<wchar_t>(&tm, L"%d%m%y %H:%M:%S");
    return sstr.str() + L" ERROR (" + std::to_wstring(error) + L"): " + returnResult;
}
std::string convert_to_string(const sockaddr* addr)
{
    char* str;
    if(addr->sa_family == AF_INET)
    {
        str = new char[INET_ADDRSTRLEN];
        inet_ntop(AF_INET, &(reinterpret_cast<const sockaddr_in*>(addr)->sin_addr), str, INET_ADDRSTRLEN);
    }
    else
    {
        str = new char[INET6_ADDRSTRLEN];
        inet_ntop(AF_INET6, &(reinterpret_cast<const sockaddr_in6*>(addr)->sin6_addr), str, INET6_ADDRSTRLEN);
    }
    std::string returnVal = str;
    if(addr->sa_family == AF_INET)
        returnVal += ":" + std::to_string(reinterpret_cast<const sockaddr_in*>(addr)->sin_port);
    else
        returnVal = "[" + returnVal + "]:" + std::to_string(reinterpret_cast<const sockaddr_in6*>(addr)->sin6_port);
    return returnVal;
}
int main()
{
    WSADATA wsaData;
    int result = WSAStartup(MAKEWORD(2,2), &wsaData);
    if(result != 0)
    {
        std::wcerr << L"Network init failed: ";
        switch(result)
        {
        case WSASYSNOTREADY:
            std::wcerr << L"WSASYSNOTREADY";
            break;
        case WSAVERNOTSUPPORTED:
            std::wcerr << L"WSAVERNOTSUPPORTED";
            break;
        case WSAEINPROGRESS:
            std::wcerr << L"WSAEINPROGRESS";
            break;
        case WSAEPROCLIM:
            std::wcerr << L"WSAEPROCLIM";
            break;
        case WSAEFAULT:
            std::wcerr << L"WSAEFAULT";
            break;
        default:
            std::wcerr << L"Unknown error code " << std::to_wstring(result);
        }
        std::wcerr << std::endl;
        return 0;
    }
    addrinfo hints = {};
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_DGRAM;
    hints.ai_flags = AI_PASSIVE;
    addrinfo* serverInfoList;
    int status = getaddrinfo(nullptr, std::to_string(SERVER_PORT).c_str(), &hints, &serverInfoList);
    if(status != 0)
    {
        int lastError = WSAGetLastError();
        std::wcerr << L"ERROR getaddrinfo: " << get_error_string(lastError) << std::endl;
    }
    addrinfo* addr = nullptr;
    SOCKET sock;
    for(addr = serverInfoList; addr != nullptr; addr = addr->ai_next)
    {
        sock = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
        if(sock == INVALID_SOCKET)
        {
            int lastError = WSAGetLastError();
            std::wcerr << L"ERROR socket: " << get_error_string(lastError) << std::endl;
            continue; // we'll try the next option
        }
        u_long blocking = 1;
        ioctlsocket(sock, FIONBIO, &blocking);
        BOOL conrest = FALSE;
        DWORD dwBytesReturned = 0;
        WSAIoctl(sock, _WSAIOW(IOC_VENDOR, 12), &conrest, sizeof(conrest), NULL, 0, &dwBytesReturned, NULL, NULL);
        int flag = 1;
        setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<char*>(&flag), (socklen_t)sizeof(flag));
        if(bind(sock, addr->ai_addr, addr->ai_addrlen) == SOCKET_ERROR)
        {
            int lastError = WSAGetLastError();
            std::wcerr << L"ERROR bind: " << get_error_string(lastError) << std::endl;
            if(closesocket(sock) == SOCKET_ERROR)
            {
                lastError = WSAGetLastError();
                std::wcerr << L"ERROR closesocket: " << get_error_string(lastError) << std::endl;
            }
            continue;
        }
        sockaddr_storage connectedDetails;
        std::memset(&connectedDetails, 0, sizeof(connectedDetails));
        int addrLen = sizeof(connectedDetails);
        if(getsockname(sock, reinterpret_cast<sockaddr*>(&connectedDetails), &addrLen) == SOCKET_ERROR)
        {
            int lastError = WSAGetLastError();
            std::wcerr << L"ERROR getsockname: " << get_error_string(lastError) << std::endl;
        }
        std::cout << "Connected to " << convert_to_string(reinterpret_cast<sockaddr*>(&connectedDetails)) << std::endl;
        break; // we've bound to one of them
    }
    if(addr == nullptr)
    {
        std::wcerr << L"ERROR: Could not bind to any addr for localhost port "" << std::to_wstring(SERVER_PORT) << """ << std::endl;
        return false;
    }
    freeaddrinfo(serverInfoList);
    while(!(GetAsyncKeyState(VK_ESCAPE) & 0x8000))
    {
    }
    result = WSACleanup();
    if(result != 0)
    {
        std::wcerr << L"Network cleanup failed: ";
        switch(result)
        {
        case WSANOTINITIALISED:
            std::wcerr << L"WSANOTINITIALISED";
            break;
        case WSAENETDOWN:
            std::wcerr << L"WSAENETDOWN";
            break;
        case WSAEINPROGRESS:
            std::wcerr << L"WSAEINPROGRESS";
            break;
        default:
            std::wcerr << L"Unknown error code " << std::to_wstring(result);
        }
        std::wcerr << std::endl;
    }
    return 0;
}

我希望它可以绑定到端口56000,但它绑定到其他端口。

最简单的方法是自己构建sockaddr_in,因为您想绑定到所有地址。

// Create IPv6 UDP socket
X = socket(AF_INET6,SOCK_DGRAM,IPPROTO_UDP);
// Allow both ipv6/ipv4 bind  
DWORD ag = 0;  
setsockopt(X,IPPROTO_IPV6, IPV6_V6ONLY, (char*)&ag, sizeof(DWORD));
sockaddr_in s = {0};  
s.sin_port = htons(SERVER_PORT);  
s.sin_family= AF_INET6;
if (bind(X,(sockaddr*)&s,sizeof(s)) == 0) { ... }

相关内容

最新更新