Как протестировать и запустить клиент-серверную программу на C ++ с использованием Eclipse - PullRequest
0 голосов
/ 27 мая 2019

Я пытаюсь начать работу с UDP и хотел бы протестировать и отладить некоторые клиент-серверные программы.

Я использую Eclipse IDE с cygwin64 в качестве компилятора.

Я нашел несколько примеров клиент-серверных программ здесь: https://www.geeksforgeeks.org/udp-server-client-implementation-c/

Я хотел бы иметь возможность запустить этот пример, чтобы начать изучать клиентские серверы UDP.

Пример кода выглядит следующим образом:

Сервер

    // Server side implementation of UDP client-server model
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>

#define PORT     8080
#define MAXLINE 1024

// Driver code
int main() {
    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 = INADDR_ANY;
    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);
    }



    int len, 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),
        0, (const struct sockaddr *) &cliaddr,
            len);
    printf("Hello message sent.\n");

    return 0;
}

Клиент

// Client side implementation of UDP client-server model 
#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <string.h> 
#include <sys/types.h> 
#include <sys/socket.h> 
#include <arpa/inet.h> 
#include <netinet/in.h> 

#define PORT     8080 
#define MAXLINE 1024 

// Driver code 
int main() { 
    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 = INADDR_ANY; 

    int n, 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); 

    close(sockfd); 
    return 0; 
} 

Я попытался открыть два разных рабочих места затмения и запустить оба кода, но он работает не так, как ожидалось, и говорит, что сообщения были отправлены, но я не смог получить их на клиенте или сервере.

Я определенно хотел бы придерживаться c / c ++ и попытаться заставить это работать в затмении, если это возможно.

Если у кого-нибудь есть какой-либо совет о том, как я могу увидеть какие-то результаты или что-нибудь, что могло бы помочь мне начать с этим, было бы очень признательно. Спасибо!

1 Ответ

2 голосов
/ 27 мая 2019

Задача

Вы неправильно указали адрес сервера в коде клиента.

servaddr.sin_addr.s_addr = INADDR_ANY;

не имеет смысла при отправке (Почему вы хотите отправить на любой доступный адрес? Вы хотите отправить на сервер.) И отклоняется sendto. Вы бы видели это, если бы проверили возвращаемое значение. Всегда проверяйте возвращаемое значение, даже для связи UDP. Конечно, существует миллион причин, по которым пакет не будет доставлен с UDP, который вы не можете обнаружить во время sendto, но хорошо знать, что сетевой стек фактически принял сообщение, даже если grue впоследствии пожирает пакет в одном из темных углов Интернета. Ошибка отправки, с которой вы можете что-то сделать, например perror, и затем исправить код соответствующим образом. Грю, не так много. Вам нужно будет сделать протокол достаточно надежным, чтобы повторно передать или иным образом пережить потерю пакета.

Решение

Получить адресную структуру сервера с помощью getaddrinfo.

Заменить

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

с чем-то похожим на

struct addrinfo hints;
struct addrinfo *hostlist;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_flags = 0;
hints.ai_protocol = IPPROTO_UDP; 

if (getaddrinfo("Server Name or Address Goes Here",
                PORT, // this needs to be a char *, not an integer
                &hints,
                &hostlist))
{
    // handle error
    exit(EXIT_FAILURE);
}

PORT в этом случае должно быть char *, поэтому вместо

#define PORT     8080 

использование

constexpr char const * PORT = "8080";

Вы можете не указывать constexpr, если ваш компилятор старый и не поддерживает его.

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

struct addrinfo *curhost;
for (curhost = hostlist; curhost != NULL; curhost = curhost->ai_next)
{
    int rval = sendto(sockfd,
                      (const char *) hello,
                      strlen(hello),
                      0,
                      curhost->ai_addr,
                      curhost->ai_addrlen);
    if (rval> 0) // always check return codes. Programmers are lazy. 
                 // They wouldn't have gone to the effort of putting
                 // it there if it wasn't important.
    {
        if server responds
            do protocol stuff to complete transaction
            break;
    }
}
freeaddrinfo(hostlist); // thou shalt not leak resources.
if (curhost == nullptr)
{
    notify user that no server was willing to talk
}

Документация для getaddrinfo.

...