2

I am programming a real-time networking system in C/C++ with Berkeley C sockets, which works on a tick-based interval. Every tick, the client program will read data from the socket with recvfrom().

The problem is that if the server did not send any data, the client will read the last data that was sent on the socket.

For example the client (pseudocode)

while (true)
{
   if (time_to_update())
   {
      int n = recvfrom(data,...);
      printf("%s",data);
   }
}

And server:

int main()
{
   int m = recvfrom(data,...);
   int n = sendto(...,"hello");
}

Then the client would keep printing "hello", whereas I only need it to print it once.

This is qutie similar to this question, recvfrom re-reading data on socket ,but I do not understand the answer very well and it does seem to solve the problem more generally.

I'm guessing the data is stored in a buffer on the netword card, in which case is there a away to clear the buffer after 1 read? Another method I have in mind is to number the packets and only read new ones, but all types are finite so I'm hoping there might be a cleaner way.

How would I make it so the client only reads the received data once?

Community
  • 1
  • 1
ParityB1t
  • 77
  • 4
  • 6
    Most likely because your socket is in non-blocking mode, you are not checking the return value from `recvfrom()`, and your code simply ends up reading the same contents of the read buffer you're using. – Sam Varshavchik May 31 '16 at 12:29
  • 1
    Why are you calling `recvfrom()` based on clock ticks, instead of reading when `select()` or `(e)poll()` tells you that data is waiting to be read? – Remy Lebeau Jun 01 '16 at 01:17
  • I am only starting to learn socket programming and the tutorial I found used the older conventions but eventually I will update my knowledge. – ParityB1t Jun 02 '16 at 15:06

2 Answers2

4
printf("%s",data);

Usual problems. Not testing for error; not testing for end of stream; not using the length. Should be:

if (n < 0)
{
    perror("recv");  // or better
    break;
}
else if (n == 0)
    break; // peer has disconnected 
else
    printf("%.*s", n, data);

If you don't check these things you will spin forever and print garbage when they happen.

I'm guessing the data is stored in a buffer on the netword card

No.

in which case is there a away to clear the buffer after 1 read

Reading it clears it. Your problem lies elsewhere.

user207421
  • 305,947
  • 44
  • 307
  • 483
  • Disconnected event is not applicable for UDP sockets. – SergeyA May 31 '16 at 13:19
  • @SergeyA UDP is not mentioned in the question. The use of `recvfrom()` suggests it but does not mandate it. It is my view that he is using TCP and that he is getting a disconnect. His server sends once and then exits. His client receives once and then loops. it wouldn't do all that if it was UDP. If there was a UDP parameter error he wouldn't receive at all, and if it was non-blocking UDP he would print garbage first. – user207421 May 31 '16 at 23:32
  • I guess, you might be correct. OP should be more specific, and I should not have jumped to conclusions. – SergeyA Jun 01 '16 at 01:39
3

Are you checking the returned value in your variable m? It could very well be returning zero or -1 (so no bytes have been read), and you keep re-printing the same value of data over and over again because nothing is modifying it.

Smeeheey
  • 9,906
  • 23
  • 39
  • 1
    UDP sockets will not return 0 on `recvfrom`. – SergeyA May 31 '16 at 13:20
  • 1
    How is that relevant? Nobody mentioned anything about the socket type – Smeeheey May 31 '16 at 13:23
  • You are saying *It could very well be returning zero* It can not. `recvfrom()` can not return 0. – SergeyA May 31 '16 at 13:24
  • 1
    It certainly can from a TCP socket, when the other side performs a shutdown. – Smeeheey May 31 '16 at 13:25
  • 1
    How is that clear at all? First of all he makes no explicit mention of it at all, so it could be either. Secondly I do not claim in my answer that I'm talking about UDP sockets in particular rather than sockets in general. Thirdly the tone of his question in fact suggests to me that he is likely to be talking about TCP sockets (there is no mention of multicasting or any other typically identifying feature of UDP). – Smeeheey May 31 '16 at 13:39
  • Nobody uses `revfrom()` and `sendto()` with TCP sockets (it is possible, but no one does that). – SergeyA May 31 '16 at 13:40
  • 3
    Actually even your opening comment is incorrect. UDP sockets *can* return 0 from `recvfrom`. It is valid to send a zero-length datagram, in which case it will be read as zero bytes. – Smeeheey May 31 '16 at 13:44