在if语句的poll()块中,每个请求多次触发函数

时间:2014-05-24 01:15:47

标签: c linux sockets

我尝试在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);
}

1 个答案:

答案 0 :(得分:1)

你有竞争条件。比赛是在你的主线程之间,它将在接受套接字上再次调用poll(),以及将在该套接字上调用accept()的生成线程。如果调用accept()的衍生线程获胜,则主线程将阻塞(如果只有一个传入连接)。如果主线程获胜,poll()调用将立即返回,因为套接字仍有等待接受的挂起连接。

在您的代码中,您根本不需要使用poll()。您可以简单地阻止对accept()的调用,并为生成的线程提供新创建的套接字来处理。如果您真的想要poll(),最简单的解决方法是在accept()唤醒后在主线程中调用poll(),并将新创建的套接字提供给生成的线程。