如何在C中使用线程与UDP套接字编程

时间:2019-03-08 23:19:46

标签: multithreading server udp client p2p

我一直在尝试编写一个简单的程序来充当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个左右的字节。但是,反过来,将客户端作为非线程运行,将服务器作为线程运行会产生与上述相同的输出。

0 个答案:

没有答案