Why my TCP client stop recv() when there's no send() executed

90 Views Asked by At

I have a client that looks like this:

struct sockaddr_in dest_addr;
dest_addr.sin_addr.s_addr = inet_addr(host_ip);
dest_addr.sin_family = AF_INET;
dest_addr.sin_port = htons(PORT);
addr_family = AF_INET;
ip_protocol = IPPROTO_IP;

int sock = socket(addr_family, SOCK_STREAM, ip_protocol);
/*
   connect() handle block
   connect successfully
*/

int state = AWAKE;
while(1){
    if(state == AWAKE){
        int err_socket = sendto(sock, message, strlen(message), 0, (struct sockaddr *)&dest_addr, sizeof(dest_addr));
    }

    int len = recv(sock, rx_buffer, sizeof(rx_buffer) - 1, 0);
    if(len<0){
        ESP_LOGE(TCP_TAG, "Error occurred during recving: errno %d", errno); --> error 11
        continue;
    }
    
    if(strcmp(rx_buffer, "ON") == 0){
        state == AWAKE;
    }else if(strcmp(rx_buffer, "OFF") == 0){
        state == SLEEPING;
    }
}

After receiving the "OFF" message, the state will switch to SLEEPING and stop sending messages to the server, but keep receiving messages.

However, when I switch the state to SLEEPING, the recv result will always return -1 while the server keeps sending messages to the client.

My questions is, do it always need send() and recv() as a peer?

1

There are 1 best solutions below

0
Remy Lebeau On

After receiving "OFF" message, the state will switch to SLEEPING

No, actually it doesn't, because you are mistakenly using the == comparison operation where you should be using the = assignment operator. So, your state doesn't actually change value.

Even if that were not the case, your rx_buffer is not null-terminated, so your strcmp() calls won't work correctly.

However, when I switch the state to SLEEPING, the recv result will always return -1 while the server keeps sending messages to the client.

That means recv() is failing. You need to then look at errno to find out why. Which, according to your comments, is 11 (EAGAIN), which simply means that the socket is operating in non-blocking mode and there is nothing available to read from the socket at that exact moment, so just try again later. This is not a fatal error.

However, an error condition that you are not handling at all is when recv() returns 0 on peer disconnect. You need to stop your loop in that situation and close your socket.

do it always need send() and recv() as a peer?

No. TCP is birectional. You can treat the socket as send-only or recv-only, if that is what your protocol requires. Though, do make sure you read from the socket periodically in order to catch peer disconnects and network failures.