First, socket
In general, the socket has an alias called a socket.
Sockets originate from UNIX and can be manipulated using "open open–> read-write write/read–> close" mode. Socket is an implementation of this pattern, the socket is a special kind of file, some of the socket function is to do it (read/write IO, open, close).
The socket is the intermediate software abstraction layer that the application layer communicates with the TCP/IP protocol family, which is a set of interfaces. In design mode, the socket is actually a façade mode, it is the complex TCP/IP protocol family hidden behind the socket interface, for the user, a set of simple interface is all, let the socket to organize data to meet the specified protocol, Instead of having to let the user define which protocol to specify at what point, which function.
In fact, the socket does not have the concept of a layer, it is only a facade design mode of application, making programming easier. is a software abstraction layer. In the network programming, we use a lot of is through the socket implementation.
1.1 Socket Descriptor
is actually an integer, we are most familiar with the handle is 0, 1, 23, 0 is the standard input, 1 is the standard output, 2 is the standard error output. 0, 1, 2 is an integer representation, the corresponding file * structure is stdin, stdout, stderr
The socket API was originally developed as part of the UNIX operating system, so the socket API is integrated with other I/O devices in the system. In particular, when an application creates a socket (socket) for Internet communication, the operating system returns a small integer as a descriptor (descriptor) to identify the socket. The application then takes the descriptor as a pass parameter and invokes the function to accomplish something (such as transmitting data over the network or receiving input data).
In many operating systems, socket descriptors and other I/O descriptors are integrated, so applications can perform socket I/O or I/OS read/write operations on files.
When an application wants to create a socket, the operating system returns a small integer as a descriptor, and the application uses this descriptor to refer to the socket that requires an I/O request for an application that requests the operating system to open a file. The operating system creates a file descriptor that is provided to the application to access the file. From the application's perspective, a file descriptor is an integer that the application can use to read and write files. Shows how the operating system implements the file descriptor as a pointer array that points to the internal data structure.
There is a single table for each program system. To be precise, the system maintains a separate file descriptor table for each running process. When a process opens a file, the system writes a pointer to the internal data structure of the file to the file descriptor table, and returns the index value of the list to the caller. The application only needs to remember this descriptor and use it later when manipulating the file. The operating system uses the descriptor as an index to access the process descriptor, and the pointer finds the data structure that holds all the information for the file.
System data structures for sockets:
1), Socket API has a function socket, it is used to create a socket. The general idea of socket design is that a single system call can create any socket because the socket is fairly general. Once the socket is created, the application also needs to call other functions to specify the specifics. For example, calling the socket will create a new descriptor entry:
2), although the internal data structure of the socket contains many fields, most of the word fields are not filled in after the system creates the socket. After an application creates a socket, you must call other procedures to populate these fields before the socket can be used.
Second, the basic socket interface function
The server-side initializes/creates the socket, then binds to the port/bind address (BIND), listens to the port (listen), calls accept blocks/waits for continuous, waits for the client to connect. At this point if a client initializes a socket and then connects to the server (connect), the client-server connection is established if the connection is successful. The client sends the data request, the server receives the request and processes the request, then sends the response data to the client, the client reads the data, closes the connection, and ends the interaction at the end.
2.1socket function
Function prototypes
int socket (int protofamily, int type, int protocol);
return value:
Returns SOCKFD SOCKFD is a descriptor, similar to the open function.
function function:
The socket function corresponds to the open operation of the normal file. The open operation of a normal file returns a file descriptor, and the socket () is used to create a socket descriptor (socket descriptor), which uniquely identifies a socket. The socket descriptor is the same as the file descriptor, and subsequent operations are useful to it, using it as a parameter to perform some read and write operations.
Function parameters:
Protofamily: The protocol domain, also known as the Protocol Family (family). Common protocol families are af_inet (IPV4), Af_inet6 (IPV6), af_local (or Af_unix,unix domain sockets), Af_route, and so on. The protocol family determines the socket address type, must use the corresponding address in the communication, such as Af_inet decided to use the IPv4 address (32 bits) and the port number (16 bit) combination, Af_unix decided to use an absolute path name as the address.
Type: Specifies the socket type. Common socket types are sock_stream, Sock_dgram, Sock_raw, Sock_packet, Sock_seqpacket, and so on.
Protocol: is the specified protocol. Commonly used protocols are, IPPROTO_TCP, IPPTOTO_UDP, IPPROTO_SCTP, IPPROTO_TIPC, respectively, they correspond to TCP transport protocol, UDP Transmission Protocol, STCP Transport Protocol, TIPC Transport protocol
Note: Not the above type and protocol can be arbitrarily combined, such as sock_stream can not be combined with IPPROTO_UDP. When protocol is 0 o'clock, the default protocol corresponding to type types is automatically selected.
When we call the socket to create a socket, it returns the socket descriptor that exists in the Protocol family (address family,af_xxx) space, but does not have a specific address. If you want to assign an address to it, you must call the bind () function, or the system will automatically randomly assign a port when you call Connect (), listen ()
2.2bind () function
function function:
The bind () function assigns a specific address in the address family to the socket, or it can be said to be a binding IP port and socket. For example, the corresponding af_inet, Af_inet6 is to assign a IPv4 or IPv6 address and port number combination to the socket.
Function Prototypes:
int bind (int sockfd, const struct SOCKADDR *addr, socklen_t Addrlen);
Function parameters:
1. The three parameters of the function are: SOCKFD: The socket descriptor, which is created through the socket () function and uniquely identifies a socket. The bind () function is to bind a name to the description word.
2.ADDR: A const struct SOCKADDR * Pointer that points to the Protocol address to bind to SOCKFD. This address structure differs depending on the address protocol family when the socket is created.
3.addrlen: Corresponds to the length of the address.
Common function Types:
struct sockaddr{sa_family_t sa_family; Char sa_data[14];}
As IPv4 corresponds to:
struct SOCKADDR_IN { sa_family_t sin_family;/* Address family:af_inet */ in_port_t sin_port; /* port in Network byte order 2 bytes */ struct in_addr sin_addr; /* Internet address 4 bytes */unsigned char sin_zero[8];};/ * Internet address. */struct in_addr { uint32_t s_addr; /* address in network byte order */};
IPv6 corresponds to:
struct SOCKADDR_IN6 { sa_family_t sin6_family; /* AF_INET6 */ in_port_t sin6_port; /* Port number */ uint32_t sin6_flowinfo;/* IPV6 Flow information */ struct in6_addr sin6_addr; /* IPV6 Address * /uint32_t sin6_scope_id;/* Scope ID (new in 2.4) */};struct in6_addr { unsigned char
S6_ADDR[16]; /* IPV6 address */};
The UNIX domain corresponds to the following:
#define Unix_path_max 108struct sockaddr_un { sa_family_t sun_family; /* Af_unix */ char Sun_path[unix_path_max]; /* pathname */};
Usually when the server is started to bind a well-known address (such as IP address + port number) to provide services, the client can be used to connect the server, and the client does not specify, there is a system automatically assigned a port number and its own IP address combination. This is why the server usually calls bind () before listen, and the client does not invoke it, but instead generates one randomly from the system at Connect ().
2.2.1 Address Translation
int_addr_t indet_addr (const char *CP)
Function: Converts the IP address in the form of a string into an integer IP address (network byte-order)
Example: Int_addr.saddr=inet_addr ("192.168.1.1");
Char *inet_ntoa (struct in_addr)
Function: Converts an integer IP address into an IP address in the form of a string
2.2.2 Network byte order
Network byte order definition: The first byte received is treated as a high level, which requires that the first byte sent by the sending side should be high. When sending data on the sending side, the first byte sent is the byte that corresponds to the number in the in-memory start address. Visible multibyte values before sending, in-memory values should be stored in the big-endian method.
The network byte order is said to be the big endian byte sequence.
The small-end method (Little-endian) is the low-bit byte emission at the lower address of the memory, that is the starting address of the value, high-byte emissions at the upper address of the memory.
The big-endian method (Big-endian) is that the high-bit byte is emitted at the low address end of the memory, that is the starting address of the value, and the low byte is discharged at the high address end.
Network byte-order conversions:----> must be converted, whether it's data or address, as long as it's greater than two bytes
uint32_t htonl (uint32_t hostlong); Converts 32-bit data from host byte order to network byte order in_addr.saddr = htonl (inaddr_any) uint16_t htons (uint16_t hostshort); Converts 16-bit data from host byte order to network byte order uint32_t Ntohl (uint32_t netlong); Converts 32-bit data from network byte order to host byte order uint16_t Ntohs (uint16_t netshort); Converts 16-bit data from network byte order to host byte order
2.3, listen (), connect () function
If, as a server, the socket (), bind () is called after the Listen () is invoked to listen to the sockets, the server will receive this request if the client calls connect () to make a connection request.
int listen (int sockfd, int backlog); int connect (int sockfd, const struct SOCKADDR *addr, socklen_t Addrlen)
The first parameter of the Listen function is the socket descriptor to listen to, and the second parameter is the maximum number of connections that the corresponding socket can queue. The socket created by the socket () function defaults to an active type, and the Listen function changes the socket to a passive type, waiting for the client's connection request.
The first parameter of the Connect function is the client's socket descriptor, the second parameter is the server's socket address, and the third parameter is the length of the socket address. The client establishes a connection to the TCP server by calling the Connect function. Successfully returns 0 if the connection fails and returns-1.
2.4. The Accept () function
After the TCP server invokes the socket (), bind (), listen (), it listens for the specified socket address. After the TCP client calls the socket (), connect (), it sends a connection request to the TCP server. After the TCP server hears this request, it calls the Accept () function to take the receive request, so the connection is established. You can then start network I/O operations, which are similar to read/write I/O operations for normal files.
int accept (int sockfd, struct sockaddr *addr, socklen_t *addrlen); Back to Connection CONNECT_FD
Parameter SOCKFD
-
The parameter SOCKFD is the listener socket in the above explanation, which is used to listen on a port, and when a client connects to the server, it uses this port number, which is associated with the socket. Of course, the customer does not know the details of the socket, it only knows an address and a port number.
-
Parameter addr
-
This is a result parameter, it is used to accept a return value, this return value specifies the address of the client, of course, this address is described by an address structure, the user should know what the address structure. If you are not interested in the customer's address, you can set this value to NULL.
-
Parameter len
-
as you can see, it is also the parameter of the result, which is used to accept the size of the addr structure, which indicates the number of bytes that the addr structure occupies. Similarly, it can also be set to null.
If accept returns successfully, the server and the customer have established a connection correctly, and the server completes the communication with the customer through the socket returned by the accept socket.
Attention:
Accept defaults to block the process until a client connection is established, and it returns a newly available socket, which is a connection socket.
At this point we need to distinguish between two sockets,
Listening sockets: The listener socket is a listening socket, just like the parameter sockfd of the accept, after calling the Listen function, the server starts calling the socket () function, which is called the Listener Socket Descriptor (listening socket)
Connection sockets: A socket becomes a listening socket from the active connected socket, and the Accept function returns a connected socket descriptor (a connection socket), which represents a point-in-point connection where a network already exists.
A server typically creates only one listener descriptor, which persists throughout the lifetime of the server. The kernel creates a connected socket descriptor for each client connection accepted by the server process, and when the server has completed a service to a customer, the corresponding connected socket descriptor is closed.
The connection socket socketfd_new does not occupy the new port to communicate with the client, and still uses the same port number as the listener socket SOCKETFD
2.5, recv ()/send () function
Of course, you can also use other functions to implement data transfer, such as read and write.
2.5.1send function
ssize_t Send (int sockfd, const void *buf, size_t len, int flags);
Both the client and server applications use the Send function to send data to the other end of the TCP connection.
The client program typically sends a request to the server with the Send function, and the server usually sends a reply to the client using the Send function.
The first parameter of the function specifies the send-side socket descriptor;
The second parameter indicates a buffer where the application will send data;
The third parameter indicates the number of bytes of data actually to be sent;
The fourth parameter is generally 0.
This describes only the execution flow of the Send function that synchronizes the socket. When this function is called, send compares the length of the data to be sent, Len, and the length of the send buffer of the socket s, and if Len is greater than the length of the send buffer of s, the function returns SOCKET_ERROR, if Len is less than or equal to the length of the send buffer of S, Then send first check whether the protocol is sending the data in the send buffer, if it is waiting for the protocol to send out the data, if the protocol has not begun to send the data in the send buffer or s of the send buffer does not have data, then send compares s of the send buffer of the remaining space and Len, If Len is larger than the remaining space, send waits for the protocol to send the data in the transmit buffer of s, if Len is less than the amount of space left, send will simply copy the data in the BUF to the remaining space (note that it is not the send buffer that sends the data to the other end of the connection). Instead of the protocol, send simply copy the data from the BUF to the remaining space in the send buffer of s). If the Send function copy data succeeds, it returns the number of bytes actually copied, and if send has an error in copy data, then send returns SOCKET_ERROR, if the network is disconnected while the send waits for the protocol to transmit the data. Then the Send function also returns SOCKET_ERROR.
Note that the Send function returns the data in the BUF after it has been successfully copied to the remaining space of S's send buffer, but at this point the data is not necessarily immediately passed to the other end of the connection. If the protocol has a network error during subsequent transfers, the next socket function returns SOCKET_ERROR. (Each of the socket functions except for send will have to wait for the data in the socket's send buffer to continue before execution, and if a network error occurs while waiting, the socket function returns SOCKET_ERROR)
2.5.2recv function Learning
int recv (SOCKET s, char far *buf, int len, int flags );
Both the client and server applications use the RECV function to receive data from the other end of the TCP connection.
The first parameter of the function specifies a receive-side socket descriptor;
The second parameter indicates a buffer, which is used to hold the data received by the RECV function;
The third parameter indicates the length of the BUF;
The fourth parameter is generally 0.
This describes only the execution flow of the recv function that synchronizes the socket. When the application calls the Recv function, recv waits for the data in the send buffer of s to be passed by the protocol, and if the protocol has a network error while transmitting the data in the send buffer of S, then the RECV function returns SOCKET_ERROR, If there is no data in the transmit buffer of s or after the data has been successfully sent by the protocol, RECV checks the socket s receive buffer, if there is no data in the s receive buffer or the protocol is receiving data, then recv waits until the protocol receives the data. When the protocol takes over the data, the RECV function will copy the data from the receive buffer of S to BUF (note that the data received by the Protocol may be greater than the length of the buf, so in this case a few recv functions are called to copy the data from the receive buffer of S. The recv function is just copy data, the real receive data is the protocol to complete, the RECV function returns the number of bytes it actually copied. If recv errors in copy, it returns SOCKET_ERROR, and if the recv function waits for the protocol to receive data, the network is interrupted, it returns 0.
2.6. Close () function
After the server has established a connection with the client, some read and write operations are performed, and the corresponding socket descriptor is closed when the read and write operation is completed, like closing the open file by calling Fclose when the file is opened.
#include <unistd.h>int close (int fd);
Close the default behavior of a TCP socket by marking the socket as closed and then immediately returning to the calling process. The descriptor can no longer be used by the calling process, that is, no longer as the first parameter of read or write.
Linux-socket Model Understanding