UDP-клиент застревает в recvfrom только в конкретной ситуации - PullRequest
0 голосов
/ 03 апреля 2019

Я пишу код C ++, который реализует сервер и клиент UDP.

Код работает нормально, когда я пишу два кода, один для сервера, а другой для клиента, как в этом примере: https://www.geeksforgeeks.org/udp-server-client-implementation-c/.

Я пытаюсь написать функцию клиента и функцию сервера в одном и том же коде. Идея в том, что я выбираю, как программа будет работать с аргументом командной строки.

Проблема заключается в том, что, реализуя этот способ и тестируя на двух терминалах, выполняющих один и тот же код, с разными аргументами командной строки, один для сервера и другой для клиента, клиент застревает в recvfrom при получении ответа сервера.

#include <unistd.h> 
#include <stdio.h> 
#include <sys/socket.h> 
#include <stdlib.h> 
#include <netinet/in.h> 
#include <string.h> 
#include <arpa/inet.h>
#include <unistd.h>
#define MAXLINE 1024
#define PORT 32000

int send(){
    int sockfd; 
    char buffer[MAXLINE]; 
    char *hello = "Hello from server"; 
    struct sockaddr_in servaddr, cliaddr; 

    // Creating socket file descriptor 
    if ( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) { 
        perror("socket creation failed"); 
        exit(EXIT_FAILURE); 
    } 

    memset(&servaddr, 0, sizeof(servaddr)); 
    memset(&cliaddr, 0, sizeof(cliaddr)); 

    // Filling server information 
    servaddr.sin_family = AF_INET; // IPv4 
    servaddr.sin_addr.s_addr = inet_addr("127.0.0.1"); 
    servaddr.sin_port = htons(PORT); 

    // Bind the socket with the server address 
    if ( bind(sockfd, (const struct sockaddr *)&servaddr, 
            sizeof(servaddr)) < 0 ) 
    { 
        perror("bind failed"); 
        exit(EXIT_FAILURE); 
    } 

    socklen_t len;
    int n; 
    n = recvfrom(sockfd, (char *)buffer, MAXLINE, 
                MSG_WAITALL, ( struct sockaddr *) &cliaddr, 
                &len); 
    buffer[n] = '\0'; 
    printf("Client : %s\n", buffer); 
    sendto(sockfd, (const char *)hello, strlen(hello), 
        MSG_CONFIRM, (const struct sockaddr *) &cliaddr, 
            len); 
    printf("Hello message sent.\n"); 

    return 0; 
}

int receive(){
    int sockfd; 
    char buffer[MAXLINE]; 
    char *hello = "Hello from client"; 
    struct sockaddr_in   servaddr; 

    // Creating socket file descriptor 
    if ( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) { 
        perror("socket creation failed"); 
        exit(EXIT_FAILURE); 
    } 

    memset(&servaddr, 0, sizeof(servaddr)); 

    // Filling server information 
    servaddr.sin_family = AF_INET; 
    servaddr.sin_port = htons(PORT); 
    servaddr.sin_addr.s_addr = inet_addr("127.0.0.1"); 

    int n;
    socklen_t len; 

    sendto(sockfd, (const char *)hello, strlen(hello), 
        MSG_CONFIRM, (const struct sockaddr *) &servaddr, 
            sizeof(servaddr)); 
    printf("Hello message sent.\n"); 

    n = recvfrom(sockfd, (char *)buffer, MAXLINE, 
                MSG_WAITALL, (struct sockaddr *) &servaddr, 
                &len); 
    buffer[n] = '\0'; 
    printf("Server : %s\n", buffer); 

    return 0; 
}

int main(int argc, char const *argv[]) {

    int command = atoi(argv[1]);

    if(command == 0){
        send();

    }
    if(command == 1){
        receive();
    }


    return 0;
}

Ожидаемые результаты примерно такие, которые я получаю при запуске клиента и сервера на отдельных кодах:

Серверная сторона:

Привет от клиента

Привет, сообщение отправлено

Клиентская сторона:

Привет, сообщение отправлено

Привет с сервера

Но при запуске приведенного выше кода я получаю

Серверная сторона:

Привет от клиента

Привет, сообщение отправлено

Клиентская сторона:

Привет, сообщение отправлено

--- застревает здесь ---

Что я делаю не так?

1 Ответ

1 голос
/ 03 апреля 2019

В вашей функции send() вы не инициализируете len длиной буфера, где recvfrom может хранить адрес клиента.

В соответствии со страницей руководства для recvfrom:

ssize_t recvfrom (int sockfd, void * buf, size_t len, int flags, struct sockaddr * src_addr, socklen_t * addrlen);

Если src_addr не равен NULL, и базовый протоколпредоставляет адрес источника сообщения, этот адрес источника помещается в буфер, на который указывает src_addr.В этом случае addrlen является аргументом значение-результат.Перед вызовом он должен быть инициализирован до размера буфера, связанного с src_addr.По возвращении addrlen обновляется и теперь содержит фактический размер исходного адреса.

Он не работает, поскольку адрес клиента не принимается должным образом, поэтому ответное сообщение отправляется по неправильному адресу.Чтобы решить вашу проблему, вам просто нужно инициализировать len перед вызовом recvfrom:

socklen_t len = sizeof(cliaddr); // The size of the buffer you're passing to store the client address
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...