Search code examples
c++socketstcprecv

First recv() cannot read message sent from server


I'm writing a simple TCP server and client where the server echoes back the message to the client. But I have a problem with the first read()/recv() call from the client side. Whenever a client connects to the server, it sends a welcome message, but I cannot display the welcome message on the client side. What i get in return from recv()/read() is 0, which indicates that the socket is closed or 0 bytes read. I know it isn't closed since the server echoes back messages but with a delay(example bellow). The read()/recv() works fine after I've written to the server from the client side. So my question is: Why does the first read()/recv() call receive return a 0?

TLDR; My client does not read()/recv() the welcome message sent from server. What am I doing wrong?

Server and client interaction(Notice empty 'Welcome message'): Server and client interaction

As you can see, the socket isn't closed so the only reason read()/recv() returns 0 is because 0 bytes read.

Client code:

(SETUP NOT INCLUDED)
printf("Connected. \n");

memset(buffer, 0, 1025);

/********* PROBLEM IS THIS READ()/RECV() **********/
n = recv(sockfd, buffer, strlen(buffer), NULL);
if(n == 0){ //
     //error("Error reading\n");
     printf("Error reading socket.");
}

printf("Welcome message: \n%s", buffer);

while(1){
    printf("\nPlease enter message: \n");

    memset(buffer, 0, 256);
    fgets(buffer, 255, stdin);
    printf("You sent: %s", buffer);

    n = write(sockfd, buffer, strlen(buffer));
    if(n <= 0)
    {
        error("Error writing socket. \n");
    }
    //om bye, break
    memset(buffer, 0, 256);
    //Läser här endast efter write
    n = read(sockfd, buffer, 255);
    if(n < 0)
    {
        error("Error reading from socket. \n");
    }

    printf("You received: %s", buffer);
}
//end while
close(sockfd);
return 0;

Relevant Server code:

 while(TRUE)
{
    /* Clear socket set */
    FD_ZERO(&readfds);
    /* Add master socket to set */
    FD_SET(masterSocket, &readfds);
    /* For now maxSd is highest */
    maxSd = masterSocket;

    /* Add child sockets to set, will be 0 first iteration */
    for(int i = 0; i < maxClients ; i++)
    {
        sd = clientSockets[i]; // sd = socket descriptor
        /* If valid socket descriptor */
        if(sd > 0)
        {
            FD_SET(sd, &readfds);
        }
        /* Get highest fd number, needed for the select function (later) */
        if(sd > maxSd)
        {   
            maxSd = sd;
        }
    }//end for-loop

    /* Wait for activity on any socket */
    activity = select(maxSd +1, &readfds, NULL, NULL, NULL);

    if((activity < 0) && (errno != EINTR))
    {
        printf("****** Error on select. ******\n"); //no need for exit.
    }

    /* If the bit for the file descriptor fd is set in the 
    file descriptor set pointed to by fdset */
    /* If something happend in the master socket, its a new connection */
    if(FD_ISSET(masterSocket, &readfds))
    {
        //står här och läser
        if((newSocket = accept(masterSocket, (struct sockaddr*)&address, (socklen_t*)&addrlen)) < 0)
        {
            perror("****** Could not accept new socket. ******\n");
            exit(EXIT_FAILURE);
        }

        /* Print info about connector */
        printf("New connection, socket fd is %d, ip is: %s, port: %d\n", newSocket, inet_ntoa(address.sin_addr), ntohs(address.sin_port));

        /**************** THIS IS THE WRITE THAT DOESN'T GET DISPLAYED ON CLIENT ******************/
        if( send(newSocket, message, strlen(message), 0) != strlen(message))
        {
             perror("****** Could not sent welcome message to new socket. ******\n");
        }

        puts("Welcome message sen successfully");

        /* Add new socket to array of clients */
        for(int i = 0; i < maxClients; i++)
        {
            if(clientSockets[i] == 0)
            {
                clientSockets[i] = newSocket;
                printf("Adding socket to list of client at index %d\n", i);
                break;
            }
        }
    }//end masterSocket if
    /* Else something happend at client side */
    for(int i = 0; i < maxClients; i++)
    {
        sd = clientSockets[i];

        if(FD_ISSET(sd, &readfds))
        {   
            /* Read socket, if it was closing, else read value */
            //denna read kan vara fel
            if((valread = read( sd, buffer, 1024)) == 0)
            {
                getpeername( sd, (struct sockaddr*)&address, (socklen_t*)&addrlen);
                printf("Host disconnected, ip %s, port %d.\n", inet_ntoa(address.sin_addr), ntohs(address.sin_port));

                close(sd);
                clientSockets[i] = 0;
            }
            else
            {
                buffer[valread] = '\0';
                send(sd, buffer, strlen(buffer), 0);
            }
        }
    }

I know this is a big wall of text but i am very thankful for anyone who takes their time with this problem.


Solution

  • The third arg to recv specifies a number bytes to read from the socket. And now look at your code:

    memset(buffer, 0, 1025);
    recv(sockfd, buffer, strlen(buffer), NULL);
    

    First, you zero out whole buffer and then call strlen on it. No wonder it returns 0, as strlen counts non-zero bytes.

    Instead, put the buffer length into a variable and use it everywhere:

    const int bufSize = 1025;
    memset(buffer, 0, bufSize);
    recv(sockfd, buffer, bufSize, NULL);