Little deeper on how send() and recv() works


I want to get a better understanding of how send() and recv() functions works.


When my server is connected to a client and I use send(), nothing seems to have been sent until the client has called recv(). If so, is the client in control of when their network receives data in this case?

If not, then I can send large amounts of data to the client's network without them being able to influence it?


Someone who has the time to give me better insight here?
Last edited on
it is sent immediately, as best as the hardware can comply, and assuming you had a working connection. The target computer's hardware and OS and all buffer up the data, recv pulls from the buffer. The buffer has limits, so you can't send a terrabyte over and then expect to pull that down with recv. Its designed expecting that its being read as its being sent -- you can get away with some delay on that, but I would not try to exploit this too much, the buffers are 'relatively' small.

If you fire up some monitoring tools you can see that you sent it, regardless of whether recv was called or not. Wireshark is a powerful but overkill tool; your built in OS tools have enough to watch bytes go across a network to see it in action.
Last edited on

Hi Jonnin. Thank you for your time. Appreciate it.


Based on your explanation, I interpret it as this...

As soon as I have called send() the data is sent to the client's computer/machine where it's stored in a "secret place"/internal buffer. Then when the client calls recv() he reads from that internal buffer.

So even if the client choose not to recv(), the clients computer still receives as much as it can handle when I call send().

Is this correct?
The thing to remember about a TCP connection is that your ONLY guarantee is that the order you write bytes at one end is the order you receive them at the other end.

Things like
- how many bytes actually get transferred in any given send() / recv() call
- how long it takes a byte to traverse the network

In particular, if send() or recv() return a partial result, then it's YOUR code that needs to retry the call to transfer the remaining data.

Think of the socket as a pipe.
You stuff bytes in at one end, and you get them out at the other.
yes, at a high level that ignores details, that is correct. Again, I urge you not to put this knowledge into your code in some attempt to let it buffer up to read later though. Just kick off a thread that reads it as fast as it can, and if you want to store it for much later, do that yourself into a file or your own buffer.
Allright.

I ran a client and server a on my computer.

Client send() multiple times, server just stays in a loop and does not use recv()

E.g. Client:

1
2
3
while (..) {
    send (...);
}



When the client sends small amounts of data, it sends several times.

However, if client send() more than a certain amount the loop occurs only once and is not repeated until the server recv() again.

This should mean that both have some control over how much data the other side can send? So how does the client know that he can't send() more at the moment here? Is something being communicated in the underlying protocol between the server and the client?

Maybe when send(), to begin with it asks if the other side is ready to receive before it actually sends? Or something similar?
Last edited on
Yes, you need to study your protocol to see what the rules are. UDP and TCP are different, for example. They do talk to each other. "Hey, my buffer is full, shut up" ... "ok, is it still full? how about now? and now? ... oh, you emptied it, have some more!" I don't remember how all that works. Its been handled for me by the tools for so long and I last dug into the details in school which is a dim memory. Something about ymodem batch and kermit.
Last edited on
your built in OS tools have enough to watch bytes go across a network to see it in action.

Thanks. What OS tools are you referring to and how should I use them to watch what comes in and out?
Last edited on
well, what OS are you on :)
Windows monitors network bytes in the task manager, for example. My virus scanner also tracks this. I can also see it in a couple of other places like the network settings/ driver areas.
if client send() more than a certain amount the loop occurs only once and is not repeated until the server recv() again.


What's "a certain amount"?

Why aren't you checking send's return value for an error?

What do you mean "until the server recv() again"? You said previously that "server just stays in a loop and does not use recv()".
Windows monitors network bytes in the task manager, for example.


Thanks :)


What do you mean "until the server recv() again"? You said previously that "server just stays in a loop and does not use recv()".


You're right, it was poorly explained there. Let's try again...

When server stayed in a loop without doing anything, client could use send() multiple times as long as "send buffer length" wasn't too big. When it was too big the client could only send once so I re-run the server and added recv() within that loop where it didn't do anything previously... Now client could send multiple times no matter the size.

I have a new question on the same topic so I'll continue here.


When my http server receives a file request from the browser it sends the entire file(36mb). Send() returns a receipt with a result equal to the entire file length + headers length.

However, webtools show that only 171 B has been received and everything is OK / 206 partial. What happened to the rest? Is the entire file (36mb) sent to the browser/recipient and then only 171 B is read into the browser?

The browser continues to send requests, the server receives a second request for a new range that should already have been sent and received the first time. Webtools shows that 176 B is received for this one.

I understand that the entire video is not necessary in the beginning before the user has pressed play, but why not take what is needed when it receives the first response instead of creating 2-3 recurring identical requests? I have been thinking a lot about this behavior and really hope someone has time to give me a little better insight into what is happening?



Request 1:

GET /file.mp4 HTTP/1.1
Host: localhost:27015
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
Accept-Encoding: identity;q=1, *;q=0
User-Agent: Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.117 Safari/537.36
Accept: */*
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: no-cors
Referer: http://localhost:27015/index.php
Accept-Language: sv-SE,sv;q=0.9,en-US;q=0.8,en;q=0.7
Cookie: _ga=GA1.1.335564697.1576867333
Range: bytes=0-


Response:

HTTP/1.1 206 Partial Content
Accept-Ranges: bytes
Connection: keep-alive
Content-Type: video/mp4
Content-Range: bytes 0-38722853/38722854
Content-Length: 38722854

(body)



Request 2:

GET /file.mp4 HTTP/1.1
Host: localhost:27015
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
Accept-Encoding: identity;q=1, *;q=0
User-Agent: Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.117 Safari/537.36
Accept: */*
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: no-cors
Referer: http://localhost:27015/index.php
Accept-Language: sv-SE,sv;q=0.9,en-US;q=0.8,en;q=0.7
Cookie: _ga=GA1.1.335564697.1576867333
Range: bytes=262144-


Response:

HTTP/1.1 206 Partial Content
Content-Range: bytes 262144-38722853/38722854
Content-Length: 38722854
Accept-Ranges: bytes
Connection: keep-alive
Content-Type: video/mp4

(body)

Last edited on
I do not know webtools.
but if you want to see what happened, run wireshark on this one.
It will tell you what went where and how. I would do this on a pair of machines on a local network with nothing else, including no internet, if you can. It saves a lot of hassle as you have to filter out the noise if there is other chatter going on.
With webtools I mean the browsers own dev tools.

Wireshark "Adapter for loopback traffic capture" is the only one showing traffic. The noise is still there even if I turn off internet. I tried it anyway and looked after the green rows (HTTP) . It shows all the requests to the server but only the "HTTP 200 OK" responses. Cant find anything about the responses with "HTTP 206 Partial Content".

The return value of send(), is it a confirmation of how many bytes has been sent from my computer? Or have the bytes only been stored in the internal buffer waiting for TCP to do its thing?
Last edited on
there is for sure messages about what was received passed back. But you should see the large file's packets too, they are in there somewhere if you sent them to the other machine. If you are still not calling recv, it may not be large enough to stand out. If you are handling what was sent, it should show the full large size being transferred.

Wireshark should show *everything* if you turn it on to do so. It takes a bit of learning and playing with it to get it filtered down to just what you want to see without filtering anything you wanted...

you may also want to step aside and study how it works down in the weeds. Again, its worked for so long that I have not thought about what the hardware and software are doing for me in a very long time. All this stuff is very, very well documented at every level on the web. It may be best to just dig in and read a bit then try to apply what you learn back to what you see. Trying to understand it by reverse engineering it will be hard .. there is a lot going on in there.
Last edited on

Yes, I'll read more about it, see what I can find. Thanks anyway man. It is appreciated as usual.

If anyone else knows anything more about this and would like to contribute, please do so.
Topic archived. No new replies allowed.