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