c++ - UDP套接字端口分配失败

标签 c++ sockets udp winsock port

我正在创建一个 winsock UDP 程序。我正在使用的代码如下所示。

我总是遇到端口分配错误。

我无法理解为什么分配的端口始终为零。如果有人可以帮助我....

void UDPecho(const char *, const char *);

void errexit(const char *, ...);

#define LINELEN  128
#define WSVERS  MAKEWORD(2, 0)

void main(int argc, char *argv[])
{
    char *host = "localhost";
    char *service = "echo";
    WSADATA wsadata;
    switch (argc) {
    case 1:
        host = "localhost";
        break;

    case 3:
        service = argv[2];
        /* FALL THROUGH */

    case 2:
        host = argv[1];
        break;

    default:
        fprintf(stderr, "usage: UDPecho [host [port]]\n");
        exit(1);

    }

    if (WSAStartup(WSVERS, &wsadata))
        errexit("WSAStartup failed\n");

    UDPecho(host, service);

    WSACleanup();

    exit(0);
}

void UDPecho(const char *host, const char *service)
{
    char buf[LINELEN+1];
    SOCKET s;
    int nchars;
    struct hostent *phe;
    struct servent *pse;
    struct protoent *ppe;
    struct sockaddr_in sin, my_sin;
    int type, status, client_port, size;
    char *transport = "udp";

    memset(&sin, 0, sizeof(sin));
    sin.sin_family = AF_INET;

    /* Map service name to port number */
    if ( pse = getservbyname(service, transport) )
        sin.sin_port = pse->s_port;
    else if ( (sin.sin_port = htons((u_short)atoi(service)))== 0)
        errexit("can't get \"%s\" service entry\n", service);

    /* Map host name to IP address, allowing for dotted decimal */
    if ( phe = gethostbyname(host) )
        memcpy(&sin.sin_addr, phe->h_addr, phe->h_length);
    else if ( (sin.sin_addr.s_addr = inet_addr(host)) == INADDR_NONE)
        errexit("can't get \"%s\" host entry\n", host);

    printf("Our target server is at address %s\n", inet_ntoa(sin.sin_addr));
    printf("The size of an FD set is %d\n", sizeof(FD_SET));

    /* Map protocol name to protocol number */
    if ( (ppe = getprotobyname(transport)) == 0)
        errexit("can't get \"%s\" protocol entry\n", transport);

    /* Use protocol to choose a socket type */
    if (strcmp(transport, "udp") == 0)
        type = SOCK_DGRAM;
    else
        type = SOCK_STREAM;

    /* Allocate a socket */
    s = socket(PF_INET, type, ppe->p_proto);
    if (s == INVALID_SOCKET)
        errexit("can't create socket: %d\n", GetLastError());

    size = sizeof(sin);
    memset(&my_sin, 0, sizeof(sin));
    getsockname (s, (struct sockaddr *) &my_sin, &size);
    client_port = ntohs(my_sin.sin_port);

    if (client_port != 0)
        printf ("We are using port %2d\n", client_port);
    else {
        printf("No port assigned yet\n");
    }
}


void errexit(const char *format, ...)
{
    va_list args;
    va_start(args, format);
    vfprintf(stderr, format, args);
    va_end(args);
    WSACleanup();

    exit(1);
}

最佳答案

UDP 不会绑定(bind)到监听端口,直到您在套接字上发出 sendto()bind()。后者可让您选择要监听的端口。另一方面,Sendto() 将为您选择一个临时端口。我希望端口将保持为零,直到您执行这两件事之一。

澄清

在收到一些评论后,我对此进行了更多调查。根据Single UNIX Specification调用 socket() 的结果是一个未绑定(bind) 套接字。通过调用 bind() 显式绑定(bind)套接字或隐式地 sendto()

将套接字的名称视为包含其(地址族、协议(protocol)、本地 IP 地址和本地端口号)的元组。前两个在 socket() 调用中指定,后两个通过调用 bind() 指定。在无连接协议(protocol)的情况下,在断开连接的套接字上调用 sendto() 将导致隐式绑定(bind)到操作系统选择的端口号。

最令人惊讶的是,我能找到的关于此行为的唯一引用是在 Microsoft documentation for sendto() 的备注部分。 .

If the socket is unbound, unique values are assigned to the local association by the system and the socket is then marked as bound. An application can use getsockname (Windows Sockets) to determine the local socket name in this case.

getsockname() 的单一 UNIX 规范状态:

If the socket has not been bound to a local name, the value stored in the object pointed to by address is unspecified.

似乎带有未指定结果的成功返回是“标准”行为...嗯...我尝试过的所有实现都成功返回,套接字地址为 0.0.0.0 :0 对应于具有未指定端口的 INADDR_ANY。在调用 bind()sendto() 之后,getsockname() 返回一个填充的套接字地址,尽管地址部分可能仍然是 INADDR_ANY

关于c++ - UDP套接字端口分配失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1516972/

相关文章:

c++ - 为什么main函数不能返回负数?

c++ - 平衡二叉搜索树 (BST)

c++ - 通过套接字发送二进制文件。文本文件有效,没有别的吗?

c++ - 无法创建顶点缓冲区

c++ - 在 C++ 中键入安全(r)位标志?

c++ - 为什么在服务器和客户端的 sin_port 中指定相同的端口?

通过 HTTP 代理的 Java TCP 数据包

c++ - 使用 libuv 接收 UDP 数据包时如何知道目标地址和端口?

异步任务中的Android setText

c - sendto和recvfrom之间的性能差异