Penguin

InNeedOfRefactor

This is to describe how to write networking programs in C using the BSD Socket Layer API. This mostly applies to almost all other languages with only minor modifications. This is an updated version of the page which is designed to be non-AddressFamily specific, for the old version see NetworkProgrammingOld. SocketAddressing may also be useful.

General structure for a server setup

The various steps of setting up a server are:

  1. Creating a socket of the correct type, with socket(2)
  2. bind(2) the socket to a port (and optionally an interface)
  3. listen(2) on that port
  4. accept(2) client connections

getaddrinfo(3) will sort out the correct parameters for socket(2) and bind(2), making things fairly simple. An example below:

  • First find our what to bind to.
  1. include <sys/socket.h>
  2. include <sys/types.h>
  3. include <netdb.h>

int bind_service(char *service,int socktype) {

struct addrinfo hints; struct addrinfo *result; struct addrinfo *result_iter; int serverfd;

hints.ai_flags=AI_PASSIVE; hints.ai_family=PF_UNSPEC; /* We don't care if it's PF_INET, or PF_INET6 / hints.ai_socktype=SOCK_STREAM / 0 for any type, SOCK_STREAM for streams, SOCK_DGRAM for datagrams / hints.ai_protocol=0; / 0 for any protocol, use getprotobyname(3) to find a protocol / hints.ai_addrlen=0; hints.ai_addr=NULL; hints.ai_canonname=NULL; / Unused */ hints.ai_next=NULL;

ret=getaddrinfo(NULL,service,&hints,&result); if (ret!=0) {

fprintf(stderr,"getaddrinfo failed: %s",gai_strerror(ret)); return -1;

}

for(result_iter = result;result_iter;result_iter=result_iter->next) {

serverfd = socket(result_iter->ai_family,result_iter->ai_socktype,result_iter->ai_protocol); if (serverfd<0) {

perror("socket"); continue;

} if (bind(serverfd,result_iter->address,result_iter->addrlen)<0) {

perror("bind"); continue;

} break;

}

if (!result_iter) {

fprintf(stderr,"Unable to bind to service \"%s\"\n",service); freeaddrinfo(result); return -1;

}

freeaddrinfo(result); return serverfd;

}

void do_client(int clientfd) {

char *message = "Hello World\n"; write(clientfd,message); close(clientfd);

}

int main(int argc,char **argv) {

int serverfd;

serverfd = bind_service("hello",SOCK_STREAM);

if (serverfd<0) {

return 1;

}

if (listen(serverfd,8)<0) {

perror("listen"); return 1;

}

for (;;) {

int clientfd;

clientfd = accept(serverfd);

if (clientfd<0) {

perror("accept"); /* Note that accept tends to fail reasonably often, so don't abort the server here */

}

if (fork()==0) {

/* Client Thread */ close(serverfd); do_client(clientfd); exit(0);

} else {

/* Server Thread */ close(clientfd);

}

}

close(serverfd);

}

A General Client Implementation

A simple client implementation:

  1. include <sys/types.h>
  2. include <sys/socket.h>
  3. include <netdb.h>

int create_client_connection(char *hostname,char *service) {

struct addrinfo hints; struct addrinfo result; struct addrinfo result_iter; int ret; int clientfd;

hints.ai_flags=0; hints.ai_family=PF_UNSPEC; hints.ai_socktype=SOCK_STREAM; hints.ai_protocol=0; hints.ai_addrlen=0; hints.ai_address=NULL; hints.ai_canonname=NULL;

ret=getaddrinfo(hostname,service,&hints,&result); if (ret!=0) {

fprintf("getaddrinfo failed: %s",gai_strerror(ret)); return -1;

}

for(result_iter = result; result ; result_iter=result_iter->next) {

clientfd=socket(result_iter->ai_family,result_iter->ai_socktype,result_iter->ai_protocol); if (clientfd<0) {

perror("socket"); continue;

} if (bind(clientfd,result_iter->ai_address,result_iter->ai_addrlen)<0) {

perror("bind"); close(clientfd); continue;

} break;

}

if (!result_iter) {

return -1;

}

return clientfd;

}

int main(int argc,char **argv) {

int clientfd; char buffer[65535?; int length;

clientfd=create_client_connection("localhost","hello");

if (clientfd<0) {

return 1;

}

len=read(clientfd,buffer,sizeof(buffer));

if (len<0) {

perror("read"); close(clientfd); return 1;

}

/* Write it to stdout (fd1) */ write(1,buffer,len);

close(clientfd);

}