How is the network connected (5) entrust the protocol stack to send messages

Think about the key

  • How do I delegate application messages to the protocol stack for delivery?
  • Which functions are called to send and receive the socket?

Core knowledge

How does the protocol stack send and receive operations

Now to tidy up the data you have, first the HTTP message packet has been packaged by the application and the server IP address has been obtained through the DNS1 request mechanism. With both conditions satisfied, we can start thinking about how to send this data to the application on the other server

Sending data is actually achieved by calling multiple socket library functions, by entrusting multiple function API to carry out a series of task interaction, each task to complete different projects, including establishing a connection part, disconnecting, etc., the purpose of these operations is to ensure whether the two parties receive the message and whether the response is normal 2

Implementation using socket

In order to establish a dedicated communication channel between the two applications, we called the socket library function. In many books, establishing a socket is described as building an invisible channel through which the two parties can send and receive messages. However, it does not mean that the computer is allowed to communicate with the network after establishing the socket. Computers sent and received messages to the network long before sockets were set up. Setting up sockets is more like determining which transmission channel we should go to find each other’s applications

Along those lines, this section describes how an application calls a socket library function to send and receive delegates. I like to use a network booking analogy to describe the steps of establishing socket connection, just like we are using the mobile app to book the room, entrust the system to operate, the real process is actually unknown, this is like standing in the perspective of the application layer to see socket connection 3

Create a stage

Purpose: Create a socket of the specified type

Just download this booking app!

Application case

Let’s look at the socket create section first:

int socket(int domain, int type, int protocol);
Copy the code

  • domain
    • The family of protocols that determines which socket to use in network transmission
    • AF_INET stands for TCP/IP network communication protocol
  • type
    • Specifies the socket type
    • SOCK_STREAM corresponds to TCP
    • SOCK_DGRAM corresponds to UDP protocol
    • SOCK_RAW can be IP or ICMP
  • protocol
    • After domain and type are set, the communication type is almost complete. Therefore, protocol is usually set to 0, indicating that the default protocol is set according to the specified type
socket(AF_INET, SOCK_STREAM, 0); // Select TCP socket(AF_INET, SOCK_STREAM, 6); // Still TCP socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); // Still TCP socket(AF_INET, SOCK_DGRAM, 0); // This time it is UDPCopy the code
#include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <sys/socket.h> // #define AF_INET 2 // #define SOCK_STREAM 1 int main(int argc, char *argv[]){ uint32_t socket_identifier = 0; /* Create socket*/ socket_identifier = socket(AF_INET, SOCK_STREAM, 0); Switch (socket_identifier){case 1: // Positive case 2:... case n: printf("socket create successfully! \n"); break; case -1: printf("socket create error! \n"); } return 0; }Copy the code

If a socket is successfully created, an identifier greater than 0 is returned. If a negative value is returned, it indicates that the socket is incorrectly created

The attachment stage

Purpose: To enable two applications to establish a connection channel

Use this account to log into the app

Application case

Take a look at the current stage:

int connect(int fd, struct sockaddr *server, int addrlen);
Copy the code

The sockaddr structure is used to set up a socket connection with a socket connection. The sockaddr structure is used to set up a socket connection with a socket connection.

struct in_addr{ ip_addr_t s_addr; }; struct sockaddr{ unsigned char sin_family; //AF_INET so IPv4 unsigned short sin_port; Struct in_addr sin_addr; // Server IP address unsigned char sin_zero[8]; // do not use};Copy the code
  • fd
    • The socket descriptor
    • Socket_identifier = socket_identifier (); socket_identifier = socket_identifier ()
  • server
    • The sockADDR structure is responsible for providing all connection messages for the socket
  • addrlen
    • Structure sockADDR length
#include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <string.h> #include <malloc.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #define SERV_PORT 8080 typedef sockaddr* info; int main(argc, char* argv[]){ info serv=(info)calloc(0, sizeof(sockaddr)); uint8_t resp; Serv ->sin_family = AF_INET; serv->sin_family = AF_INET; serv->sin_port = htons(SERV_PORT); Inet_pton (AF_INET, "127.0.0.1" serv - > sin_addr); resp = connect(socket_identifier, (info)serv, sizeof(sockaddr)); if(resp < 0) printf("socket connect error! \n"); return 0; }Copy the code

By creating the socket function API, we get the local socket number socket_identifier4. The next task is to connect to the application on the server. The IP address will help us find the server address, and port number 5 will help us find the application running on the server

Sending and receiving phase

When we successfully establish the connection, the data can flow between the two applications through the socket, then we can fetch the data using read()/recv() and transfer the data using write()/send(). The only difference between read()/write and recv()/send() is that the recv()/send() input parameter has a flag descriptor, which provides more detailed control over the operation options. However, we will continue to use the generic socket API → read()/write

Send a message

Purpose: Write data to the Socket and send it

This is it! Order now!

Application case
ssize_t write(int fd, const void *buf, size_t nbyte);
Copy the code
  • Fd is the descriptor
  • Buf is the buffer to which data is written. The const decorates buf to prevent changes
  • Nbyte is the buffer size
#include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <string.h> #include <malloc.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> define MAX 1024 char* buf=(char*)malloc(max); // buffer int main(argc, char* argv[]){ ssize_t s_write; Strcpy (buf, "socket test"); strcpy(buf, "socket test"); s_write = write(socket_identifier, buf, MAX); if(s_write < 0){ printf("socket write error! \n"); } else{ printf("socket write data length=%d\n", s_read); // How much data is sent}... return 0; }Copy the code

If the buffer size is 0, 0 will be returned. If the buffer size fails, -1 will be returned. It and the received message read(), which we’ll cover later, are essentially two enemies, one eager to push data into the buffer and the other eager to push data out

Receives the message

Purpose: To read data through the Socket in the connection

System prompt ~ you have placed the order successfully!

Application case
ssize_t read(int fd, void* buf, size_t nbyte);
Copy the code
  • Fd mentioned that earlier
  • Buf is the buffer that reads the data, and socket is the buffer that pushes the data
  • Nbyte is the buffer size
#include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <string.h> #include <malloc.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> define MAX 1024 char* buf=(char*)malloc(max); // buffer int main(argc, char* argv[]){ ssize_t s_read; / /*socket read*/ s_read = read(socket_identifier, buf, MAX); if(s_read < 0){ printf("socket read error! \n"); } else{ printf("socket read data length=%d\n", s_read); // Read buffer length}... return 0; }Copy the code

A negative number indicates an error, and a 0 or a positive number indicates the size of the buffer read. If we get a return value of 0, we may have several special meanings:

  • The buffer was empty. There was nothing
  • The socket domains of the communication parties are inconsistent, such as AF_INET and AF_INET6
  • When two communicators are suddenly connected

Close the stage

Purpose: Disable the socket

If you have finished booking, please log out

Programming paradigm

int close(int fd);
Copy the code
  • Fd needs no further explanation
#include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <string.h> #include <malloc.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> int main(argc, char* argv[]){ int s_close; S_close = close(socket_identifier); s_close = close(socket_identifier); (s_close < 0) ? printf("socket close error!" ) : printf("close successfully!" ); return 0; }Copy the code

If the socket is used to disconnect communication between two parties, 0 is returned on success, and -1 is returned on error


  1. [[How is the Internet connected (4)DNS]]↩
  2. The transport layer uses TCP ↩
  3. The section on socket connections will cover ↩ when we introduce the transport layer
  4. The identifier is used by applications to identify numerous local end sockets using ↩
  5. The socket between the client and server is used to identify multiple peer sockets using ↩