When programming a server or a client, we have to deal with port numbers and IP addresses, but we usually do this through an abstraction called a socket. Sockets are the standard API for network programming; they are the abstraction which we use to describe a connection, i.e. a duplex communication. The typical way of creating and using sockets, in C, is the following:
// Client side ------------------------------------------------------------
struct addrinfo *addr;
int fd = socket(AF_INET, SOCK_STREAM, 0); // fd is the socket's filehandle
getaddrinfo("www.cnn.com", "http", NULL, &addr); // converts hostname to IP address
connect(fd, addr->ai_addr, addr->ai_addrlen); // connect to remote host
send(fd, send_buf, len, 0); // now send then receive data
...
recv(fd, recv_buf, len, 0);
// Server side ------------------------------------------------------------
struct addrinfo *addr, *remote_addr;
int fd = socket(AF_INET, SOCK_STREAM, 0);
// fd is the socket's filehandle getaddrinfo(NULL, "http", NULL, &addr); // convert service to port number ("ht bind(fd, addr->ai_addr, addr->ai_addrlen); // bind socket to a particular port nu listen(fd, 1); // listen for connections. Second argument is # of allowable waiting
// Now accept connection on socket fd; when a connection comes in, we'll move it to int newfd = accept(fd, remote_addr->ai_addr, &(remote_addr->ai_addrlen));
// we process the accepted connection on newfd, with recv() and send(),
// and at the same time, we'll keep using fd to accept other incoming connections