SOCKET Learning Notes

Introduction

Interview questions mentioning epoll involve socket programming. To understand epoll principles in depth, we first need to understand socket programming. A socket is an inter-process communication (IPC) mechanism, even in networks. This means the main entities communicating in a network are processes, not computers. Socket learning includes how to establish servers and clients, and how to use socket APIs.

fd=socket(domain, type, protocol);

The socket call can be used to create a socket, for example, domain can specify IPv4, type can specify TCP, and protocol is generally 0.

  • domain domain specifies the communication scope and the type of communication address. There are several classic types: UNIX IPV4 IPV6, corresponding to parameters AF_UNIX AF_INET AF_INET6. The domain parameters all start with AF, representing address families. PF stands for protocol families. Originally, address families and protocol families were designed to have many-to-many relationships, but during implementation, each protocol family corresponds to exactly one address family. So basically, specifying the domain determines the protocol family and the address family.

  • type Socket indicates whether it’s a stream or a datagram, which essentially means TCP or UDP. For TCP, it’s SOCK_STREAM; for UDP, it’s SOCK_DGRAM.

bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

This call is used to bind a socket to an address. After that, TCP packets can be sent, and in some cases, UDP packets can also be sent through write, but only data from the peer socket can be read on this socket.

  • sockaddr This structure has an integer representing the address type, followed by a char array. As we’ll see, depending on the use case, other data structures are passed in, but they are generic.

listen(int sockfd, int backlog)

Marks a socket descriptor as passive. It can be connected by active sockets. backlog is used to limit the number of pending connections.

accept(int sockfd, struct sockaddr *addr, socklen_t * addrlen);

The accept call blocks and waits for an incoming request on the file descriptor sockfd. Once the request succeeds, a new socket is created, and this new socket connects with the other party.

  • addr Returns the address of the other party
  • addrlen Passes in the length of addr, indicating the maximum length that can be written.

connect(int sockfd, const struct sockaddr * addr, socklen_t addrlen);

Connects sockfd to the address described by addr.

close(int fd)

Used to close the connection

read write

Used for reading from or writing to sockfd

recvfrom(int sockfd, void *buffer, size_t length, int flags, struct sockaddr *src_addr, socklen_t *addrlen);

sendto(int sockfd, const void *buffer, size_t length, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);

Used to send and receive UDP packets. The server side cannot use the listen function and accept function, and the client side cannot use the connect function.

unix domain

Using the APIs above, communication through files on the local machine can be implemented. The sockaddr used by unix domain is sockaddr_un, represented as follows:

struct sockaddr_un{
    sa_family_t sun_family;
    char sun_path[108];
}

Network Byte Order

The network byte order follows big-endian, while x86 is a little-endian structure. The conversion is done using the following functions:

  • htons
  • htonl
  • ntohs
  • ntohl h is for host, n is for net, s is for 16-bit, and l is for 32-bit. s and l stand for short and long, although these standards are no longer used that way now.

Internet Socket Address Structure

The socket address used in networks is sockaddr_in, defined as follows:

struct sockaddr_in{
    sa_family_t sin_family;
    in_port_t sin_port;
    struct in_addr sin_addr;
    unsigned char __pad[X];
}

As you can see, the difference is that the char array is replaced by a port and an address. sin is the abbreviation of socket Internet, which is as poor an abbreviation as sun.

Internet Socket Address Conversion

APIs for converting string address formats to binary address formats:

inet_pton(int domain, const char *src, void *addrptr);

This function is used to convert the string contained in src to a network byte order binary address, storing it in addrptr. p stands for presentation, meaning a human-readable address.

const char * inet_ntop(int domain, const void *addrptr, char *dst_str, size_t len);

This function converts a network byte order binary address to a human-readable address, writing it to dst_str. The buffer size is passed in by len.

getaddrinfo(const char *host, const char *service, const struct addrinfo *hints, struct **result);

This function returns a socket address and port number given a host name and service name. getaddrinfo takes host, service, and hints as inputs, where the host parameter includes a hostname or an IPv4 string. Service is a service name or a port number. After calling this function, freeaddrinfo should be used to free the space.

getnameinfo(const struct sockaddr *addr, socklen_t addrlen, char *host, size_t hostlen, char *service, size_t servlen, int flags);

Given a socket address structure, returns a host and service name string.

setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);

sockfd is the file descriptor pointing to the socket. The level parameter specifies the protocol to which the socket option applies, such as TCP or IP, indicating the socket API layer where the option takes effect. Generally, this option is set to SOL_SOCKET, indicating that it applies to the socket API layer. The optname parameter indicates the option we expect to set, optvalue is used to set the value of that option, which can be an integer or a pointer to a structure pointing to a buffer, and the optlen parameter is the size of the region pointed to by that pointer.

For example, to set sockfd to the reuseaddr property, you can call:

    int reuse = 1;
    if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) == -1)
    {
        err_exit("setsockopt");
    }

getsockopt(int sockfd, int level, int optname, void *optval, socklen_t optlen);

The usage is the same as above, but it’s for getting rather than setting.

comments powered by Disqus
Built with Hugo
Theme Stack designed by Jimmy