user3132755
user3132755

Reputation: 23

Unix C program---socket and select function

I am just start learning Unix C programming and there is a question I cannot solve. In this program, I made a simple server with socket and select function. When I use different terminals to start client programs which tried to connect server, the server can accept new client and make connection successfully(print a sentence, according to my code). However, when I tried to send message in client program to server(by scanf() and send() ) in client program, the server just block there and no message can be received. Would you please help me find the defect in my program? Thanks very much for any suggestion!! Here is my server program's code( there is no problem in client program, I think):

  1 #include <stdio.h>
  2 #include <unistd.h>
  3 #include <stdlib.h>
  4 #include <sys/types.h>
  5 #include <sys/socket.h>
  6 #include <netinet/in.h>
  7 #include <string.h>
  8 #include <fcntl.h>
  9 #include <sys/select.h>
 10 //all kinds of header 
 11 main(){
 12     int sfd;  //server's file descriptor 
 13     int fdall[100];  //array for client descriptor 
 14     int count=0;  //total number of clients
 15     int maxfd=0;   // max value of all descriptors
 16     char buf[1024]={0}; //used for receiving message from client, by recv()
 17     fd_set fds;  // readset in select()
 18     sfd=socket(AF_INET,SOCK_STREAM,0);
 19 
 20     struct sockaddr_in add;
 21     add.sin_family=AF_INET;
 22     add.sin_port=htons(9999);
 23     add.sin_addr.s_addr=inet_addr("192.168.122.1");
 24     int i,j,r;
 25 
 26     r=bind(sfd,(struct sockaddr*)&add,sizeof(add));
 27     if(r==-1) printf("bind:%m\n"),exit(-1);
 28     else puts("bind ok!");
 29     listen(sfd,10);
 30 
 31     while(1){
 32         FD_ZERO(&fds);
 33         maxfd=0;
 34         FD_SET(sfd,&fds);
 35         maxfd=maxfd>sfd?maxfd:sfd;
 36         for(i=0;i<100;i++){
 37             fdall[i]=-1;
 38         }
 39         r=select(maxfd+1,&fds,0,0,0);
 40         if(FD_ISSET(sfd,&fds)){
 41             fdall[count]=accept(sfd,0,0);
 42             puts("new client!");
 43             count++;
 44         }
 45         for(i=0;i<count;i++){
 46             if(FD_ISSET(fdall[i],&fds)!=-1&&fdall[i]!=-1){
 47                 r=recv(fdall[i],buf,1023,0);
 48                 for(j=0;j<count;j++){
 49                     if(fdall[j]!=-1){
 50                         send(fdall[j],buf,r,0);
 51                     }
 52                 }
 53             }
 54         }
 55     }
 56 }

Upvotes: 0

Views: 820

Answers (2)

Marian
Marian

Reputation: 7472

There several problems with your current code:

1.) There is always only one socket set in your fds set. It is the socket where you are listening for new connections. You probably want to put there all sockets connected to clients too.

2.) The test FD_ISSET(fdall[i],&fds)!=-1 has no sense. FD_ISSET(fdall[i],&fds) is something like a boolean value to be tested for equality/disequality to zero only.

3.) Your test FD_ISSET(fdall[i],&fds) always results to zero, because you have cleared all values (except sfd) in fds. Note that select never adds file descriptors to the set. It removes those which would block on next I/O operation.

4.) At each pass of the big loop you set fdall[i] to -1 although the previous value may be an open socket and you never close the socket.

It seems to me that you need to rethink the basic functionality. You shall set fdall[i] to -1 before the big loop. In the loop you shall add all sockets from fdall[i] to fds. When a new client connects you shall skip at the next loop iteration in order to avoid testing of FD_ISSET with this new socket (which is probably beyond the value maxfd for which select was called). Hope it helps.

Upvotes: 0

abligh
abligh

Reputation: 25129

You cannot use scanf to read from a socket. scanf will read from STDIN; that's what is causing your blocking. You cannot use fscanf either, as that will require a FILE *, and though it is possible with freopen to make a file from a socket, it will assume it can sit there and read to its heart's content, rather than using select.

What you will need to do is read from the socket into a buffer. When you have the appropriate amount of data (perhaps delimited by a newline), then use sscanf (note additional s), having ensured the string you are parsing is NUL terminated.

Upvotes: 1

Related Questions