views:

65

answers:

4

Hi, I basically have a server set up and I'm accepting new clients(UNIX) and i'm using select() command to wait for activity on file descriptor but I'm not sure how to write from the clients side and then read it on the servers side

FD_ZERO(&readfds);
FD_SET(server_sockfd, &readfds);
FD_SET(STDIN_FILENO, &readfds); 
while (1) {
   testfds = readfds;
   select(4 + MAXCLIENTS, &testfds, NULL, NULL, NULL);
   for (fd = 0; fd < 4 + MAX_CLIENTS; fd++) {
     if (FD_ISSET(fd, &testfds)) {
        if (fd == server_sockfd) { /* new connection request */
           client_sockfd = accept(server_sockfd, NULL, NULL);
           if (num_clients < MAXCLIENTS) {
              FD_SET(client_sockfd, &readfds);
              num_clients++;
           } else {
              sprintf(message, "XSorry, too many clients.  Try again later.\n");
              write(client_sockfd, message, strlen(message));
              close(client_sockfd);
           }
        } else if (fd == STDIN_FILENO) { 
           fgets(kb_message, BUFSIZ + 1, stdin);
           if (strcmp(kb_message, "quit\n") == 0) {
              sprintf(message, "XServer is shutting down.\n");
              for (fd2 = 4; fd2 < 4 + MAX_CLIENTS; fd2++) {
                 if (FD_ISSET(fd2, &readfds)) {
                    write(fd2, message, strlen(message));
                    close(fd2);
                 }
              }
              close(server_sockfd);
              exit(EXIT_SUCCESS);
           } else {
              sprintf(message, "M%s", kb_message);
              for (fd2 = 4; fd2 < 4 + MAX_CLIENTS; fd2++)
                 if (FD_ISSET(fd2, &readfds))
                    write(fd2, message, strlen(message));
           }
        } else { /* client leaving */
           close(fd);
           FD_CLR(fd, &readfds);
           num_clients--;
        }
     }
  }

}

How would I handle write request from clients and then write back to them, would it be under "else" and how can I check if client is exiting or writing.

Thanks

A: 

Your problem might be that you have a variable called read. It's going to mask one of hte functions you need to use - the read() system call to get data out of the socket. The client puts it in with write(). You might also want to check the return value from select(), which will tell you how many of the file descriptors are ready for reading. Then you can check which ones using FD_ISSET(). It looks like you're doing that part already (except you seem to be checking the wrong variable?)... just call read() on that file descriptor to get out the data the client wrote.

Carl Norum
That's probably just a typo, he's using `readfds` in the loop after `select(2)`.
Nikolai N Fetissov
@Nikolai, yeah that's true. There's some weird casing on `StDIN_FILENO`, too. I guess this isn't the real code.
Carl Norum
+2  A: 

The most common mistake with select(2) is not re-initializing the descriptor sets, since second, third, and forth arguments are input-output parameters.

Setup an fd_set, for reading before the outer loop, add listening socket descriptor to it, enter the loop, make a copy of the this fd_set and give the copy to select(2). When new connection arrives, add its descriptor to the original fd_set. Same for closed socket (error or EOF on read(2)) - remove the descriptor from the original fd_set.

Hope this helps.

Nikolai N Fetissov
+1  A: 

You are correct in thinking you need the read code in your 'else' block. If a file descriptor triggers and it isn't stdin or the 'connect' descriptor, then it is one of your clients attempting to send you data. When one of those file descriptors is triggered in the select, you need to call 'read' on that descriptor to read the data into the buffer. The read command will return you the number of bytes read. If this is a positive number, then it indicates the client has sent you data. If it is zero, then that indicates that the client has ended the TCP connection to your server.

The else block will look something like:

 else 
  {
     //Existing connection has data for us to read
     if((nBytes = read(fd, buffer, MAXBUFFER)) <= 0) 
     {
        if(nBytes == 0)
        {
          //Actually, its sending us zero bytes, connection closed
          printf("Socket %d hung up\n", fd;
        }
     else
          printf ("Read Error"\n)
  }

Also, Follow Nikolai N Fetissov's advice above and make sure that when client's connect you store their fd in a permanent fd_set structure, as the one you are using is being modified by the select call.

bdk
Okay I'll try the above code....Thanks
Roberto
A: 
else 
{
  bzero(buf,100);
     n=read(i,buf,100); // Read the client message 
            buf[n]='\0';
       if(n==0) // Check the client is closed or not 
      {

              printf("%d is closed\n",i);
              close(i);
              FD_CLR(i, &master);
              if(i==fdmax)
              fdmax--;

       }
       else
       {
            n=strlen(buf);

        write(1,buf,n);
        fflush(stdout);

          write(1,"Enter the message\n",18);
          bzero(buf,100);
          read(0,buf,100);
            buf[n]='\0';
          write(i,buf,n);
          fflush(stdout);
       }
    } 

Notes: After accept the client, Add the client in the fd set. Then read the message from the client If the message is equal to 0, then the client is closed. If you want to send the message to the client, using the client fd, you can send to the client

muruga