Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Trying to understand logic behind network communication

In C, to receive/send data you usually do(roughly):

Server:

  • Create socket
  • Bind socket to port
  • listen
  • Accept
  • Receive Send data

On client side:

  • Create socket
  • Connect
  • Receive send

My question comes after server has done accept.

Imagine after accept on the server side there are three separate lines to send data:

connfd = accept(listenfd, (struct sockaddr*)NULL ,NULL);
write(connfd, var1, var1Size);
write(connfd, var2, var2Size);
write(connfd, var3, var3Size);

Does this mean on the client side I need to have three reads? Like this:

read(sockfd, &x, size1);
read(sockfd, &y, size2);
read(sockfd, &z, size3);

In other words how should send and receive calls correspond on server and client side? Should for each send be a corresponding receive on the client side?

What if on client side, after 3 read calls(like above), I want to send data to server? Shall I just add one new send and one new receive on client and server side respectively?

Should all these send/receives be happening within a single accept call context?

Here is a image to better illustrate what kind of scenario I could be interested in:

enter image description here

Pseudo code explaining how to handle this kind of connections would be welcome.


1 Answers

Unless you are working with a protocol which has a concept of "messages", e.g. UDP, all you have is a stream of bytes. You can send and receive them any way you wish.

You could, for example, send two 16-bit integers and receive them as one 32-bit integer. This is probably not what you intended but it's perfectly legal and used all the time in situations where it is needed. You can compose data structures on either side (sending and receiving) independandly, as long as it makes sense to your application.

Your bytes are sent in the order of your write()'s and you WILL receive them in the same order. I.e.

send(var1)  --->  recv(var1)
send(var2)  --->  recv(var2)

There is no way in normal TCP (barring unused edge cases which I'll not even specify because nobody should use them) that you will receive var2 before var1.

TCP communication is bi-directional: each end-point (client and server) can send at the same time. It is up to you and your application to decide when to send and when to receive. The sending and receiving buffers are independant: you can send a few bytes, receive a few, send some more... and there will be no interference between them (i.e. you will not "overwrite" the receive buffer by sending some data nor vice versa).

I'll repeat it again: ALL you have in TCP is a stream of bytes. TCP doesn't know and doesn't care how these bytes are structured, neither on the sending nor on the receiving side. It's ALL up to you. When you send an integer or a data structure, you are sending a memory dump of those, as bytes.

For example, there's a common error where you attempt to send() a data structure and because the sending buffers are full, the system will make a partial write. If you do not check the return status of the send() call to detect this situation and then send the remainder of bytes by yourself, in another send() call, your client WILL be stuck in recv() when it expects the full structure and receives only a part of it, if you specify MSG_WAITALL.

like image 192
Ivan Voras Avatar answered Feb 05 '26 21:02

Ivan Voras