Synfire's Guide To C Programming

12. Sockets

Well, now you've got what it takes to write some fairly kewl programs that work with files on your computer, and can ease many common tasks. BUT WAIT! What about working across networks, and creating some kewl client server programs? Well, if you've ever used a chat program or web browser you might have thought what it would be like to create your own. That is what this section is about. This is called 'Socket Programming' and I think this is the best part of programming. ( Of course this is comming from a hacker ;) )

Okay, lets jump into this. First thing you should do is login as root and go to the '/usr/include/sys' directory. Then open the 'socket.h' file in your favorite text editor. Now scroll down to where you see...
struct osockaddr
{
   unsigned short int sa_family;
   unsigned char sa_data[14];
};
Now this is kinda cryptic, so lets create another struct. Just below the osockaddr struct type this:
struct SockAddr
{
  short int Family;
  unsigned short int Port;
  struct in_addr Address;
  unsigned char Zero[8];
};

Now that you have both of these structs socket programming is fairly simple. Now there are many tutorials on socket programming so I'm just going over one aspect. Here we will write a Simple TCP Stream client and server. This is enough to get the general idea, and write fairly good programs, TCP Stream programs are the most created on the net because it is the most reliable method of data transfer.

tcpclient.c
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
/* Yes there are allot of header files but you will need them all! */

#define PORT 6666 /* This will be the port that your client will
             connect to on the remote machine. If this
             client wants to connect to Telnet then you
             would use port 23, FTP port 21, and the list
             goes on, make sure if you write a server then
             you make the ports in the 4 digit range so
             not to interfer with other network programs. */

#define MAXDATASIZE 100 /* This is the maximum size of information
               that can be recieved at a time from the
               server. */

int main(int argc, char *argv[])
{
    int sock_fd, numbytes;
    /* Creates a socket file descriptor for data exchange,
       numbytes holds the number of bytes recieved from
       the server. */

    char buffer[MAXDATASIZE];
    /* This holds all the information sent from the server. */

    struct hostent *he;
    /* This structure is used to get the IP address from a hostname. */

    struct SockAdder Their;
    /* This is the structure you created to hold information
       about the stream you will be using. */

    if(argc != 2)
    {
        /* This checks to make sure that the right
           amount of arguements were passed on the
           command line. */

        fprintf(stderr, "usage: client hostname\n";
        exit (1);
    }

    if((he=gethostbyname(argv[1])) == NULL)
    {
        herror("gethostbyname");
        exit (1);
    }
    

    /* socket() -
       This is always the first part of a connection.
       You will notice that the connections will be built by if
       statements. The above if statement should be used if you
       think the user might type in a domain name like...
       "www.yahoo.com" instead of an IP address. Then to create
       an internet connection using the TCP protocol type this
       next if statement. */

    if((sock_fd=socket(AF_INET,SOCK_STREAM,0)) == -1)
    {
        perror("socket");
        exit (1);
    }

    /*
    This is the information that will be used to make a connection.
    just leave it like this everytime, I do it this way to make it
    more readable. */

    Their.Family = AF_INET;
    /* This is the socket address family, This text only covers
    AF_INET connections so if you want more info type 'man socket'
    at your linux prompt. */

    Their.Port = htons(PORT);
    /* This is the port your client will be connecting to. For the
       most part this will always be the same. Just always remember to
       define your port at the beginning of your program. Or if you want
       a user specified port you could use...

       unsigned int PORT = argv[3];

       just after main(). */

    Their.Address = *((struct in_addr *)he->h_addr);
    /* This is the address of the person your connecting to
       for the most part this will stay the same too. */

    bzero(&(Their.Zero), 8);
    /* Don't ask just add it here everytime! */

 if(connect(sock_fd, (struct sockaddr *)&Their, sizeof(struct sockaddr)) == -1)
   {
    /* This creates a full 'handshake' connection to
       the remote host. ALL CLIENT PROGRAMS WILL HAVE THIS! */

        perror("connect");
        exit (1);
    }

    if((numbytes=recv(sock_fd,buffer,MAXDATASIZE,0)) == -1)
    {
        /* I will explain this a bit. recv() gets information
           from the server through your file descriptor(sock_fd)
           and places as much as it can, determined by MAXDATASIZE,
           into 'buffer'. Then the number of bytes placed into
           'buffer' is placed into 'numbytes'. */

        perror("recv");
        exit (1);
    }

    buffer[numbytes] = '\0';
    /* A lacking carrage return is placed at the end of the buffer. */

    printf("> %s", buffer);
    /* prints all information in the buffer to the screen. */

    close(sock_fd);
    /* closes the connection */

    return (0);
}
Now I have commented this enought that you should be able to figure it out on your own. I do recomend reading a guide on Networking to better understand the lingo, but other than that you should do fine.

Here we go, the client program is VERY easy but a bit more goes into server programs. Servers have to bind to a port, recieve connection, fork off a sub-proccess and handle sending and recieving data. I know it sounds like alot but I'm sure you'll have no problems following the comments. In this section I will OverComment for you! ;)

tcpserver.c
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/wait.h>
/* Yes, even more includes but once again you'll need them all! */

#define PORT 6666
/* This is the port the server will be listening on. */

#define BACKLOG 10
/* This is how many connections your server will accept at once. */


int main()
{
    int sock_fd, new_fd;
    /* Two file discriptors are created. Servers have to have
       both. One will be used for when your server forks to the
       client. */

    struct SockAddr My;
    struct SockAddr Their;
    /* Creates a local socket and a remote socket. The remote
       socket holds the person connectings information and the
           local one holds your servers connection information. */

    int Size;
    /* This will hold the size of SockAddr for use with accept(). */

    if ((sock_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
    {
        /* creates your local socket, just like in the client */

        perror("socket");
        exit (1);
    }

    My.Family = AF_INET;
    My.Port = htons(PORT);
    /* The above two set up your SA_family and your local port
       just as in the client. */

    My.Address.s_addr = INADDR_ANY;
    /* This sets the address to your current IP. For servers
       this is what you always want. */
    
    bzero(&(My.Zero), 8);
    /* Once again, don't ask just do it. ;) */

    if (bind(sock_fd, (struct sockaddr *)&My, sizeof(struct sockaddr)) == -1)
    {
        /* This binds your server to your local port.
           This will keep other programs from trying 
           to use the same port. */

        perror("bind");
        exit (1);
    }

    if (listen(sock_fd, BACKLOG) == -1)
    {
        /* This statement tells your computer to sit and
           wait and listen for up to 10, the amount of 
           BACKLOG, connections. */

        perror("listen");
        exit(1);
    }

    while (1) 
    {
        /* while(1) is called a forever loop, meaning that
           it will just loop over constantly until return()
           is called with an int. */

        Size = sizeof(struct SockAddr);
        /* Stores the size of struct SockAddr to Size for
           use with accept. */

    if ((new_fd = accept(sock_fd, (struct sockaddr *)&Their, &Size)) -1)
    {
    /* The above is called when a connection 
       is made, it uses your other file descriptor
       'new_fd' to recieve their socket information. */

        perror("accept");
        printf("> %s has connected!\n", inet_ntoa(Their.Address));
        /* Prints the IP address of the connecting person on the 
           screen. Thats about all you get on the server side.
           This is good if you want to get someones IP for some
           reason ;) just create this client and have the connect
           to you on the 'PORT' port and it will display their 
           IP on screen. */


         if (!fork())
         {
             /* Don't worry about that just use it.
                I'm the kinda person that if you always
                have to do it, then I'm not gonna take
                time to explain it. Just do it. */

             if(send(new_fd, "Hello Client!\n", 14, 0) == -1) 
            {
                /* sends the string Hello Client! to
                   the client. For more advance servers
                   you would put a function there and 
                   have all the operations placed in the
                   function. */

                perror("send");
            }
            close(new_fd);
            /* This closes the file descriptor. */
            exit(0);
        }
        close(new_fd);

        while(waitpid(-1,NULL,WNOHANG) > 0);
        /* Once again just do it. */
    }
}
Okay that is enough for this tutorial. If you really want to get serious about C socket programming for linux go to...

http://www.programmersheaven.com/
or
http://www.google.com/linux?q=Socket+Programming&hl=en

I forgot to tell you. Most of the stuff in this tutorial will work for you Windows Programmers, except for the Socket Programming. Windows have their own Socket API and I suggest looking for information at...

http://www.google.com/microsoft?q=Socket+Programming&hl=en

for more information. Well I hate to say it, but this is all I'm doing on C. I know it's not the best tutorial in the world, but it does get you started. After all I'm more or less a C++ coder but there is the occasional job the C is need. I by no means think C++ is better than C, it's just my preferred language, I mean ASM is much better than C or C++ but there is no way in HELL I would write all my programs in it! So for now I'm out, LaTeRz!

< < < Lesson 11: Pointers



Want some naughty smileys for your Yahoo messenger? Then look HERE.