Я пытался написать простую программу, которая бы действовала как одноранговый узел в сети 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 или около того байтов независимо от длины ответа сервера. Тем не менее, переворот наоборот и запуск клиента как не потока, а сервера как потока приводит к тому же выводу, что и выше.