All networking API function are considered equivalent to system calls
such as read
{.verbatim} or write
{.verbatim}, they lay in man(2).
#define INADDR_ANY (u_int32_t)0x00000000
in_addr_t inet_addr(const char *cp);
uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);
int socket(int domain, int type, int protocol);
int bind(int sock_fd, struct sockaddr *addr, socklen_t addr_size);
int listen(int socket, int backlog);
int connect(int socket, const struct sockaddr *address, socklen_t address_len);
ssize_t send(int socket, const void *buffer, size_t length, int flags);
ssize_t recv(int socket, void *buffer, size_t length, int flags);
When socket()
{.verbatim} is created, which is just allocating a file
resource in the OS, by specifiying the protocol family and type, and
which mode of transmission i.e. UDP or TCP. It requires additional
information on the address itself, namelty the host and the port, which
both should be in machine encoding i.e. same behaviour as
hton()
{.verbatim}.
- Except that
inet_addr()
{.verbatim} returns the address in machine encoding already
As a legacy, there are two types
struct sockaddr
{.verbatim} andstruct sockaddr_in
{.verbatim}, they represent the same information, but the later is more convenient to work with.
At last, both the socket and the address are entangeled using
bind()
{.verbatim}
When getting a socket for the server, we may listen()
{.verbatim} for
incoming connections. Each new connection is a new socket()
{.verbatim}
associated with a client, that is created after calling
accept()
{.verbatim}.
However, listen()
{.verbatim} runs asynchronously,
accept()
{.verbatim} should be called for as many clients that ahve
sent the request. Yet, it blocks e.g. same as waiting for IO. Thus if no
new request has been sent, accept()
{.verbatim} will await and blocks
the process.
This can be resolved using multitasking, by telling the OS to not block
using fcntl()
{.verbatim} to alter the flags of the socket file. And
then use poll()
{.verbatim} to fetch only the ones that are ready to be
fetched. By setting event POLLIN
{.verbatim} on creation, the OS would
set flags in return when it is unblocking. Now instead of blocking the
process, an EWOULDBLOCK
{.verbatim} (or EAGAIN
{.verbatim}) would be
raised, resolving the block.
For each client that has sent, we may recv()
{.verbatim} some data to
be put in a buffer, the length of the data is returned, and a closed
connection would return 0. However, the total length of the incoming
data may overfit the size of the buffer, thus it may require multiple
reads until it blocks by raising errno
{.verbatim}.