我尝试在C中编写简单的服务器,使用poll()来测试侦听套接字中的传入请求并创建一个服务请求的线程。在if-statement测试块fds[0].revents & POLLIN
中,每个请求创建一个线程,但printf
每个请求执行多次。
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/poll.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
struct sockaddr_in serverAddr, clientAddr;
struct pollfd fd[1];
socklen_t clientlen;
pthread_attr_t pattr;
int serverfd, optval = 1;
void *accreq(void *);
void make_request_thread();
void sig_handler(int);
int main(int argc, char *argv[])
{
signal(SIGINT, sig_handler);
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(80);
inet_pton(AF_INET, "127.0.0.1", &serverAddr.sin_addr.s_addr);
serverfd = socket(AF_INET, SOCK_STREAM, 0);
setsockopt(serverfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
bind(serverfd, (struct sockaddr *)&serverAddr, sizeof(serverAddr));
listen(serverfd, 5);
clientlen = sizeof(clientAddr);
fd[0].fd = serverfd;
fd[0].events = POLLIN;
pthread_attr_init(&pattr);
pthread_attr_setdetachstate(&pattr, PTHREAD_CREATE_JOINABLE);
while(1)
{
if(poll(fd, 1, -1) > 0)
{
if(fd[0].revents & POLLIN)
{
printf("Hello!\n"); /* Why this function executed more than once per incoming request*/
make_request_thread();
}
}
}//end while loop
return 0;
}
void *accreq(void *arg)
{
int saccfd = accept(serverfd, (struct sockaddr *)&clientAddr, &clientlen), port, rc, wc;
char buffer[2048], addr[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &clientAddr.sin_addr.s_addr, addr, INET_ADDRSTRLEN);
port = ntohs(clientAddr.sin_port);
printf("[Accept request from %s:%i]\n", addr, port);
rc = read(saccfd, buffer, sizeof(buffer));
printf("%s\n", buffer);
wc = write(saccfd, buffer, strlen(buffer));
close(saccfd);
pthread_exit(0);
}
void make_request_thread()
{
pthread_t thread_acc;
pthread_create(&thread_acc, &pattr, accreq, NULL);
}
void sig_handler(int signo)
{
printf("\nCatch signal interrupt\nExiting...\n");
pthread_attr_destroy(&pattr);
close(serverfd);
exit(0);
}
答案 0 :(得分:1)
你有竞争条件。比赛是在你的主线程之间,它将在接受套接字上再次调用poll()
,以及将在该套接字上调用accept()
的生成线程。如果调用accept()
的衍生线程获胜,则主线程将阻塞(如果只有一个传入连接)。如果主线程获胜,poll()
调用将立即返回,因为套接字仍有等待接受的挂起连接。
在您的代码中,您根本不需要使用poll()
。您可以简单地阻止对accept()
的调用,并为生成的线程提供新创建的套接字来处理。如果您真的想要poll()
,最简单的解决方法是在accept()
唤醒后在主线程中调用poll()
,并将新创建的套接字提供给生成的线程。