Re: Learnign select()



On Jun 16, 6:47 pm, Barry Margolin <bar...@xxxxxxxxxxxx> wrote:
In article <g353th$js...@xxxxxxxx>, arnuld <sunr...@xxxxxxxxxxxxxxxx>
wrote:

STATEMENT: I have created a TCP echo server-client pair where client
sends some text to server and then server sends back the same text to
client and then client prints it onto the screen.

PROBLEM #1:  I can't understand the select() :(

PROBLEM #2: I have edited my server program to use select() and it has no
compilation or run-time errors but when it runs then server hangs there
infinitely consuming all of the CPU.

If a program hangs in select() it shouldn't use any CPU time.  So I
suspect it's looping after select() returns, not hanging in select()
itself.

There are some problems in your code that I've annoted below.



Down here you will find the code for both server and client. I am using
Unp vol-1 by Stevens but still can't understand how the select is
implemented in code . any pointers ?  . So far I understand only this:

You seem to be using it correctly.  You even did something right that
most beginners get wrong -- your use of rdset and rdset2.  Most
first-time select() users don't realize they have to re-initialize the
fdset every time through the main loop.







-- * --
select() works as a 3rd party which sits between different clients and
single server. It checks to see of the client connection (FD) is ready
for reading and when it is then it gives that connection to the server.
Hence it does not do any communication  by itself, It just acts as medium
between server and clients and its main purpose is to keep server
unblocked all the time.
-- * --

-------------- server code ---------------
/* A server handeling multiple client using select which in fact
   a single-tasking mechanism and I always thought select is a
   replacement for a multi-tasking mechanism :-O
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/select.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define SERVER_IP  "127.0.0.1"

enum { ARRSIZE=101, BACKLOG=10 } ;

int main( int argc, char** argv )
{
  int i, j;
  int server_fd, accept_fd;
  int servport;
  struct sockaddr_in servaddr, cliaddr;
  socklen_t cliaddr_len;
  char arrc[ARRSIZE];

  /* preparation for select() */
  int maxrank_fd; /* used with select() */
  int max_idx;   /* maximum index into the array */
  int arrfd[FD_SETSIZE];
  fd_set rdset, rdset2;
  int nready, sockfd;

  if( argc != 2 )
    {
      fprintf(stderr, "USAGE: ./file PORT\n");
      exit( EXIT_FAILURE );
    }
  else
    {
      servport = atoi( argv[1] );    
    }

  servaddr.sin_family = AF_INET;
  servaddr.sin_port   = htons( servport );
  inet_aton( SERVER_IP, &(servaddr.sin_addr) );
  memset( &servaddr.sin_zero, '\0', sizeof( servaddr.sin_zero ) );

  if( -1 == (server_fd = socket(AF_INET, SOCK_STREAM, 0)) )
    {
      perror("SOCKET() error");
      exit( EXIT_FAILURE );
    }

  if( -1 == bind(server_fd, (struct sockaddr*) &servaddr, sizeof
(servaddr)) )
    {
      perror("BIND() error");
      exit( EXIT_FAILURE );
    }

  if( -1 == (listen(server_fd, BACKLOG)) )
    {
      perror("LISTEN() error");
      exit( EXIT_FAILURE );
    }

  /* select comes into play after listen() and before accept() */
  maxrank_fd = server_fd;
  max_idx = -1;

  /* initialize the array of client FDs */
  for( i=0; i < FD_SETSIZE; ++i )
    {
      arrfd[i] = -1;
    }

  /* initilaize the FD set
     it will connect select() with the server)_fd we created */
  FD_ZERO(&rdset);
  FD_SET( server_fd, &rdset );

  /* apply & use select() */
  for( ; ; )
    {
      /* copy the set. older ones will be used later */
      rdset2 = rdset;
      nready = select( maxrank_fd + 1, &rdset2, NULL, NULL, NULL );

      if( FD_ISSET(server_fd, &rdset2) )
        {
          cliaddr_len = sizeof( struct sockaddr_in);
          if( -1 == (accept_fd = (accept(server_fd, (struct sockaddr*)
&cliaddr, &cliaddr_len))) )
            {
              perror( "ACCEPT() error");
              exit( EXIT_FAILURE );
            }

          for( j=0; j < FD_SETSIZE; ++j )
            {
              if( arrfd[j] < 0 )
                {
                  arrfd[j] = accept_fd;
                  break;
                }
            }

          /* check if arrfd is full */
          if( j == FD_SETSIZE )
            {
              perror("Server Overloaded with too many connections.
\nPlease connect later");
              exit( EXIT_FAILURE );
            }

          /* add the accept() descriptor to the old set */
          FD_SET( accept_fd, &rdset );

          if( accept_fd > server_fd )
            {
              maxrank_fd = accept_fd;
            }

          if( j > max_idx )
            {
              max_idx = j;
            }

          if( --nready <= 0 )
            {
              continue;
            }
        }

      /* we can use the useless i from one earlier loop */
      for( i=0; i < max_idx; ++i )
        {
          if( (sockfd = arrfd[i]) < 0 )
            {
              continue;
            }

          if( FD_ISSET(sockfd, &rdset2) )
            {
              if( -1 == (recv(accept_fd, arrc, ARRSIZE, 0)) )

You have to read from sockfd, not accept_fd.

                {
                  perror( "READ() error");
                  exit( EXIT_FAILURE );
                }

              if( -1 == (send(accept_fd, arrc, ARRSIZE, 0)) )

You have to write to sockfd, not accept_fd.

You shouldn't send ARRSIZE bytes, you should send the number of bytes
that recv() returned.  Unfortunately, you didn't save that anywhere.

                {
                  perror( "READ() error");

This should be "SEND() error".

                  exit( EXIT_FAILURE );
                }
            }

          if( --nready <= 0 )

This should be inside the if(FD_ISSET(sockfd, &rdset2)) block.

            {
              break;
            }

        }
    }

  return 0;
}

------------- client code -------------

I haven't looked at the client code, but I wouldn't be surprised if it
has problems like the ones I noticed in the server.





/* A client to send a string to a server handeling multiple-clients using
   slect
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define SERVER_IP  "127.0.0.1"

enum { ARRSIZE=101 } ;

int main( int argc, char** argv )
{
  int conn_fd, conn_port;
  struct sockaddr_in cliaddr;
  char arrc[ARRSIZE] = "Spanish Eyes\n";

  if( 2 == argc )
    {
      conn_port = atoi(argv[1]);
    }
  else
    {
      fprintf(stderr, "USAGE:  ./file PORT\n");
      exit( EXIT_FAILURE );
    }

  cliaddr.sin_family = AF_INET;
  cliaddr.sin_port   = htons(conn_port);
  inet_pton( AF_INET, SERVER_IP, &cliaddr.sin_addr );
  memset( &cliaddr.sin_zero, '\0', sizeof(cliaddr.sin_zero) );

  if( -1 == (conn_fd = socket(PF_INET, SOCK_STREAM, 0)) )
    {
      perror("SOCKET() error");
      exit( EXIT_FAILURE );
    }

  if( -1 == (connect(conn_fd, (struct sockaddr*) &cliaddr, ARRSIZE)) )
    {
      perror("CONNECT() error");
      exit( EXIT_FAILURE );
    }

  if( -1 == (send(conn_fd, arrc, ARRSIZE, 0)) )
    {
      perror("SEND() error");
      exit( EXIT_FAILURE );
    }

  if( -1 == (recv( conn_fd, arrc, ARRSIZE, 0)) )
    {
      perror("RECV() error");
      exit( EXIT_FAILURE );
    }

  printf("---------------\n%s\n", arrc);

  return 0;
}
[arnuld@dune ~]$

--
Barry Margolin, bar...@xxxxxxxxxxxx
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
*** PLEASE don't copy me on replies, I'll read them in the group ***- Hide quoted text -

- Show quoted text -- Hide quoted text -

- Show quoted text -

Is there some kind of trick to finding the errors right away in a
piece of code? Or does this just from experience?

Chad



.



Relevant Pages

  • Re: What doesnt lend itself to OO?
    ... >> proxy and instructs the server to constuct the real object. ... rather than client code. ... If 'clock' is instantiated in the server, ... > for the server interface at the OOA level. ...
    (comp.object)
  • This is going straight to the pool room
    ... or not the client has privilege to do what they're trying to do, ... The server environment is this: ... 3GL User action Routines that Tier3 will execute on your behalf during the ... Routine Name: USER_INIT ...
    (comp.os.vms)
  • [Full-Disclosure] R: Full-Disclosure Digest, Vol 3, Issue 42
    ... Full-Disclosure Digest, Vol 3, Issue 42 ... SD Server 4.0.70 Directory Traversal Bug ... Arkeia Network Backup Client Remote Access ...
    (Full-Disclosure)
  • Re: What doesnt lend itself to OO?
    ... > rather than client code. ... no way to do that without also touching the object with clock semantics ... will not encapsulate both clock semantics and network semantics. ... The server can do whatever it wants ...
    (comp.object)
  • Re: [Full-disclosure] [GOATSE SECURITY] Clench: Goatses way to say "screw you" to certificate au
    ... the risk of javascript being rewritten is highlighted ...     * Users cannot effectively comprehend anything but password ... getting hundreds of thousands or millions of users to install a client ... Client connects to server and sends hello. ...
    (Full-Disclosure)