user14602432
user14602432

Reputation: 11

Blocking and non-blocking file descriptors under the hood

I've spent already some weeks investigating how Linux tcp/ip stack works. And the most difficult part for me is network sockets. I have a lot of questions but I will do my best to be as specific as possible. Let's talk about udp sockets for simplicity.

  1. As I understand recvfrom() is just a case of read() syscall for copying data from the socket buffer inside kernel to the user space. I looked through the implementation and all user space operations end at the point sock->ops->some-protocol-dependent-operation (i.e. sock->ops->recvmsg). Correct me if I am wrong.
  2. What happen next? Logically, we need to check if socket has data for us and than return (copy) it according to the protocol(UDP) structure implemented in the kernel TCP/IP stack. Again correct me if I missed something important.
  3. And here is the 'darkest' part for me. I know that sockets (roughly speaking opened file descriptors) could be blocking and non-blocking. I know that network sockets are blocking by default (Why so?). What I cannot understand is how kernel blocks them. I tried to find this in Linux kernel sources but it's pretty hard. What I understand from the bunch of same questions is: When NIC has data arrived it signals cpu and pass it through the network stack up to the TCP layer. On that level we have opened socket and our network stack copy incoming data to the socket buffer. Then some magical system (what is the name and how does It poll the buffer?) signals that there is an event on a fd, so recvfrom becomes unblocked. The next question: Is recvfrom just make process sleep (what mechanism is used? sigwait?). Or Is there a long polling somewhere inside of this stacktrace?
  4. Does turning fd to non-blocking mode mean using epoll somewhere inside? Why cannot I just use it in my program to check that fd is ready and than call recvfrom ? Or this is a bad practice?

Guys, really sorry for so broad topic but everything is interconnected and I cannot split it to different parts.

Upvotes: 1

Views: 281

Answers (1)

Lize
Lize

Reputation: 1

I think you have a correct approach for the first question

Then, UDP is not connected -> you will only need one recvfrom (). However TCP is connected and so you will "keep" your connexion and so you will also maybe need several recv() (and so to make a loop) [I don't really know if it is what you want to know...]

recv() and recvfrom() are blocking functions (they wait a new message), and so to unblock them you will need fcntl () [e.g: fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFL) | O_NONBLOCK)]. And then, you can verify that you have new message with loops. But I think this is easier using select () (you have'nt to use fcntl() and it allow to use a socket only when it is activated by an activity [reception here]).

I hope this will answer your questions (and I hope I say nothing bad)

Upvotes: 0

Related Questions