UDP套接字端口分配失败

发布于 2024-08-06 20:26:52 字数 2856 浏览 8 评论 0 原文

我正在创建一个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);
}

I am creating a winsock UDP program. code i am using is shown below.

I am always getting port assignment error.

I am not able to understand why port always allocated is zero. If some can help me with this....

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);
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

怪我闹别瞎闹 2024-08-13 20:26:52

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

澄清

在发表一些评论后,我对此进行了更多研究。根据 单一 UNIX 规范 调用 socket() 的结果 是一个未绑定套接字。通过调用 bind() 显式绑定套接字。 或隐式sendto()

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

最令人惊讶的是,我能找到的对此行为的唯一参考是 sendto() 的 Microsoft 文档。

如果套接字未绑定,系统会为本地关联分配唯一值,然后将套接字标记为已绑定。在这种情况下,应用程序可以使用 getsockname(Windows 套接字)来确定本地套接字名称。

getsockname() 的单一 UNIX 规范指出:

如果套接字尚未绑定到本地名称,则存储在地址指向的对象中的值是未指定的。

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

UDP doesn't bind to the listening port until you either issue a sendto() or a bind() on the socket. The latter lets you select the port that you want to listen on. Sendto(), on the other hand, will pick an ephemeral port for you. I would expect that the port will remain zero until you do one of these two things.

Clarification

I looked into this a little more after some of the comment. According to the Single UNIX Specification the result of calling socket() is an unbound socket. A socket is bound explicitly by calling bind() or implicitly sendto().

Think of a socket's name as a tuple containing its (Address Family, Protocol, local IP Address, and local Port Number). The first two are specified in the socket() call and the last two by calling bind(). In the case of connectionless protocols, a call to sendto() on a disconnected socket will result in an implicit bind to an OS chosen port number.

The most surprising thing is that the only reference that I can find to this behavior is in the remarks section of the 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.

The Single UNIX Specification for getsockname() states:

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

It seems that a successful return with an unspecified result is the "standard" behavior... hmmm... The implementations that I have tried all return successfully with a socket address of 0.0.0.0:0 which corresponds to INADDR_ANY with an unspecified port. After calling either bind() or sendto(), getsockname() returns a populated socket address though the address portion might still be INADDR_ANY.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文