Search code examples
csockets

C trying to understand select() and FD_ISSET()


Im trying to make a basic non blocking chat client, but i cant really understand select() and FD_ISSET(). im trying to listen to the socket with the code below, but it wont work, it doesn't print anything, why not?

#include <string.h>
#include <netdb.h>
#include <sys/socket.h>
#include <sys/types.h>

int main(int argc, char const* argv[])
{
   fd_set readfs;
   char sendline[100];
   char str[100];
   char *some_addr;
   int listen_fd, comm_fd;

   struct sockaddr_in servaddr;

   listen_fd = socket(AF_INET, SOCK_STREAM, 0);

   //Socket error
   if (listen_fd == -1) {
      printf("Error on getting socket, Exiting!\n");
      return 1;
   }
   bzero(&servaddr, sizeof(servaddr));

   servaddr.sin_family = AF_INET;
   servaddr.sin_addr.s_addr = htons(INADDR_ANY);
   servaddr.sin_port=htons(22000);

   bind(listen_fd, (struct sockaddr *) &servaddr, sizeof(servaddr));

   listen(listen_fd, 10);

   comm_fd = accept(listen_fd, (struct sockaddr *) NULL, NULL);

   FD_ZERO(&readfs);
   FD_SET(comm_fd, &readfs);

   while (1)
   {
      select(listen_fd,&readfs, NULL, NULL, NULL);
      if(FD_ISSET(listen_fd,&readfs))
      {
         bzero(str,100);
         read(listen_fd,str,100);
         printf("%s", str);
         /* write(listen_fd, "read!", strlen(str)+1); */
      }
   }
   return 0;
}

EDIT: My code trying to Connect to the server:

#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdio.h>
#include<string.h>

int main(int argc,char **argv)
{
    int sockfd,n;
    char sendline[100];
    char recvline[100];
    struct sockaddr_in servaddr;

    sockfd=socket(AF_INET,SOCK_STREAM,0);
    bzero(&servaddr,sizeof servaddr);

    servaddr.sin_family=AF_INET;
    servaddr.sin_port=htons(22000);

    inet_pton(AF_INET,"127.0.0.1",&(servaddr.sin_addr));

    connect(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr));

    while(1)
    {
        bzero( sendline, 100);
        bzero( recvline, 100);
        fgets(sendline,100,stdin); /*stdin = 0 , for standard input */

        write(sockfd,sendline,strlen(sendline)+1);
        read(sockfd,recvline,100);
        printf("%s\n",recvline);
    }

    return 0;
}

Solution

  • Four major problems, here:

    1. Your select() call and the read/write loop should be using comm_fd, not listen_fd. If you call select() on listen_fd it'll return when there is an accept()able connection available, but you want to wait on the connected socket you already have for input, so use comm_fd.

    2. The first argument to select() should be the highest file descriptor in the sets plus one. Since you only have one file descriptor, here, it should be comm_fd + 1.

    3. You should move your FD_ZERO and FD_SET macros inside the while loop, and execute them prior to every select() call, because select() is going to modify those fd sets you pass to it.

    4. You don't check the return from your system calls for errors. You should.

    Other points:

    1. bzero() has been removed from POSIX for quite some time, now, you should be using the standard memset() instead.

    2. You shouldn't pass INADDR_ANY though htons(), just use it as it is.

    3. It's only a comment in your program, but while STDIN_FILENO may be 0, stdin is a FILE pointer, and is not 0.