Network programming-socket related concepts

Byte order

To understand network programming, you need to understand the storage order of bytes in computer communication.

Endian concept

Considering a 32-bit machine, the CPU accumulator can load 4 bytes at a time. The order of the 4 bytes in the memory affects the integer value loaded by the accumulator.
The endianness is divided into Big-Endian and Little-Endian. The sender always has to convert the data to big-endian byte order and send it

  • Big-endian byte order: refers to the high-order byte of the integer stored at the low address of the memory, also known as network byte order
  • Little-endian byte order: the high-order byte of the integer is stored at the high address of the memory, which is mostly used by modern PCs

Assuming that the direction of memory increase is from left to right, the storage format of 12345678 in the memory is as follows

  • The storage in big-endian byte order is 0x12 0x34 0x56 0x78, 12 is the high bit of the number, stored in the low bit of the memory address
  • The storage in little-endian byte order is 0x78 0x56 0x34 0x12, 12 is the high bit of the number, stored in the high bit of the memory address

Endian conversion function

The byte order conversion function is encapsulated in BSD Socket, the header file is #include <arpa/inet.h>

  1. Conversion port
  • uint16_t htons(uint16_t hostshort); // host byte order-network byte order
  • uint16_t ntohs(uint16_t netshort); // network byte order-host byte order
  1. Convert IP
  • uint32_t htonl(uint32_t hostlong); // host byte order-network byte order
  • uint32_t ntohk(uint32_t netlong); // Network byte order-host byte order

among them

  • h-host host, host byte order
  • to-what to convert into
  • n-network network byte order
  • s - short unsigned short
  • l - long unsigned int

Socket introduction

Socket is used for communication between processes between different hosts.
Socket contains IP address and port.
Socket communication is divided into server-side and client-side.

Socket socket is an abstraction of the breakpoint of two-way communication between application processes on different hosts on the network. Socket is one end of process communication on the network, providing a mechanism for application layer processes to exchange data using network protocols

Socket can be regarded as the endpoint of each communication connection when two network applications communicate. This is a logical concept. It is an API for inter-process communication in a network environment, and it is also a communication endpoint that can be named and addressed. Each socket in use has its type and a process connected to it.

In the Linux environment, sockets are used to represent special file types for network communication between processes. The essence is a pseudo file formed by the kernel with the help of a buffer. Can be referenced with file descriptors.

socket address

The socket address is actually a structure that encapsulates information such as port number and IP

Socket address includes general socket address and dedicated socket address

Universal socket address

The socket address in the socket network programming interface is the structure sockaddr, which is defined as follows

#include <bits/socket.h>
struct sockaddr {
    
    
    sa_family_t sa_family;
    char sa_data[14];
};
typedef unsigned short int sa_family_t;

The sa_family member is a variable of the address family type (sa_family_t). The address family type usually corresponds to the protocol family type. The common protocol
family (also called domain) and the corresponding address family are as follows:
Insert picture description here
Macros PF_* and AF_* are defined in the bits/socket.h header file, and the latter has exactly the same value as the former , So the two are usually mixed
.
The sa_data member is used to store the socket address value. However, the address values ​​of different protocol families have different meanings and lengths, as
shown below : The
Insert picture description here
14-byte sa_data cannot hold the address values ​​of most protocol families at all. Therefore, Linux defines the following new
general socket address structure. This structure not only provides enough space for storing address values, but is also memory-aligned.

#include <bits/socket.h>
struct sockaddr_storage
{
    
    
    sa_family_t sa_family;
    unsigned long int __ss_align;
    char __ss_padding[ 128 - sizeof(__ss_align) ];
};
typedef unsigned short int sa_family_t;

Dedicated socket address

Many network programming functions were born earlier than the IPv4 protocol. At that time, the struct sockaddr structure was used. For forward compatibility, sockaddr now degenerates into a (void *) role, passing an address to the function. As for whether this function is sockaddr_in or sockaddr_in6 is determined by the address family, and then the function is forced to convert the type to the required address type.

Insert picture description here
The general socket structure is not easy to use. It is necessary to perform tedious bit operations when setting and obtaining the IP address and port number. Therefore, Linux provides a dedicated socket structure for each protocol family.

The UNIX local domain protocol family uses the following dedicated socket address structure:

#include <sys/un.h>
struct sockaddr_un
{
    
    
    sa_family_t sin_family;
    char sun_path[108];
};

The TCP/IP protocol family has two dedicated socket address structures, sockaddr_in and sockaddr_in6, which are used for IPv4 and IPv6 respectively:

#include <netinet/in.h>
struct sockaddr_in
{
    
    
    sa_family_t sin_family; /* __SOCKADDR_COMMON(sin_) */
    in_port_t sin_port; /* Port number. */
    struct in_addr sin_addr; /* Internet address. */
    /* Pad to size of `struct sockaddr'. */
    unsigned char sin_zero[sizeof (struct sockaddr) - __SOCKADDR_COMMON_SIZE -
    sizeof (in_port_t) - sizeof (struct in_addr)];
};
struct in_addr
{
    
    
    in_addr_t s_addr;
};
struct sockaddr_in6
{
    
    
    sa_family_t sin6_family;
    in_port_t sin6_port; /* Transport layer port # */
    uint32_t sin6_flowinfo; /* IPv6 flow information */
    struct in6_addr sin6_addr; /* IPv6 address */
    uint32_t sin6_scope_id; /* IPv6 scope-id */
};
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
typedef uint16_t in_port_t;
typedef uint32_t in_addr_t;
#define __SOCKADDR_COMMON_SIZE (sizeof (unsigned short int))

It is worth noting that:

  1. The port numbers in these dedicated socket structures are all expressed in network byte order.
  2. All variables of the dedicated socket address (and sockaddr_storage) type need to be converted to the universal socket address type sockaddr (direct coercion) during actual use, because the type of the address parameter used by all socket programming APIs is sockaddr.

Guess you like

Origin blog.csdn.net/MinutkiBegut/article/details/114265869