Basic Socket Programming

Creating a Socket

Step Zero:  Pick Your Socket Type

There are two kinds of sockets, server side and client side.  A server socket waits for a connection and a client socket initiates a connection.  It's rather like a phone call, where one person sits by the phone waiting (server) and one person actually dials (client).  This how-to describes how to make a server socket.

Step Zero(b):  Overview

To make a server side socket, there are only a few steps.  You must

Step One:  Get Your Own Hostname

To get your own hostname is very easy.  You just call the gethostname() function with a buffer large enough to hold the hostname. 

char localhostname[255];
gethostname(localhostname,255);

Step Two:  Fill in the sockaddr_in struct

To make a socket, you need to fill in a sockaddr_in structure.  This structure will contain your internet address and will be used to build the socket.  You can get one by just declaring a variable of type sockaddr_in.  These are the parts that need to be filled in.  All values go in NETWORK BYTE ORDER!!!
struct sockaddr_in { 
    uint8_t        sin_len;       // length of the structure? (1 byte char)
    sa_family_t    sin_family;    // what type of address is this? (1 byte char)
    in_port_t      sin_port;      // what port number to use? (2 byte short)
    struct in_addr sin_addr;      // what address (IP number) to use? (4 byte int)
    char           sin_zero[8];   // Eight empty bytes for future expansion
}
struct in_addr {
    in_addr_t      s_addr;        // An IP number (4 byte int)
}
First you use gethostbyname() to translate the name into a 'hostent' which contains lots of information including the IP number and the family.  Second you copy the family and the IP number into the sockaddr.
 
// IN:  The char array 'localhostname' 
// OUT: The hostent struct hp  
// OUT: A partially filled in sockadd_in struct sa 
struct sockadd_in sa; 
struct hostent *hp;
hp = gethostbyname(localhostname);
sa.sin_family = hp->h_addrtype;
bcopy((char *)hp->h_addr, (char *)&sa.sin_addr, hp->h_length);
 

You also need to fill in the portnumber.  If it is a well known service (like telnet), you can search for it by name using getservbyname() or look in the file /etc/services.  If it is a service you made, you can pick your own portnumber.  Remember that ports less than 1024 are reserved for the superuser.  Also, remember that the portnumber needs to be in network byte order.  The htons() function converts a host short to a network short, and ntohs() does the opposite.  Since portnumbers are shorts, those are the functions you want.
 

// IN:  The port number 'port' 
// OUT: The sockaddr_in struct with the portnumber set 
sa.sin_port = htons(portnum);

Step Three:  Making a socket

Making a socket is very simple.  Just use the socket call, telling it the type of socket you want.
 
// IN:  A host entry 'hp' for the address family 
// Out: A socket 's' 
s = socket(hp->h_addrtype, SOCK_STREAM, 0);

Step Four:  Connecting the Socket to the Address

You must bind() the address of yourself to the socket you just made.  Then you set the backlog, which describes the number of pending connections that can exist simoltainiously.
 
// IN:      A socket 's'
// IN:      The backlog level 'BACKLOG'
// IN:      Our own address in the struct sockaddr_in 'sa'.
// OUT:   The socket is now associated with the address 'sa'. 
ret = bind(s, (struct sockaddr *)&sa, sizeof(sa));
listen(s, BACKLOG);
 

Step 4:  Waiting for a Connection

Now your program must wait for a connection from some client.  The system call accept() will do this.  However, accept() will wait forever for a connection.  If you want a wait with timeout, please see "select' or 'poll'.
// IN:      A socket 's'
// OUT:  A sockaddr with the client's IP number 'client'
// OUT:  A file descriptor to connected to the client
struct sockaddr client;
unsigned int client_len = sizeof(client);
int fd = accept(s, (struct sockaddr *)&client, &client_len)


Step 5:  Reading and Writing

You can read and write data using the file descriptors from step four.  What you want to read and write depends on your server and client.  However, this is how:
 
// READING 
// IN:     A length 'len' to read 
// IN:     A char array 'buf' which better be at least 'len' long 
// IN:     A file descriptor 
// OUT:  The length read 'ret' which is less than zero on error 
len = read(fd, buf, len);
/ WRITING 
// IN:     A length 'len' to write 
// IN:     A char array 'buf' which better be at least 'len' long 
// IN:     A file descriptor 
// OUT:  The length written 'ret' which is less than zero on error 
len = write(fd, buf, len);

Conclusion

Putting everything together, one can make an open server socket like this.  This code is missing all error checking!  You should add error checking for working code.
int MakeServerSocket(int *port) {
const int MAXNAMELEN = 255;
const int BACKLOG = 3;
char localhostname[MAXNAMELEN]; // local host name
int s;
int len;
struct sockaddr_in sa;
struct hostent *hp;
struct servent *sp;
int ret;

gethostname(localhostname,MAXNAMELEN);
hp = gethostbyname(localhostname);


sa.sin_port = htons(port);

bcopy((char *)hp->h_addr, (char *)&sa.sin_addr, hp->h_length);
sa.sin_family = hp->h_addrtype;

s = socket(hp->h_addrtype, SOCK_STREAM, 0);

ret = bind(s, (struct sockaddr *)&sa, sizeof(sa));

listen(s, BACKLOG);
cout << "Waiting for connection on port " << port << endl;
struct sockaddr_in client;
unsigned int client_len = sizeof(client);
int fd = accept(sock, (struct sockaddr *)&client, &client_len)
return s;
}

main() {
int sock = MakeServerSocket(40900);
write(sock, "Hi", 2);
}