Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Linux socket: How to make send() wait for recv()

Tags:

c

sockets

recv

send

I am making a simple client-server application using TCP protocal.

I Know that by default. recv() will block until the other side call a send() to this socket. But is it possible that send() block itself until the other side has recv()ed the msg instead of keeping send()ing to outgoing queue and later to find the other side recv() got a whole bunch of msg sent by multiple send()s

In other words. Is it possible to let every send() wait for the other side's recv() before it can call another send()?

To ilustate my question. I'll post a simple code here:

client.c

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

int main(int argc, char *argv[])
{
    int sockfd = 0;
    char sendBuff[1024];
    struct sockaddr_in serv_addr;
    int i;

    if(argc != 2)
    {
        printf("\n Usage: %s <ip of server> \n",argv[0]);
        return 1;
    } 

    if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        printf("\n Error : Could not create socket \n");
        return 1;
    } 

    memset(&serv_addr, '0', sizeof(serv_addr)); 

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

    if(inet_pton(AF_INET, argv[1], &serv_addr.sin_addr)<=0)
    {
        printf("\n inet_pton error occured\n");
        return 1;
    } 

    if( connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
    {
        printf("\n Error : Connect Failed \n");
        return 1;
    }

    do{
        memset(sendBuff, '\0', sizeof(sendBuff));
        sprintf(sendBuff, "This is line %d", i);
        send(sockfd, sendBuff, strlen(sendBuff), 0);
        //sleep(1);
    }while(++i<100);

    return 0;
}

server.c

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

int main(int argc, char *argv[])
{
    int listenfd = 0, connfd = 0;
    struct sockaddr_in serv_addr; 

    char sendBuff[1025];
    char recvBuff[100];

    int i = 0;

    listenfd = socket(AF_INET, SOCK_STREAM, 0);
    memset(&serv_addr, '0', sizeof(serv_addr));
    memset(sendBuff, '0', sizeof(sendBuff)); 

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    serv_addr.sin_port = htons(5000); 

    bind(listenfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)); 

    listen(listenfd, 10); 

    connfd = accept(listenfd, (struct sockaddr*)NULL, NULL); 

    do{  
        memset(recvBuff, '\0', sizeof(recvBuff));
        recv(connfd, recvBuff, sizeof(recvBuff),0);
        printf( "%s\n", recvBuff);
    }while(++i<100); 

    return 0;
} 

What I expect on the server side outcome is to print:

This is line 0
This is line 1
This is line 2
This is line 3
...

However, the actual outcome is like this:

This is line 0
This is line 1This is line 2This is line3This is line 4
This is line 5This is line 6This is line 7This is line 8This is line 9This is line 10
This is line 11This is line 12...

However this is easy to explain: when the client side issued a send(), it didn't wait for the server side's recv() to finish, and for some reason, the server side recv() loop is slower than client side's send(). Thus several send()s on client side may get piled together and received by server as a whole. (is my explanation right?)

Actually there seems to be a very silly and loose solution. just add a sleep(1)(as I commented out) after each send() in the loop. I know this will make the code very inefficient and if the recv() loop will take longer time to implement some other complicated actions( This is obviously unpredictable when the program gets large) which will take longer than 1 sec. This solution fails!

So is there a better solid way to let the two sides communicate with each other to ensure the msg sent by one single send() received by a single recv()?

like image 262
user2151995 Avatar asked Nov 05 '13 17:11

user2151995


People also ask

Does recv wait for send?

By default, recv() will always wait for at least one byte to be received. But, if there are more bytes, it will return them all, up to the length of the buffer that you've requested. In the send() example above, 25 bytes are always written to the network unless an error has occurred.

Does recv wait for data?

If data is not available for the socket socket, and socket is in blocking mode, the recv() call blocks the caller until data arrives. If data is not available and socket is in nonblocking mode, recv() returns a -1 and sets the error code to EWOULDBLOCK.

Does RECV have a timeout?

http.server.recv.timeout() : Amount of time (in seconds) that the proxy waits to receive data from the server before timing out. Default is 180.

Is recv () a blocking call?

recv(IPC, Buffer, int n) is a blocking call, that is, if data is available it writes it to the buffer and immediately returns true, and if no data is available it waits for at least n seconds to receive any data.


1 Answers

client.c

while(condition)
{
  send() from client;
  recv() from server;
}

server.c

recv() from client;
while(condition)
{
  send() from server; //acknowledge to client
  recv() from client;
}
like image 55
ravi Avatar answered Oct 16 '22 07:10

ravi