使用select而不是fork

时间:2013-04-04 19:00:58

标签: c sockets tcp

在查看Beej的网络编程指南之后,我正在尝试使用select而不是fork来重做我的server.c.我不太确定会出现什么问题;我的程序编译,但不接受连接。我知道我的包含i< = fdmax的循环功能不正常,但我无法弄清楚原因。似乎if语句不能正常工作。

#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <sys/wait.h>
#include <errno.h>
#include <sys/select.h>

#define Connections 5

void SignalCatcher(int signum)
{
   wait3(NULL,WNOHANG, NULL);
   //wait(-1);
}

int main(int argc, char**argv)
{
   int listenfd,connfd,n, i;
   struct sockaddr_in servaddr,cliaddr;
   socklen_t clilen;
   pid_t     childpid;
   char mesg[1000];
   FILE *inputFile;
   inputFile = fopen("movie.txt", "r");
   char returnMsg[1000];
   int fdmax, newfd;
   fd_set readfd;
   fd_set mastersocket;
   FD_ZERO(&mastersocket);
   FD_ZERO(&readfd);


   //Creating socket number
   listenfd=socket(AF_INET,SOCK_STREAM,0);

   //Setting up the internet address
   bzero(&servaddr,sizeof(servaddr));
   servaddr.sin_family = AF_INET;
   servaddr.sin_addr.s_addr=htonl(INADDR_ANY);
   servaddr.sin_port=htons(32000);
   bind(listenfd,(struct sockaddr *)&servaddr,sizeof(servaddr));

   //Listening for clients
   listen(listenfd,1024);
   FD_SET(listenfd, &mastersocket);
   fdmax=listenfd;

   //signal(SIGCHLD, SIG_IGN);
   signal(SIGCHLD, SignalCatcher);

   //Infinite loop that waits for/accepts connections.
   for(;;)
   {
      readfd = mastersocket;
      clilen=sizeof(cliaddr);
      if(select(fdmax+1, &readfd, NULL, NULL, NULL) == -1) {
       perror("select");
       exit(4);}
      //connfd = accept(listenfd,(struct sockaddr *)&cliaddr,&clilen);


      for(i=0; i<=fdmax;i++)
      {
       if (FD_ISSET(i, &readfd)){
        if(i==listenfd){
            printf("-SUCCESS\n");
            clilen = sizeof cliaddr;
            connfd = accept(listenfd,(struct sockaddr *)&cliaddr,&clilen); }



      if (connfd!=-1)
      {


     // if ((childpid = fork()) == 0)
     // {
         close (listenfd);

         for(;;)
         {

            n = recvfrom(connfd,mesg,1000,0,(struct sockaddr *)&cliaddr,&clilen);

            if (n == -1 /*&& errno == EWOULDBLOCK*/) continue;
            else if(n==0) break;
            //sendto(connfd,mesg,n,0,(struct sockaddr *)&cliaddr,sizeof(cliaddr));
        //write(connfd , mesg , strlen(mesg)); //both work
            //write(connfd , "" , 1);
            printf("-------------------------------------------------------\n");
            printf("%d",listenfd);
            mesg[n] = 0;
            printf("Received the following:\n");
            printf("%s",mesg);
            printf("-------------------------------------------------------\n");

         }

     // } 
      close(connfd);

      } //if connfd!=-1
     } 
    } //for i<=fdmax
   }
}

3 个答案:

答案 0 :(得分:2)

您可以通过检查函数的返回值来自己回答这个问题。在网络编程中,通常的习惯用语是:

if (foo() < 0) {
        fprintf(stderr, "foo: %s\n", strerror(errno));
        /* recover from error or... */
        exit(EXIT_FAILURE);
}

...其中foo()bind()listen()accept()send*/recv*()之一,等等。

继续尝试。 errno会告诉你什么是错的。

此外,目前还不清楚为什么要使用select()。您所做的只是在一个插槽上侦听,并在有人连接后立即关闭它。相反,你可以accept(listenfd)

答案 1 :(得分:1)

首先你不应该在退出程序时关闭它应该关闭的监听fd。其次,我们需要接受在侦听套接字上排队的所有传入连接。然后,如果侦听套接字不可读,则现有连接必须是可读的,因此请读取该连接的数据。我只读过一次,但是你可以在循环中读取该连接,直到recv失败。

以下代码更改应该有效:

   //Infinite loop that waits for/accepts connections.
   for(;;)
   {
      readfd = mastersocket;
      clilen=sizeof(cliaddr);

      if(select(fdmax+1, &readfd, NULL, NULL, NULL) == -1) {
       perror("select");
       exit(4);}
      //connfd = accept(listenfd,(struct sockaddr *)&cliaddr,&clilen);


     for(i=0; i<=fdmax;i++)
     {
       if (FD_ISSET(i, &readfd)){
         if(i==listenfd){
            printf("-SUCCESS\n");
            clilen = sizeof cliaddr;
            connfd = accept(listenfd,(struct sockaddr *)&cliaddr,&clilen); 
              if (connfd!=-1)
              {
                    FD_SET(connfd, &mastersocket);
                    if (connfd > fdmax) {
                        fdmax = connfd;
                    }
              }
         }
         else
         {
            n = recvfrom(i,mesg,1000,0,(struct sockaddr *)&cliaddr,&clilen);
            if ((n == -1 /*&& errno == EWOULDBLOCK*/)  || (n==0)) {
                 close (i);
                 FD_CLR (i, &mastersocket);
                  if (i == fdmax)
                  {
                     while (FD_ISSET(fdmax, &mastersocket) == 0)
                        fdmax -= 1;
                  }
            }
            //sendto(i,mesg,n,0,(struct sockaddr *)&cliaddr,sizeof(cliaddr));
            //write(i , mesg , strlen(mesg)); //both work
            //write(i , "" , 1);
            printf("-------------------------------------------------------\n");
            printf("%d",listenfd);
            mesg[n] = 0;
            printf("Received the following:\n");
            printf("%s",mesg);
            printf("-------------------------------------------------------\n");
         }
     } 
    } //for i<=fdmax
  }

答案 2 :(得分:0)

我尝试使用更改代码,对我来说工作正常。 此外,如果您希望一次只有一个客户端与服务器通信,则启用while循环以读取客户端数据。

server.c

#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <sys/wait.h>
#include <errno.h>
#include <sys/select.h>

#define Connections 5

void SignalCatcher(int signum)
{
   wait3(NULL,WNOHANG, NULL);
   //wait(-1);
}

int main(int argc, char**argv)
{
   int listenfd,connfd,n, i;
   struct sockaddr_in servaddr,cliaddr;
   socklen_t clilen;
   pid_t     childpid;
   char mesg[1000];
   FILE *inputFile;
   inputFile = fopen("movie.txt", "r");
   char returnMsg[1000];
   int fdmax, newfd;
   fd_set readfd;
   fd_set mastersocket;
   FD_ZERO(&mastersocket);
   FD_ZERO(&readfd);

   //Creating socket number
   listenfd=socket(AF_INET,SOCK_STREAM,0);

   //Setting up the internet address
   bzero(&servaddr,sizeof(servaddr));
   servaddr.sin_family = AF_INET;
   servaddr.sin_addr.s_addr=htonl(INADDR_ANY);
   servaddr.sin_port=htons(32000);
   bind(listenfd,(struct sockaddr *)&servaddr,sizeof(servaddr));

   //Listening for clients
   listen(listenfd,1024);
   FD_SET(listenfd, &mastersocket);
   fdmax=listenfd;

   //signal(SIGCHLD, SIG_IGN);
   signal(SIGCHLD, SignalCatcher);

   //Infinite loop that waits for accepts connections.
   for(;;)
   {
      readfd = mastersocket;
      clilen=sizeof(cliaddr);

      if(select(fdmax+1, &readfd, NULL, NULL, NULL) == -1) {
       perror("select");
       exit(4);}
      //connfd = accept(listenfd,(struct sockaddr *)&cliaddr,&clilen);


     for(i=0; i<=fdmax;i++)
     {
       if (FD_ISSET(i, &readfd)){
         if(i==listenfd){
            printf("-SUCCESS\n");
            clilen = sizeof cliaddr;
            connfd = accept(listenfd,(struct sockaddr *)&cliaddr,&clilen); 
              if (connfd!=-1)
              {
                    FD_SET(connfd, &mastersocket);
                    if (connfd > fdmax) {
                        fdmax = connfd;
                    }
              }
         }
         else
         {
            //while(1) {
                n = recvfrom(i,mesg,1000,0,(struct sockaddr *)&cliaddr,&clilen);
                if ((n == -1 /*&& errno == EWOULDBLOCK*/)  || (n==0)) {
                     close (i);
                     FD_CLR (i, &mastersocket);
                      if (i == fdmax)
                      {
                         while (FD_ISSET(fdmax, &mastersocket) == 0)
                            fdmax -= 1;
                      }
                    // break;
                }
                //sendto(i,mesg,n,0,(struct sockaddr *)&cliaddr,sizeof(cliaddr));
                //write(i , mesg , strlen(mesg)); //both work
                //write(i , "" , 1);
                printf("-------------------------------------------------------\n");
                printf("%d",listenfd);
                mesg[n] = 0;
                printf("Received the following:\n");
                printf("%s",mesg);
                printf("-------------------------------------------------------\n");
             }
         //} /* end of while */
     } 
    } //for i<=fdmax
  }
}

client.c

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>
#include <unistd.h> 
#include <stdlib.h>
#include <string.h>

#define SERVER_PORT 32000

int main (int argc, char *argv[]) {

  int sd, rc, i;
  struct sockaddr_in localAddr, servAddr;
  struct hostent *h;
  char message[1000] ;

  servAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
  servAddr.sin_family = AF_INET;
  servAddr.sin_port = htons( SERVER_PORT );

  /* create socket */
  sd = socket(AF_INET, SOCK_STREAM, 0);
  if(sd<0) {
    perror("cannot open socket ");
    exit(1);
  }

  /* bind any port number */
  localAddr.sin_family = AF_INET;
  localAddr.sin_addr.s_addr = htonl(INADDR_ANY);
  localAddr.sin_port = htons(0);

  rc = bind(sd, (struct sockaddr *) &localAddr, sizeof(localAddr));
  if(rc<0) {
    printf("%s: cannot bind port TCP %u\n",argv[0],SERVER_PORT);
    perror("error ");
    exit(1);
  }

    /* connect to server */
    rc = connect(sd, (struct sockaddr *) &servAddr, sizeof(servAddr));
    if(rc<0) {
        perror("cannot connect ");
        exit(1);
    }

   while(1)
   {
        printf("Enter message : ");
        scanf("%s" , message);
        rc = send(sd, message, strlen(message) + 1, 0);

        if(rc<0) {
          perror("cannot send data ");
          close(sd);
          exit(1);
        }
        printf("To_server: data%u sent (%s)\n",strlen(message),message);
  }
  return 0; 
}