Crouching Kitten
Crouching Kitten

Reputation: 1185

C socket atomic non-blocking read

I'm implementing a TCP/IP server application which uses epoll in edge-triggered mode and does non-blocking socket operations. The clients are using simple blocking operations without epoll.

I don't see how "atomic reads" can be implemented on the server side. To explain what I mean about "atomic read", see this example with simple blocking operations:

But in the case of epoll + non-blocking operations this can happen:

In this case the read is not "atomic". It is not guarantied that when the data was written with a single write operation, then the read will return the whole, in one piece.

Is it possible to know when the data is partial? I know that one solution is to always append the data size to the beginning, or another could be to always close and re-open the connection, but I don't wanna do these: because I think the kernel must know that not the full "package" (how is that unit called BTW?) arrived, since it guaranties atomicity for the blocking operations.

Many thanks!

Upvotes: 1

Views: 1065

Answers (1)

Prabhu
Prabhu

Reputation: 3541

TCP is stream based and not message oriented. Even in case of blocking socket, you cannot be guaranteed that what the application sends would go as is on the wire in one go. TCP will decide its own course.

So, it is up to the application to do "atomic" read of it wishes. For example:

The application protocol should dictate that the message should be prepended by the length bytes. The length bytes inform the peer the size of the application data of interest. Of course, the application should be aware of when the two byte length indicator begins.

[2 byte msg length][Data bytes of interest]

Based on this information the application doing read should take action. It should be polling the socket until it receives all bytes as indicated by the msg length bytes. Only then process the data.

If you need "atomic" read and not partial read you can use MSG_PEEK flag in recv. This shall not remove the data from the socket buffer. Application peeks into the socket, see if required number of data is in socket buffer based on return value.

ret = recv(sd, buf, MAX_CALL_DATA_SIZE, MSG_PEEK);

Upvotes: 3

Related Questions