Thread: accepting clients from server with select, need help with select()

  1. #1
    Registered User
    Join Date
    Feb 2019
    Posts
    7

    accepting clients from server with select, need help with select()

    Ive been recommended by another user Salem to use select(..) instead of threading for this implementation.

    Im not sure why Im getting these unexpected behaviors

    * when I put a printf() before the select it does not print.
    * once I get a new connection, it doesn't wait for select()
    * if I close the server program it will close my client


    On my server I will setup a TCP socket to listen on and send it to accept_connections(..)

    accept_connections(..) will use select(..) to handle the new incoming connections and to monitor the client file descriptors.

    after new connection I simply send a message back to client with greet_client(..)


    so far,

    I've tried to reinitialize the master set and working set at the top of each iteration , by using FD_ZERO(..) on master set at the top of the loop and then put the client fd's back into the set using an array.

    Code:
    
    void accept_connections(int accept_sock){
    
    
      fd_set master_set;
      fd_set working;
      FD_ZERO(&master_set);
      FD_SET(accept_sock,&master_set);
      
      int maxfd = accept_sock;
      int result;
    
    
    
    
      for(;;){
            
           printf(" hello wolld ");   <----------- if I put this here it will print infinitely ONLY after the first connection made
    
            memcpy(&working, &master_set, sizeof(working));
            result = select(maxfd + 1, &working, NULL, NULL, NULL);
    
    
            if(result == 0){
              printf("select timed out! \n");
            }
    
    
            else if(result < 0){
              printf("select error! \n");
            }
    
    
            else{
              if(FD_ISSET(accept_sock,&working)){
    
    
                int client_sock;
                struct sockaddr_in client_address;
                unsigned int client_address_len; 
                client_address_len = sizeof(client_address);
    
    
                client_sock = accept(accept_sock,(struct sockaddr *)&client_address, &client_address_len);
                       
                if(maxfd < client_sock){
                   maxfd = client_sock;
                }
            
                FD_SET(client_sock,&master_set);
               
               greet_client(client_sock);
              }
      
               ...else receive client IO
           
            }
      }
    }
    Last edited by frododo1; 02-27-2019 at 02:59 PM.

  2. #2
    Registered User
    Join Date
    Feb 2019
    Posts
    499
    printf() uses stdout, which is line buffered. Try to call fflush(stdout); to flush the buffer (or add a '\n' char at the end of the stream).

    fd_set is supposed to be an opaque type. Copying with memcpy() may not work properly. Why are you making this copy?

    Prefeer to use poll() or epoll() syscalls. They are faster, more flexible and easier to use (epoll() is slightly complicated, but faster than poll()).

    There is also libevent (the faster approach!)... This is used by Apache/nginx, nowadays....

  3. #3
    Registered User
    Join Date
    Feb 2019
    Posts
    7
    Quote Originally Posted by flp1969 View Post
    printf() uses stdout, which is line buffered. Try to call fflush(stdout); to flush the buffer (or add a '\n' char at the end of the stream).

    fd_set is supposed to be an opaque type. Copying with memcpy() may not work properly. Why are you making this copy?

    Prefeer to use poll() or epoll() syscalls. They are faster, more flexible and easier to use (epoll() is slightly complicated, but faster than poll()).

    There is also libevent (the faster approach!)... This is used by Apache/nginx, nowadays....
    I was using memcpy() bc I saw it in an example.
    Originally I was just using "copyset = masterset".

    libevent or poll() instead of select()?

    ughh okay ill look into it, but so far poll looks almost exactly the same

    Either way I still wish I could just get this properly work...
    any suggestions on why this is not working?

  4. #4
    Registered User
    Join Date
    Feb 2019
    Posts
    499
    A simple server, using poll() for study:

    Code:
    // server.c
    //   Compile with:
    //   $ cc -O2 -pthread -o server server.c
    //
    #include <unistd.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <pthread.h>
    #include <poll.h>
    #include <string.h>
    #include <arpa/inet.h>
    
    // Defines max connections backlog.
    // Don't use more then SOMAXCONN (128 on linux), unless you did some tweaking on procfs.
    #define MAXCONN 16
    
    // the argument void* won't be a pointer, but the value of the socket's file descriptor.
    // Thread function will deal with the socket and close it, when finished...
    //
    // OBS: To get the peer address/port use getpeername().
    static void *thread_func ( void * );
    
    int main ( void )
    {
      int listen_fd, conn_fd, n;
    
      // Used to bind listening socket to 0.0.0.0:8080.
      struct sockaddr_in sin = { .sin_family = AF_INET, .sin_port = htons ( 8080 ) };
    
      pthread_t tid;
      pthread_attr_t attr;
    
      /* This is necessary only for non-ephemeral ports (1~1023)... */
      //if ( getuid() != 0 )
      //{
      //  fputs ( "ERROR: Must be root!\n", stderr );
      //  return EXIT_FAILURE;
      //}
    
      // Create listening socket...
      if ( ( listen_fd = socket ( AF_INET, SOCK_STREAM, IPPROTO_TCP ) ) == -1 )
      {
        perror ( "socket()" );
        return EXIT_FAILURE;
      }
    
      puts ( "TCP socket created" );
    
      // Allow reusage of address.
      n = 1;
      setsockopt ( listen_fd, SOL_SOCKET, SO_REUSEADDR, &n, sizeof n );
    
      // Binds this socket to 'local' interface.
      if ( bind ( listen_fd, ( struct sockaddr * ) &sin, sizeof sin ) == -1 )
      {
        perror ( "bind()" );
        close ( listen_fd );
        return EXIT_FAILURE;
      }
    
      puts ( "Socket bounded to 0.0.0.0:8080" );
    
      // Start listening socket... (this is not a blocking call).
      if ( listen ( listen_fd, MAXCONN ) == -1 )
      {
        perror ( "listen()" );
        close ( listen_fd );
        return EXIT_FAILURE;
      }
      else
      {
        puts ( "Listening..." );
    
        while ( 1 )
        {
          struct pollfd pfd = { .fd = listen_fd, .events = POLLIN };
    
          // This is a blocking call if listen_fd isn't ready to be read.
          // I'm ignoring errors here...
          if ( poll ( &pfd, 1, 0 ) == 1 )
          {
            // Finally accepts the connection and create the thread...
            if ( ( conn_fd = accept ( listen_fd, NULL, NULL ) ) != -1 )
            {
              printf ( "Socked [%d] connected.\n", conn_fd );
    
              pthread_attr_init ( &attr );
              pthread_attr_setdetachstate ( &attr, PTHREAD_CREATE_DETACHED );
    
              // Note: Passing the socket to the thread in a non portable way!
              //       This is safe if sizeof(int) <= sizeof(void *)...
              pthread_create ( &tid, &attr, thread_func, ( void * ) conn_fd );
            }
          }
        }
      }
    
      // will never get here!
      close ( listen_fd );
      return EXIT_SUCCESS;
    }
    
    // Simple thread.
    // I'm not checking for errors here for simplicity...
    void *thread_func ( void *argp )
    {
      int sock_fd;
      struct sockaddr_in sin;
      socklen_t len;
      char str[INET_ADDRSTRLEN];
      static const char * const msg = "Test...\n";
    
      sock_fd = ( int ) argp;
    
      send ( sock_fd, msg, strlen ( msg ), 0 );
    
      len = sizeof sin;
      getpeername ( sock_fd, ( struct sockaddr * ) &sin, &len );
      inet_ntop ( AF_INET, &sin.sin_addr, str, sizeof str );
      printf ( "Message sent to %s:%u\n", str, ntohs ( sin.sin_port ) );
    
      close ( sock_fd );
      printf ( "Socket [%d] closed.\n", sock_fd );
    
      return NULL;
    }
    Test using telnet:

    Code:
    $ telnet <addr> 8080
    []s
    Fred

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. select server help
    By Annonymous in forum C Programming
    Replies: 11
    Last Post: 10-31-2012, 12:43 PM
  2. Chat server not using select
    By Per Andersson in forum C Programming
    Replies: 1
    Last Post: 07-06-2012, 08:12 AM
  3. TCP Server with select() function
    By netpumber in forum Windows Programming
    Replies: 6
    Last Post: 10-24-2011, 10:19 AM
  4. Select(); server help!
    By klipseracer in forum Networking/Device Communication
    Replies: 3
    Last Post: 03-02-2008, 11:16 PM
  5. select() server
    By chrismiceli in forum Linux Programming
    Replies: 0
    Last Post: 09-09-2003, 08:56 PM

Tags for this Thread