6

In Receiver, I have

recvfd=accept(sockfd,&other_side,&len);
while(1)
{
   recv(recvfd,buf,MAX_BYTES-1,0);
   buf[MAX_BYTES]='\0';
   printf("\n Number %d contents :%s\n",counter,buf);
   counter++;
}

In Sender , I have

send(sockfd,mesg,(size_t)length,0);
send(sockfd,mesg,(size_t)length,0);
send(sockfd,mesg,(size_t)length,0);

MAX_BYTES is 1024 and length of mesg is 15. Currently, It calls recv only one time. I want recv function to be called three times for each corresponding send. How do I achieve it?

sattu
  • 632
  • 1
  • 22
  • 37
  • 3
    It's impossible: `recv` doesn't know which is size of data portion! You can only make buffer size equal to `length`. – Eddy_Em Jun 07 '13 at 18:36
  • 3
    You're perhaps using TCP. TCP does not preserve any message boundaries. It just gives you a stream to work with. You can't make recv() behave like you want. – nos Jun 07 '13 at 18:40
  • 4
    The basic rule, is that you **must not** expect data to come out of TCP connection in the same size chunks that you put it into the other end. That is sometimes can is merely a matter of timing coincidence - relying on that is only going to introduce bugs which will break operation in the real world, despite sometimes seeming to work on your test system. – Chris Stratton Jun 07 '13 at 18:55

5 Answers5

6

In short: yes, it is blocking. But not in the way you think.

recv() blocks until any data is readable. But you don't know the size in advance.

In your scenario, you could do the following:

  1. call select() and put the socket where you want to read from into the READ FD set
  2. when select() returns with a positive number, your socket has data ready to be read
  3. then, check if you could receive length bytes from the socket:
    recv(recvfd, buf, MAX_BYTES-1, MSG_PEEK), see man recv(2) for the MSG_PEEK param or look at MSDN, they have it as well
  4. now you know how much data is available
  5. if there's less than length available, return and do nothing
  6. if there's at least length available, read length and return (if there's more than length available, we'll continue with step 2 since a new READ event will be signalled by select()
eckes
  • 64,417
  • 29
  • 168
  • 201
6

To send discrete messages over a byte stream protocol, you have to encode messages into some kind of framing language. The network can chop up the protocol into arbitrarily sized packets, and so the receives do not correlate with your messages in any way. The receiver has to implement a state machine which recognizes frames.

A simple framing protocol is to have some length field (say two octets: 16 bits, for a maximum frame length of 65535 bytes). The length field is followed by exactly that many bytes.

You must not even assume that the length field itself is received all at once. You might ask for two bytes, but recv could return just one. This won't happen for the very first message received from the socket, because network (or local IPC pipe, for that matter) segments are never just one byte long. But somewhere in the middle of the stream, it is possible that the fist byte of the 16 bit length field could land on the last position of one network frame.

An easy way to deal with this is to use a buffered I/O library instead of raw operating system file handles. In a POSIX environment, you can take an open socket handle, and use the fdopen function to associate it with a FILE * stream. Then you can use functions like getc and fread to simplify the input handling (somewhat).

If in-band framing is not acceptable, then you have to use a protocol which supports framing, namely datagram type sockets. The main disadvantage of this is that the principal datagram-based protocol used over IP is UDP, and UDP is unreliable. This brings in a lot of complexity in your application to deal with out of order and missing frames. The size of the frames is also restricted by the maximum IP datagram size which is about 64 kilobytes, including all the protocol headers.

Large UDP datagrams get fragmented, which, if there is unreliability in the network, adds up to greater unreliability: if any IP fragment is lost, the entire packet is lost. All of it must be retransmitted; there is no way to just get a repetition of the fragment that was lost. The TCP protocol performs "path MTU discovery" to adjust its segment size so that IP fragmentation is avoided, and TCP has selective retransmission to recover missing segments.

Kaz
  • 55,781
  • 9
  • 100
  • 149
2

I bet you've created a TCP socket using SOCK_STREAM, which would cause the three messages to be read into your buffer during the first recv call. If you want to read the messages one-by-one, create a UPD socket using SOCK_DGRAM, or develop some type of message format which allows you to parse your messages when they arrive in a stream (assuming your messages will not always be fixed length).

ryanbwork
  • 2,123
  • 12
  • 12
  • Even if I have a fix message format, I need to parse it only after the buf gets full. Correct? – sattu Jun 07 '13 at 18:43
  • If your messages are fixed-length, you read data from the socket into your buffer, only parse complete messages in the buffer (as there may be multiple messages in the buffer), and leave any partial messages in the buffer for later reads to finish. – Remy Lebeau Jun 07 '13 at 18:46
  • No, as Remy commented on the other answer, `recv` will return when any data is available. If you are using TCP sockets, I'd advise reading from the socket using a buffer whose size matches your fixed length message to achieve the behavior you desire. – ryanbwork Jun 07 '13 at 18:47
  • 1
    Correct, however beware when considering UDP as developer-packetized alternative that UDP makes no guarantee that packets will be delivered, does not inform you if delivery has failed, and even has the (at least theoretical) risk of delivering packets *in a different order* than that in which they were sent. – Chris Stratton Jun 07 '13 at 18:58
1

First send the length to be received in a fixed format regarding the size of length in bytes you use to transmit this length, then make recv() loop until length bytes had been received.


Note the fact (as also already mentioned by other answers), that the size and number of chunks received do not necessarly need to be the same as sent. Only the sum of all bytes received shall be the same as the sum of all bytes sent.

Read the man pages for recvand send. Especially read the sections on what those functions RETURN.

alk
  • 69,737
  • 10
  • 105
  • 255
-4

recv will block until the entire buffer is filled, or the socket is closed.

If you want to read length bytes and return, then you must only pass to recv a buffer of size length.

You can use select to determine if

  1. there are any bytes waiting to be read,
  2. how many bytes are waiting to be read, then
  3. read only those bytes

This can avoid recv from blocking.

Edit:

After re-reading the docs, the following may be true: your three "messages" may be being read all-at-once since length + length + length < MAX_BYTES - 1.

Another possibility, if recv is never returning, is that you may need to flush your socket from the sender-side. The data may be waiting in a buffer to actually be sent to the receiver.

Matt Houser
  • 33,983
  • 6
  • 70
  • 88
  • 2
    This is not entirely true. `recv()` will block until *any* data becomes available, and then it returns how many bytes were actually received *not exceeding the requested number of bytes*, so it is possible (even likely) that `recv()` returns fewer bytes than requested. It does not wait for the entire requested number to arrive before exiting. That is why it is very important to pay attention to the actual return value and call `recv()` again if more bytes are expected. – Remy Lebeau Jun 07 '13 at 18:42
  • google is doing a lousy job by showing excerpts of this answer at the top of search result lol – Superziyi Apr 26 '20 at 07:45