Как использовать потоки с программированием сокетов UDP в C - PullRequest
0 голосов
/ 09 марта 2019

Я пытался написать простую программу, которая бы действовала как одноранговый узел в сети UDP P2P. На этом этапе я просто пытаюсь запустить потоки сервера и клиента, а затем общаюсь друг с другом. Однако когда оба запускаются как потоки, клиент никогда не получает ответ от сервера. Тем не менее, запуск только клиента в качестве потока работает нормально, но не будет работать в качестве решения для размещения в сети P2P, поскольку сервер должен быть потоком. Что-то не так в следующем коде, или я забыл управлять синхронизацией с потоками?

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#include <semaphore.h>
#include <sys/types.h> 
#include <sys/socket.h>
#include <sys/time.h>
#include <arpa/inet.h> 
#include <netinet/in.h> 

#define PORT 8080
#define MAXLINE 1024

struct Request {
    int sock;
    struct sockaddr_in cliaddr;
    char *msg;
    socklen_t len;
};


void *handle_send(void *varg) {
    struct Request *req = (struct Request *)varg;

    sendto(req->sock, (const char *)req->msg, strlen(req->msg), MSG_CONFIRM, (const struct sockaddr *) &(req->cliaddr), req->len); 
printf("Hello message sent by server.\n"); 

    return NULL;
}

void *server (void *varg) {
    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 n, rc;
    pthread_t threads[20];
    int thread_no = 0;
    socklen_t len;

    while (1) {
        n = recvfrom(sockfd, (char *)buffer, MAXLINE, MSG_WAITALL, (struct sockaddr *) &cliaddr, &len); 
        buffer[n] = '\0'; 
        printf("Client : %s\n", buffer); 
        struct Request *req = malloc(sizeof(struct Request)); 
        req->cliaddr = cliaddr;
        req->sock = sockfd;
        req->len = len;
        req->msg = hello;

        rc = pthread_create(&threads[thread_no], NULL, handle_send, (void *) req);
        thread_no++;

    }
}   

void *client (void *varg) {
    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); 
    } 

    struct timeval read_timeout;
    read_timeout.tv_sec = 0;
    read_timeout.tv_usec = 10;
    setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &read_timeout, sizeof(read_timeout));

    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;
    socklen_t len;

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

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

    close(sockfd); 

    return NULL;
}

int main(int argc, char *argv[]) { 
    int pserver, pclient;
    pthread_t p, c;

    pserver = pthread_create(&p, NULL, server, NULL);
    pclient = pthread_create(&c, NULL, client, NULL);

    pthread_join(c, NULL);
    pthread_join(p, NULL);

    return 0; 
}

Вывод, который я получаю при запуске кода:

Hello message sent by client.
Client : Hello from client
Hello message sent by server
Read -1 bytes
Server : 

Когда я запускаю сервер не как поток, а клиент как поток, клиент получает ответ от сервера и читает 17 или около того байтов независимо от длины ответа сервера. Тем не менее, переворот наоборот и запуск клиента как не потока, а сервера как потока приводит к тому же выводу, что и выше.

...