csocketsnetwork-programmingtcpposix-select

select() working for STDIN but not sockets


I have the following C code for a TCP client:

#define PORT 8888


void connexion(int sock)
{
    fd_set rfds;
    struct timeval tv;
    int retval;

    FD_ZERO(&rfds);
    FD_SET(0, &rfds);
    FD_SET(sock, &rfds);
    char buf[512];

    retval = select(3, &rfds, NULL, NULL, NULL);

    if (retval == -1)
        perror("select()");
    else if (retval) {
        read(retval, buf, 512);
        printf("\nbuf: %s", buf);
        memset(buf, 0, 512);
    }
    connexion(sock);
}

int main(int argc, char const *argv[])
{
    int sock = 0, valread;
    struct sockaddr_in serv_addr;
    char *hello = "Hello from client";
    char buffer[1024] = {0};
    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        printf("\n Socket creation error \n");
        return -1;
    }

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(PORT);

    if(inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr)<=0)
    {
        printf("\nInvalid address/ Address not supported \n");
        return -1;
    }

    if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
    {
        printf("\nConnection Failed \n");
        return -1;
    }
    connexion(sock);
}

I try to read the standard input without stopping reading sockets. Indeed, I need to be able to receive messages while I write one. To do this, I use the select function. But I only receive messages from my terminal, never from the server.

The server has nevertheless received the sockets from the client... What is wrong with this code?


Solution

  • you do not use select in the right way, replace

        retval = select(3, &rfds, NULL, NULL, NULL);
    

    by

        retval = select(sock+1, &rfds, NULL, NULL, NULL);
    

    select() working for STDIN ...

    that works for stdin because stdin is 1 so is less than 3

    Out of that in

    read(retval, buf, 512);
    

    does not do what you expect, do

    if (FD_ISSET(sock, &rfds)) {
      read(sock, buf, 512);
      printf("buf from socket: %s\n", buf);
    }
    if (FD_ISSET(stdin, &rfds)) {
      read(stdin, buf, 512);
      printf("buf from stdin: %s\n", buf);
    }
    

    warning if you read on the socket and the null character is not sent/read because printf will have an undefined behavior, may be save the read length to add the null character at the end

    if the socket is closed or you reach the EOF on stdin both read may read nothing, so it is better to check their result

    Do not use an else between the two if because you can have input from both

    Your terminal recursion can be replaced by a loop

    In your printf it is strange to produce the newline before and not after, doing after flushes the output

    In main

    char *hello = "Hello from client";
    char buffer[1024] = {0};
    

    are unused