#include <sys/socket.h> #include <netinet/in.h> /* TCP socket: (man 7 tcp) */ #include <netinet/tcp.h> int tcp_socket = socket(AF_INET, SOCK_STREAM, 0); /* UDP socket: (man 7 udp) */ #include <netinet/udp.h> int udp_socket = socket(AF_INET, SOCK_DGRAM, 0);
The inet (ipv4) sockaddr_in structure:
struct sockaddr_in { sa_family_t sin_family; /* address family: AF_INET */ in_port_t sin_port; /* port in network byte order */ struct in_addr sin_addr; /* internet address */ }; /* Internet address. */ struct in_addr { uint32_t s_addr; /* address in network byte order */ };
A TCP or UDP socket on the internet is identified by two pieces of information, the machines IP address (a 32 bit integer value) and a port number (a 16 bit integer value.)
The address and port are stored in the structure in network byte order (man 3 byteorder) which has the most significant byte first. Intel machines are least significant byte first, so integers cannot be directly assigned to the structure, portable code should make no assumption in any event.
To convert numbers to network byte order (and back again) you may use the following set of functions (man 3 byteorder):
#include <arpa/inet.h>
uint32_t htonl(uint32_t hostlong); Covert a host long to network long
uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort); Convert a host short to a network short
uint16_t htons(uint16_t hostshort);
uint32_t ntohl(uint32_t netlong); Convert a network long to host long
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort); Convert a network short to a network short.
uint16_t ntohs(uint16_t netshort);
Port numbers below 1024 are "reserved" for known services. Using one requires elevated privileges.
While a server should use a specific port when bind()ing so that clients can find it. A client socket does not bind() but will be randomly assigned a free port on address INADDR_ANY when connect()ing to a remote host.
Pre-defined "addresses":
int serv_sock = socket(AF_INET, SOCK_DGRAM, 0); struct sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_port = htons(1234); /* Allow connections on any IP address this machine uses: */ addr.sin_addr.s_addr = INADDR_ANY; bind(serv_sock, (struct sockaddr *)&addr, sizeof(struct sockadd_in));
#include <netdb.h> extern int h_errno; struct hostent *gethostbyname(const char *name);
Resolves a DNS name to a hostent structure. Returns NULL on failure.
struct hostent { char *h_name; /* official name of host */ char **h_aliases; /* alias list */ int h_addrtype; /* host address type */ int h_length; /* length of address */ char **h_addr_list; /* list of addresses */ } #define h_addr h_addr_list[0]
#include <sys/types.h> #include <sys/socket.h> ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);
Sends a message to the given dest_addr, otherwise just like write.
dest_addr
int client_sock = socket(AF_INET, SOCK_DGRAM, 0); struct sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_port = htons(1234); struct hostent *he = gethostbyname("oldmanprogrammer.net"); if (he == NULL) { herror("gethostbyname"); exit(0); } /* Copy address into sin_addr.s_addr. Use memcpy(3), not bcopy(3): */ memcpy(&addr.sin_addr.s_addr, &(he->h_addr_list[0]), he->h_length); int w = sendto(client_sock, msg, strlen(msg), 0, (struct sockaddr *)&addr, sizeof(struct sockaddr_in));
A stream socket is a "connected" socket. It acts virtually identical to a local socketpair(). One end must create a name bound socket then use the listen(2) system call and then accept(2) connection requests from a client. The client uses the connect(2) system call to make the connection.
client server 1) Make a socket 1) Make a socket 2) bind(2) socket 3) use listen(2) on socket 2) connect(2) 4) accept(2) connection, get a new descriptor representing the connection.
After the connection is established communication may proceed as if a socketpair().
socketpair()
#include <sys/types.h> #include <sys/socket.h> int listen(int sockfd, int backlog);
On success (return value of 0) makes the bound socket a socket that accepts connections. The backlog parameter represents the size of the queue of incoming connections, which are removed when accepted. Connections will be refused if the queue becomes full.
#include <sys/types.h> #include <sys/socket.h> int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
Accepts a connection, returning a new file descriptor representing that connection. If a sockaddr structure is passed to the call it will fill it in with the address of the client connection. addrlen will store the size of the socket address.
#include <sys/types.h> #include <sys/socket.h> int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
For stream or seqpacket sockets it connects the socket to a remote listening socket, address given in the addr structure. For datagram sockets it makes the address the default address for all subsequent writes and the only address that data-grams will be accepted by.
Returns 0 on success, -1 on error.
/* Create socket */ int sock = socket(AF_INET, SOCK_STREAM, 0); /* Setup the address */ struct sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_port = htons(1234); /* Resolve hostname to an IP address: */ struct hostent *he = gethostbyname("oldmanprogrammer.net"); if (he == NULL) { herror("gethostbyname"); exit(0); } /* Copy address into sin_addr.s_addr: */ memcpy(&addr.sin_addr.s_addr, he->h_addr_list[0], he->h_length); /* Finally connect to the remote end: if (connect(sock, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) < 0) { perror("connect"); exit(0); }
/* Create socket */ int sock = socket(AF_INET, SOCK_STREAM, 0); /* Setup our sockets address: */ struct sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_port = htons(1234); addr.sin_addr.s_addr = INADDR_ANY; /* Bind the address to our socket: */ if (bind(sock, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) < 0) { perror("bind"); exit(0); } /* Start listening for connections: This socket will only be used to accept * connections now. */ if (listen(sock, 128) < 0) { perror("listen"); exit(0); } while (1) { int client_len = sizeof(struct sockaddr_in); struct sockaddr_in client_addr; int client_sock = accept(sock, (struct sockaddr *)&client_addr, &client_len); if (client >= 0) handle_client(client_sock, client_addr); }