Q: select() returns upon socket connection, or STDIN, but not both

Q: select() returns upon socket connection, or STDIN, but not both

Post by David Duda » Tue, 22 Sep 1998 04:00:00



I am trying to use a select() statement to listen to both STDIN and a
socket.  If I run the server and then begin running clients, it works
correctly.  If I run the server and begin typing STDIN, it works correctly.

If I intermix client connections with typing, it thereafter only sees
whichever came first.  For example, with the server running, then a client
running, and then typing, it never sees STDIN.  Or, with the server running,
then some typing, and then attempted client connections, it never sees the
clients.  What am I doing wrong?  Thanks in advance.

I am on AIX.  Here is the code:

main()
{
    int s, t, problem = 0, child = 0;
    struct timeval tv;
    fd_set readfds;
    char buf[80];

    tv.tv_sec = 4;
    tv.tv_usec = 0;
    FD_ZERO(&readfds);
    system("clear");

    if ((s = open_socket()) >= 0)
    {
        signal(SIGCHLD, sighandler);
        FD_SET(STDIN_FILENO, &readfds);
        FD_SET(s, &readfds);

        while (!problem && !child)
        {
            printf("\nwaiting...\n");
            select(s+1, &readfds, NULL, NULL, NULL);
            if (FD_ISSET(STDIN_FILENO, &readfds))
           {
                scanf("%s", buf);
                printf("you entered this: '%s'\n", buf);
            }
            if (FD_ISSET(s, &readfds))
            {
                printf("\theard from socket\n");
                if ((t = accept_client(s)) >= 0)
                {
                    switch(fork())
                    {
                        case -1 :               /* uh-oh */
                            perror("fork");
                            close(s);
                            close(t);
                            problem = 1;
                        case 0 :                /* child */
                            close(s);
                            interact(t);
                            child = 1;
                        default :               /* parent, keep watching */
                            close(t);
                            problem = 1;
                    }
                }
                else if (errno != EINTR)     /* EINTR might happen on
accept() *
/
                {
                    perror("accept_client");
                    problem = 1;
                }
            }
        }
    }
    else
    {
        perror("open_socket");
        problem = 1;
 }
    exit(problem);

Quote:}

int open_socket()
{
    int retval = 0, socket_main;
    struct sockaddr_in addr_local;

    /* create socket */
    if ((socket_main = socket(AF_INET, SOCK_STREAM, 0)) >= 0)
    {
        /* populate local address structure */
        addr_local.sin_family = AF_INET;
        addr_local.sin_port = htons(PORTNUM);
        addr_local.sin_addr.s_addr = INADDR_ANY;
        bzero(&(addr_local.sin_zero), 8);

        /* bind socket to port */
        if ((retval = bind(socket_main, (struct sockaddr *)&addr_local,
                            sizeof(struct sockaddr))) >= 0)
        {
            /* listen to port */
            if ((retval = listen(socket_main, QUEUE_SIZE)) < 0)
                perror("listen");
        }
        else perror("bind");
    }
    else perror("socket");

    if (retval < 0) socket_main = retval;   /* an error occurred */

    return(socket_main);

Quote:}

int accept_client(int s)
{
    int socket1, addr_remote_size;
    struct sockaddr_in addr_remote;
    struct hostent *info_client;

    addr_remote_size = sizeof(struct sockaddr);
    /* accept socket connection */
    if ((socket1 = accept(s, (struct sockaddr *)&addr_remote,
                            &addr_remote_size)) >= 0)
    {
        info_client = gethostbyaddr((char *)&addr_remote.sin_addr,
                                sizeof(addr_remote.sin_addr), AF_INET);
        printf("server: got connection from %s (%s)\n",
                    info_client->h_name, inet_ntoa(addr_remote.sin_addr));
    }
    else perror("accept");

    return(socket1);

Quote:}

void interact(int t)
{
    char str[80];

    strcpy(str, "Hello world!\n");
    printf("Sending: '%s'\n", str);
    if (send(t, str, strlen(str), 0) < 0) perror("send");
    close(t);

Quote:}

void sighandler(void)
{
    while (waitpid(-1, NULL, WNOHANG) > 0);
Quote:}

 
 
 

Q: select() returns upon socket connection, or STDIN, but not both

Post by Bob Withe » Tue, 22 Sep 1998 04:00:00


[This followup was posted to comp.unix.programmer


Quote:> I am trying to use a select() statement to listen to both STDIN and a
> socket.  If I run the server and then begin running clients, it works
> correctly.  If I run the server and begin typing STDIN, it works correctly.

> If I intermix client connections with typing, it thereafter only sees
> whichever came first.  For example, with the server running, then a client
> running, and then typing, it never sees STDIN.  Or, with the server running,
> then some typing, and then attempted client connections, it never sees the
> clients.  What am I doing wrong?  Thanks in advance.

> I am on AIX.  Here is the code:

> main()
> {
>     int s, t, problem = 0, child = 0;
>     struct timeval tv;
>     fd_set readfds;
>     char buf[80];

>     tv.tv_sec = 4;
>     tv.tv_usec = 0;
>     FD_ZERO(&readfds);
>     system("clear");

>     if ((s = open_socket()) >= 0)
>     {
>         signal(SIGCHLD, sighandler);
>         FD_SET(STDIN_FILENO, &readfds);
>         FD_SET(s, &readfds);

>         while (!problem && !child)
>         {
>             printf("\nwaiting...\n");
>             select(s+1, &readfds, NULL, NULL, NULL);
>             if (FD_ISSET(STDIN_FILENO, &readfds))
>            {
>                 scanf("%s", buf);
>                 printf("you entered this: '%s'\n", buf);

You need to reset readfds before each invocation of select.  Move the two
FD_SET's inside the loop between printf and select.

Regards,
Bob

 
 
 

Q: select() returns upon socket connection, or STDIN, but not both

Post by John Simpso » Tue, 22 Sep 1998 04:00:00


 >
 > I am trying to use a select() statement to listen to both STDIN and a
 > socket.  If I run the server and then begin running clients, it works
 > correctly.  If I run the server and begin typing STDIN, it works
correctly.
 >
 > If I intermix client connections with typing, it thereafter only sees
 > whichever came first.  For example, with the server running, then a
client
 > running, and then typing, it never sees STDIN.  Or, with the server
running,
 > then some typing, and then attempted client connections, it never
sees the
 > clients.  What am I doing wrong?  Thanks in advance.
 >
 > I am on AIX.  Here is the code:
 >

I believe  your problem is in not resetting your fd_set within your
while loop.  I think the 'select' call modifies the values of the set
bits to indicate which will not block on a read.  This means that after
the first return for the select when you begin typing, the bit for the
socket will be turned off, and the select will not be looking for the
socket again.  Try moving the FD_SET() startements into the while loop,
so the fd_set gets initialized before each select().

 > main()
 > {
 >     int s, t, problem = 0, child = 0;
 >     struct timeval tv;
 >     fd_set readfds;
 >     char buf[80];
 >
 >     tv.tv_sec = 4;
 >     tv.tv_usec = 0;
 >     FD_ZERO(&readfds);
 >     system("clear");
 >
 >     if ((s = open_socket()) >= 0)
 >     {
 >         signal(SIGCHLD, sighandler);
 >         FD_SET(STDIN_FILENO, &readfds);
 >         FD_SET(s, &readfds);
 >
 >         while (!problem && !child)
 >         {
 >             printf("\nwaiting...\n");
 >             select(s+1, &readfds, NULL, NULL, NULL);
 >             if (FD_ISSET(STDIN_FILENO, &readfds))
 >             {
 >                 scanf("%s", buf);
 >                 printf("you entered this: '%s'\n", buf);
 >             }
 >             if (FD_ISSET(s, &readfds))
 >             {
 >                 printf("\theard from socket\n");
 >                 if ((t = accept_client(s)) >= 0)
 >                 {
 >                     switch(fork())
 >                     {
 >                         case -1 :               /* uh-oh */
 >                             perror("fork");
 >                             close(s);
 >                             close(t);

Quote:>                             problem = 1;
>                         case 0 :                /* child */
>                             close(s);
>                             interact(t);
>                             child = 1;
>                         default :               /* parent, keep watching */
>                             close(t);
>                             problem = 1;
>                     }
>                 }
>                 else if (errno != EINTR)     /* EINTR might happen on
> accept() *
> /
>                 {
>                     perror("accept_client");
>                     problem = 1;
>                 }
>             }
>         }
>     }
>     else
>     {
>         perror("open_socket");
>         problem = 1;
>  }
>     exit(problem);
> }

>_

John H. Simpson

Phone: 503-499-2667  FAX: 503-499-3629

CNF Service Co. (CNF Transportation, Inc.)
1717 NW 21st St.
Portland, OREGON 97209 USA

for e-mail, remove _not_oj_ from address

 
 
 

Q: select() returns upon socket connection, or STDIN, but not both

Post by Nic » Wed, 23 Sep 1998 04:00:00



> I am trying to use a select() statement to listen to both STDIN and a
> socket.  If I run the server and then begin running clients, it works
> correctly.  If I run the server and begin typing STDIN, it works correctly.

> If I intermix client connections with typing, it thereafter only sees
> whichever came first.  For example, with the server running, then a client
> running, and then typing, it never sees STDIN.  Or, with the server running,
> then some typing, and then attempted client connections, it never sees the
> clients.  What am I doing wrong?  Thanks in advance.

> I am on AIX.  Here is the code:

> main()
> {
>     int s, t, problem = 0, child = 0;
>     struct timeval tv;
>     fd_set readfds;
>     char buf[80];

>     tv.tv_sec = 4;
>     tv.tv_usec = 0;
>     FD_ZERO(&readfds);
>     system("clear");

[snip]

Another thing you may need to watch out for here is what you end up
doing with the timeval struct 'tv'. If you end up using it as the
timeout in the select() call, you'll get problems again as select will
modify it.

If you plan to use it with the select(), set it from inside the while
loop:

while (...) {
        tv.tv_sec = 4;
        tv.tv_usec = 0;
        ...
        ret = select(..., &tv);
        ...

Hope this helps you with your journey into the magic and monsters of
select() :-)

Regards,
        Nic (who needs a better newsreader ;-) B.

-- Nic B. -- email "sky" at "wibble dot net" ------
-- UNIX Programmer, The Internet Group (NZ) Ltd. --
-- #include <stddisclaimer.h> ---------------------