簡體   English   中英

如何強制 udp 服務器接收到的 udp 客戶端套接字綁定到特定的客戶端端口

[英]How do I force a udp client socket received by a udp server to bind to a specific client port

我需要通過 udp 連接兩個程序。 這種工作方式是兩個程序都是 udp 服務器,它們在兩個端口上發送和接收,如下所示:

programA 偵聽端口 20037 並在端口 20038 上發送。 programB 偵聽端口 20038 並在端口 20037 上發送。

programA 和 programB 都運行在同一台計算機上。

programA 已經寫好了,它確實像上面那樣綁定了它的套接字。 即傳輸端口 = 20038 和偵聽端口 = 20037。

我寫了一個udp程序作為programB。

我的程序 B 將服務器套接字綁定到端口 20038,這是正確的。

但是當 programB 收到來自 programA 的消息時,客戶端套接字似乎綁定到某個隨機端口,例如端口 10690。但我需要它綁定到端口 20037。

使用的協議,需要在收到消息時發回一個簡單的 ack 消息。

我的代碼如下所示:

struct sockaddr_in client;
char buffer[BUFFER_SIZE];
/* Loop and get data from clients */
while (1)
{
    int client_length = (int)sizeof(struct sockaddr_in);

    /* Receive bytes from client */
int bytes_received = recvfrom(sd, buffer, BUFFER_SIZE, 0, (struct sockaddr *)&client, &client_length);
if (bytes_received < 0)
{
        fprintf(stderr, "Could not receive datagram.\n");
        closesocket(sd);
        WSACleanup();
        exit(0);
    }

    printf("%u bytes received from client on port %u\n", bytes_received, client.sin_port);
    SendAck();
}

而 SendAck() 是這樣的:

void udpserver::SendAck() {

    unsigned char acker[] = { SOM, ACK };
    int length = sizeof(acker)/sizeof(acker[0]);

    int client_length = (int)sizeof(struct sockaddr_in);
    if (sendto(sd, (const char*)acker, length, 0, (struct sockaddr *)&client, client_length) == -1)
    {
        fprintf(stderr, "Error transmitting data.\n");
        closesocket(sd);
        WSACleanup();
        exit(0);
    }
    else
        printf("successfully sent ack to client\n");
}

我假設收到的客戶端套接字的端口號是 20037,但它是一個隨機數。 我可以強制客戶端套接字綁定到端口 20037 嗎? 因為 ack 消息必須發送到端口 20037。

我不能改變這個設計。 ProgramA 將始終綁定到偵聽端口 20037 並通過將其客戶端端口綁定到 20038 來發送。我可以自由地執行 programB 所需的任何操作。

將套接字綁定到要用作出站端口的端口:

client.sin_port = htons(20037);

然后發送:

sendto(sd, (const char*) acker, length, 0,
        (struct sockaddr*) &client, client_length);

recvfrom()報告接收到的數據包是從遠程 IP/端口發送的。 ProgramA 正在從端口 20038 發送數據。 SendAck()正在使用recvfrom()提供的客戶端信息調用sendto() recvfrom() ,這意味着 ACK 正在發送到端口 20038,而不是端口 20037。

UDP 系統向與發送端口不同的端口發送回復是不常見的。 但就這樣吧。 您必須告訴sendto()要發送到哪個端口。

您也沒有正確記錄發件人的端口。 client.sin_port以網絡字節順序表示。 在記錄時使用ntohs()將其更改為主機字節順序。 不這樣做會導致您看到的隨機數。

嘗試這個:

struct sockaddr_in client;
char buffer[BUFFER_SIZE];

/* Loop and get data from clients */
while (1)
{
    int client_length = (int)sizeof(struct sockaddr_in);

    /* Receive bytes from client */
    int bytes_received = recvfrom(sd, buffer, BUFFER_SIZE, 0, (struct sockaddr *)&client, &client_length);
    if (bytes_received < 0)
    {
        fprintf(stderr, "Could not receive datagram.\n");
        closesocket(sd);
        WSACleanup();
        exit(0);
    }

    printf("%u bytes received from client at %s on port %u\n", bytes_received, inet_ntoa(client.sin_addr), ntohs(client.sin_port));

    SendAck(&client);
}

void udpserver::SendAck(struct sockaddr_in *client)
{
    struct sockaddr_in receiver;

    memcpy(&receiver, client, sizeof(struct sockaddr_in));
    receiver.sin_port = htons(20037);

    unsigned char acker[] = { SOM, ACK };
    int length = sizeof(acker)/sizeof(acker[0]);

    if (sendto(sd, (const char*)acker, length, 0, (struct sockaddr *)&receiver, sizeof(struct sockaddr_in)) == -1)
    {
        fprintf(stderr, "Error transmitting data.\n");
        closesocket(sd);
        WSACleanup();
        exit(0);
    }
    else
        printf("successfully sent ack to client at %s on port %d\n", inet_ntoa(receiver.sin_addr), ntohs(receiver.sin_port));
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM