2013-04-04 90 views
-1

在看了Beej的网络编程指南之后,我试图用select而不是fork来重做我的server.c。我不太确定发生了什么问题;我的程序编译,但不接受连接。我知道我的循环包含我< = fdmax不能正常工作,但我不明白为什么。似乎if语句不能正常工作。使用select而不是fork

#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 
    } 
} 
+0

当你说你的程序不接受连接,你的意思是接受调用失败,或者,你的程序只是阻止和永远接受接受电话? – maditya 2013-04-04 19:37:54

+0

目前,第一个客户端将连接并能够发送一条消息。之后,服务器不会再收到任何消息。如果客户端被终止,我得到错误“select:bad file descriptor” – krikara 2013-04-04 19:39:53

+0

那么,大概你的服务器正在进入for(;;)循环,所以接受更多客户端的代码不会执行。 for(;;)似乎击败了使用select()的目的。 – nos 2013-04-04 19:43:13

回答

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)

+2

虽然很好的建议,但它不是这个代码混淆的主要来源。代码关闭listenfd,这样自然会拒绝更多的客户端,代码也会进入一个循环,每次只处理一个连接。 – nos 2013-04-04 19:47:53

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 
    } 
+0

服务器仅重复客户端发送的第一条消息。然后客户端保持连接状态,但服务器不会重复所有客户端消息。我不明白为什么它不这样做,因为它不断重复for(i = 0; i <= fdmax; i ++)循环 – krikara 2013-04-04 21:02:29

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; 
}