Preliminary analysis of Linux network programming API functions
Today, let's look at some of the core APIs in network programming mentioned in the previous blog posts, and explore what specific preparations and initializations are being done in the kernel when we invoke each API.
1 , Socket (family,type,protocol)
When we are developing a Web application, we use the system calls to create a socket. The work done by the API is as follows:
The system call mainly accomplishes two tasks: "Create sockets" and "bind file handles for sockets".
The socket{} structure is defined as follows:
struct Socket {
Socket_state State; Socket status
unsigned long flags; identification, such as Sock_async_nosapce
Const struct proto_ops *ops; Protocol-specific socket operation set
struct Fasync_struct *fasync_list; Asynchronous wake-up queue
struct file *file; Pointer to file
struct sock *sk; Point to the sock structure in the next layer
wait_queue_head_t wait; Wait for a list of tasks on this socket
Short type; Types of Packets
};
When you create a socket socket, you are initializing these members, such as OPS, file, and SK.
1). Create socket: Sock_create ()
Find the address cluster we specified in the global array struct net_proto_family net_families[] According to the family parameter value. Different types of address clusters have a struct net_proto_family{} type of object, such as the ax25_family_ of our common IPv4 Inet_family_ops,ipv6 inet6_family_ops,x25 protocol OPS and so on. When the kernel is initialized, the modules call the Sock_register () interface inside their initialization function to register their respective address cluster objects in the net_families[] array.
Our analysis focuses on the IPV4 protocol cluster, the Inet_family_ops object. The focus is on the Inet_create function, which is the main task of creating a socket socket and initializing the relevant struct members as necessary. As for the basis and principle of its creation when we talk about the protocol stack, we understand that this is mainly to let everyone have a perceptual grasp of its process execution process.
In the Sock_alloc () function we create an object of struct socket{} type, which, if called a, assigns the second parameter Type field of the socket () system call to A->type.
In the Inet_create () function, we find our corresponding protocol conversion switch in the global array struct INET_PROTOSW inetsw[] based on the value of type. The inetsw[] array is initialized in the Inet_init () function:
Where inetsw_array[] is a more important data structure, defined in the af_inet.c file:
depending on the value of type, you can determine whether the struct Socket{}->ops is inet_stream_ops, Inet_dgram_ops, or Inet_sockraw_ops. Then, in the corresponding case, a struct sock{} object Sk=sk_alloc () is instantiated with Tcp_prot, Udp_prot, or Raw_prot as input parameters. The association between socket{} and sock{} is established, and finally the third parameter of the socket () system call is protocol to the property sk_protocol in the sock{} object.
Do not understand don't worry, I said, here is just for everyone to comb the whole process, until we talk about the protocol stack chapter, and then look back to this article, feel these things are too small pediatrics.
2). Handle for socket binding file: Sock_map_fd ()
We all know that network sockets are also a kind of system IO, so it is unavoidable to deal with file systems. Each socket corresponds to an open file identifier, so after the socket initialization is complete, it is necessary to associate it with a local unique file identifier, that is, to establish an association between socket{} and file{}.
2 , Bind (SOCKFD, sockaddr, Addrlen)
The system call executes in the kernel as follows:
The focus is on the Socket->ops->bind () callback interface. We now know that for IPV4, the OPS here is nothing more than a inet_stream_ops,inet_dgram_ops , or inet_sockraw_ops object. As it happens, the bind function pointers in these three objects all point to the Inet_bind () function. Only the case of the original socket, this will call the Raw_prot object's bind callback function, that is, Raw_bind ().
3 , Listen (SOCKFD, backlog)
Here we can see that non-connected sockets and raw sockets are not listen, and only streaming sockets are valid.
4 , connect (SOCKFD, sockaddr, Addrlen)
From this picture we do see that the Connect () system call can be used not only for connection-oriented sockets, but also for connections and raw sockets.
5 , Accept (SOCKFD, sockaddr, Addrlen)
Similarly, we see that only connection-oriented streaming sockets call accept () to make sense. The final call is the Accept member function of the Tcp_prot object.
This article is to further analyze the network programming in several common API functions within the call process, on the one hand, you can have a deeper understanding of these APIs, not just stay on the metaphysical level, on the other hand for the subsequent analysis of the implementation of the protocol stack principle, lay a solid foundation.
Not finished, to be continued ...
Uncover the veil of common API for network programming "on"