Проблемы с UDP-сокетами и потоками - PullRequest
1 голос
/ 03 мая 2019

Я столкнулся с проблемой с UDP-сокетами.

Для этой конкретной программы один файл .c должен быть и клиентом для другого сервера (через TCP), и сервером / клиентом для себя (выполняется дважды, работает на отдельных серверах). Он будет работать дважды одновременно, и поскольку он должен иметь возможность одновременно выполнять подключение TCP (для одного типа данных) и соединение UDP (для другого типа данных), это необходимо сделать с нитями или вилками, но я использовал темы.

У меня проблема в том, что UDP-сокеты не получают дейтаграмм друг от друга. Нет ошибок компиляции, и он работает нормально, но нет выходных данных, кроме общих отладочных операторов печати. Он застревает в командах recvfrom.

Код ниже разделен на две части (опять же, в одном и том же файле .c). Верхняя часть - это раздел сервера, а нижняя часть - это раздел клиента. Это все сделано в потоке. Я попытался создать сокет ТО, вызывая поток с клиентским кодом (идея заключалась в том, что поток связывался бы с родителем, но это не имело значения), но он получал тот же результат. Итак, на данный момент поток обрабатывает только UDP-соединение, а родительский обрабатывает TCP.

Если вам нужно больше объяснений, пожалуйста, не стесняйтесь спрашивать. Это для школьного задания, поэтому я не могу дать СЛИШКОМ много, но я скажу, что могу.

Спасибо!

БЫСТРОЕ РЕДАКТИРОВАНИЕ: весь этот код, приведенный ниже, просто отправляет привет на сервер и обратно клиенту. Дальнейшие детали не нужны.

Предположим, что argv->stuff - это структура, которую я передал потоку, и что пользователь предоставляет сервер, IP-адрес и порт при выполнении.

//----- Server portion of code is below

int cli2_sockfd; 
char buffer_cli2[MAXLINE]; 
char *hello2 = "Hello from client 2"; 
struct sockaddr_in cli2_addr, client1_addr; 
int clis_portno = atoi(argv->port);
clis_portno = clis_portno + 1;

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

memset(&cli2_addr, 0, sizeof(cli2_addr)); 
memset(&client1_addr, 0, sizeof(client1_addr)); 

// Filling server information 
cli2_addr.sin_family = AF_INET; // IPv4 
cli2_addr.sin_addr.s_addr = INADDR_ANY; 
cli2_addr.sin_port = htons(clis_portno); 

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

while(1)
{
    int n2;
    socklen_t len2;
    if((n2 = recvfrom(cli2_sockfd, (char *)buffer_cli2, MAXLINE, 
                0, ( struct sockaddr *) &client1_addr, 
                &len2)) < 0)
    {
        perror("svr recvfrom");
        exit(EXIT_FAILURE);
    }

    buffer_cli2[n2] = '\0'; 
    printf("Client 1: %s\n", buffer_cli2); 

    if(sendto(cli2_sockfd, (const char *)hello2, strlen(hello2), 
        MSG_CONFIRM, (const struct sockaddr *) &client1_addr, 
            len2) < 0)
    {
        perror("svr sendto");
        exit(EXIT_FAILURE);
    }
    printf("Hello message sent.\n"); 
}


//----- The client portion of the code is below


int client1_sockfd; 
char buffer[MAXLINE]; 
char *hello1 = "Hello from client 1"; 
struct sockaddr_in   client2_addr; 
struct hostent *client_2;
clis_portno = atoi(argv->port);
clis_portno = clis_portno + 1;

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

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

if((client_2 = gethostbyname(argv->name)) == NULL)
{
    perror("cli gethostbyname");
    exit(EXIT_FAILURE);
}

bzero((char *) &client2_addr, sizeof(client2_addr));

// Filling Client 2 information 
client2_addr.sin_family = AF_INET; 
bcopy((char *)client_2->h_addr, (char *)&client2_addr.sin_addr.s_addr, client_2->h_length);
client2_addr.sin_port = htons(clis_portno); 

while(1)
{
    int n1;
    socklen_t len1;

    if( sendto(client1_sockfd, (const char *)hello1, strlen(hello1), 
        0, (const struct sockaddr *) &client2_addr, 
            sizeof(client2_addr)) < 0)
    {
        perror("cli sendto");
        exit(EXIT_FAILURE);
    }

    printf("IN THREAD: Hello1 = %s\n", hello1); 

    if((n1 = recvfrom(client1_sockfd, (char *)buffer, MAXLINE, 
                MSG_WAITALL, (struct sockaddr *) &client2_addr, 
                &len1)) < 0)
    {
        perror("cli recvfrom");
        exit(EXIT_FAILURE);
    }

    buffer[n1] = '\0'; 
    printf("IN THREAD: Client 2 : %s\n", buffer); 
}

Ответы [ 2 ]

0 голосов
/ 03 мая 2019

Я немного почистил ваш код и заставил его работать, используя порт 9999 для сервера.И клиент подключается к localhost.Я убрал некоторые из этих операторов memcpy вокруг gethostbyname, некоторые ваши вызовы инициализации структуры, удалил некоторые из вызовов exit, которые могут произойти из-за доброкачественных ошибок (включая ошибки recvfrom, когда сервер отключен).Этот флаг MSG_WAITALL выглядел странно, поэтому я тоже убрал его.

Я получил его, работая с Cygwin без каких-либо специальных взломов.Я не сомневаюсь, что он будет работать в Linux (или любом Unix).

Вы можете увидеть, как он работает здесь в режиме сервера:

enter image description here

И соответствующее окно в режиме клиента:

enter image description here

Код здесь:

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/time.h>
#include <stdlib.h>
#include <memory.h>
#include <ifaddrs.h>
#include <net/if.h>
#include <stdarg.h>

#define MAXLINE 260
#define MSG_CONFIRM "Confirm"

void server(unsigned short port)
{
    int cli2_sockfd = -1;
    char buffer_cli2[MAXLINE] = { 0 };
    char *hello2 = "Hello from client 2";
    struct sockaddr_in cli2_addr = { 0 }, client1_addr = { 0 };
    unsigned short clis_portno = port;

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

    // Filling server information 
    cli2_addr.sin_family = AF_INET; // IPv4 
    cli2_addr.sin_addr.s_addr = INADDR_ANY;
    cli2_addr.sin_port = htons(clis_portno);

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

    while (1)
    {
        int n2;
        socklen_t len2 = sizeof(client1_addr);
        if ((n2 = recvfrom(cli2_sockfd, (char *)buffer_cli2, MAXLINE,
            0, (struct sockaddr *) &client1_addr,
            &len2)) < 0)
        {
            perror("svr recvfrom");
            exit(EXIT_FAILURE);
        }

        buffer_cli2[n2] = '\0';
        printf("Client 1: %s\n", buffer_cli2);

        if (sendto(cli2_sockfd, (const char *)hello2, strlen(hello2),
            0, (const struct sockaddr *) &client1_addr,
            len2) < 0)
        {
            perror("svr sendto");
        }
        printf("Hello message sent.\n");

    }
}

void client(const char* hostname, unsigned short port)
{
    int client1_sockfd;
    char buffer[MAXLINE];
    char *hello1 = "Hello from client 1";
    struct sockaddr_in   client2_addr = { 0 };
    struct hostent *client_2 = NULL;
    unsigned short clis_portno = port;

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

    if ((client_2 = gethostbyname(hostname)) == NULL)
    {
        perror("cli gethostbyname");
        exit(EXIT_FAILURE);
    }

    // Filling Client 2 information 
    client2_addr.sin_family = AF_INET;
    client2_addr.sin_port = htons(clis_portno);
    memcpy(&client2_addr.sin_addr, client_2->h_addr, 4);

    while (1)
    {
        int n1;


        if (sendto(client1_sockfd, (const char *)hello1, strlen(hello1),
            0, (const struct sockaddr *) &client2_addr,
            sizeof(client2_addr)) < 0)
        {
            perror("cli sendto");
            exit(EXIT_FAILURE);
        }

        printf("IN THREAD: Hello1 = %s\n", hello1);

        socklen_t len1 = sizeof(client2_addr);
        if ((n1 = recvfrom(client1_sockfd, (char *)buffer, MAXLINE,
            0, (struct sockaddr *) &client2_addr,
            &len1)) < 0)
        {
            perror("cli recvfrom");
        }
        else
        {
            buffer[n1] = '\0';
            printf("IN THREAD: Client 2 : %s\n", buffer);
        }
        sleep(1);
    }
}




int main(int argc, char** argv)
{

    if ((argc > 1) && (strcmp(argv[1], "s") == 0))
    {
        printf("Running in server mode\n");
        server(9999);
    }
    else
    {
            printf("Running in client mode\n");
            client("localhost", 9999);
    }
    return 0;
}
0 голосов
/ 03 мая 2019

Вы забыли инициализировать len2:

socklen_t len2;
if((n2 = recvfrom(cli2_sockfd, (char *)buffer_cli2, MAXLINE, 
            0, ( struct sockaddr *) &client1_addr, 
            &len2)) < 0)

Лучше:

socklen_t len2 = sizeof(client1_addr);
n2 = recvfrom(cli2_sockfd, (char *)buffer_cli2, MAXLINE, 
        0, ( struct sockaddr *) &client1_addr, 
        &len2));
if (n2 < 0)
{
   ….

Не уверен, что это ваша единственная проблема, препятствующая получению пакетов.

...