Topic : Socket Programming in Unix
Author : BracaMan
Page : 1 Next >>
Go to page :


BASIC C Socket Programming In Unix For Newbies




Written by: BracaMan
E-mail    : BracaMan@clix.pt
ICQ       : 41476410
URL   : http://www.BracaMan.net


For more tutorials: http://code.box.sk
    http://blacksun.box.sk


For comments, errors or just to say hello: <BracaMan@clix.pt>



CONTENTS



1. Introduction
2. Different types of Internet Sockets
3. Structures
4. Conversions
5. IP Addresses
6. Important Functions

   6.1. socket()
   6.2. bind()
   6.3. connect()
   6.4. listen()
   6.5. accept()
   6.6. send()
   6.7. recv()
   6.8. sendto()
   6.9. recvfrom()
   6.10. close()
   6.11. shutdown()
   6.12. gethostname()

7. Some words about DNS

8. A Stream Server Example

9. A Stream Client Example

10. Last Words

11. Copyright



1. INTRODUCTION



Are you trying to learn c socket programming? Or do you think that it's hard stuff?
Well, then you must read this basic tutorial to get basic ideas and concepts and to start
to work with sockets. Don't expect to be a "socket programming master" after reading this
tutorial. You'll only be that if you practice and read a lot.



2. DIFFERENT TYPES OF INTERNET SOCKETS



In the first place I must explain what a socket is. In a very simple way, a socket is a way
to talk to other computer. To be more precise, it's a way to talk to other computers using
standard Unix file descriptors. In Unix, every I/O actions are done by writing or reading
to a file descriptor. A file descriptor is just an integer associated with an open file and it
can be a network connection, a terminal, or something else.

About the different types of internet sockets, there are many types but I'll just describe two
of them - Stream Sockets (SOCK_STREAM) and Datagram Sockets (SOCK_DGRAM).

"And what are the differences between this two types?" you may ask. Here's the answer:

        Stream Sockets - they're error free; if you send through the stream socket three
items "A,B,C", they will arrive in the same order - "A,B,C" ;
they use TCP ("Transmission Control Protocol") - this protocol
assures the items' order.
      
      Datagram Sockets - they use UDP ("User Datagram Protocol"); they're connectionless
because you don't need to have an open connection as in Stream
Sockets - you build a packet with the destination information and
send it out.

A lot more could be explained here about this two kind of sockets, but I think this is enough
to get the basic concept of socket. Understanding what a socket is and this two types of
internet sockets is a good start, but you need to learn how to "work" with them. You'll learn
it in the next sections.


3. STRUCTURES



The purpose of this section is not to teach you structures but to tell you how are they
used in C socket programming. If you don't know what a structure is, my advice is to read
a C Tutorial and learn it. For the moment, let's just say that a structure is a data type
that is an aggregate, that is, it contains other data types, which are grouped together into
a single user-defined type.

Structures are used in socket programming to hold information about the address.


The first structure is struct sockaddr that holds socket information.


struct sockaddr{
unsigned short  sa_family;    /* address family */
char         sa_data[14];  /* 14 bytes of protocol address */
};



But, there's another structure (struct sockaddr_in) that help you to reference to the socket's
elements.



struct sockaddr_in {
short int      sin_family;  /* Address family */
unsigned short int   sin_port;   /* Port */
struct in_addr      sin_addr;   /* Internet Address */
unsigned char      sin_zero[8]; /* Same size as struct sockaddr */
};



Note: sin_zero is set to all zeros with memset() or bzero() (See examples bellow).


The next structure is not very used but it is defined as an union.

As you can see in both examples bellow (Stream Client and Server Client) , when I declare for
example "client" to be of type sockaddr_in then I do client.sin_addr = (...)

Here's the structure anyway:

struct in_addr {
unsigned long s_addr;
};


Finally, I think it's better talk about struct hostent. In the Stream Client Example, you can
see that I use this structure. This structure is used to get remote host information.

Here it is:


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 from name server.  */
#define h_addr  h_addr_list[0]  /* Address, for backward compatibility.  */
};


This structure is defined in header file netdb.h.


In the beginning, this structures will confuse you a lot, but after you start to write some
lines, and after seeing the examples, it will be easier for you understanding them. To see
how you can use them check the examples (section 8 and 9).



4. CONVERSIONS



There are two types of byte ordering: most significant byte and least significant byte.
This former is called "Network Byte Order" and some machines store their numbers internally
in Network Byte Order.

There are two types you can convert: short and long.
Imagine you want to convert a long from Host Byte Order to Network Byte Order. What would you
do? There's a function called htonl() that would convert it =) The following functions are
used to convert :

htons() -> "Host to Network Short"
htonl() -> "Host to Network Long"
ntohs() -> "Network to Host Short"
ntohl() -> "Network to Host Long"

You must be thinking why do you need this. Well, when you finish reading this document, it will
all seems easier =) All you need is to read and a lot of practice =)

An important thing, is that sin_addr and sin_port (from struct sockaddr_in) must be in Network
Byte Order (you'll see in the examples the functions described here to convert and you'll start
to understand it).

5. IP ADRESSES



In C, there are some functions that will help you manipulating IP addresses. We'll talk about
inet_addr() and inet_ntoa() functions.


inet_addr() converts an IP address into an unsigned long. An example:

(...)

dest.sin_addr.s_addr = inet_addr("195.65.36.12");

(...)

/*Remember that this is if you've a struct dest of type sockaddr_in*/



inet_ntoa() converts string IP addresses to long. An example:

(...)

char *IP;

ip=inet_ntoa(dest.sin_addr);

printf("Address is: %s\n",ip);

(...)


Remember that inet_addr() returns the address in Network Byte Order - so you don't need to
call htonl().


6. IMPORTANT FUNCTIONS



In this section I'll put the function' syntax, the header files you must include to call it,
and little comments. Besides the functions mentioned in this document, there are more, but
I decided to put only these ones here. Maybe I'll put them in a future version of this
document =) To see examples of these functions, you can check the stream client and stream
server source code (Sections 8 and 9)


  6.1. socket()
  


#include <sys/types.h>
#include <sys/socket.h>

int socket(int domain,int type,int protocol);


Let's see the arguments:

domain   -> you can set "AF_INET" (set AF_INET to use ARPA internet protocols)
    or "AF_UNIX" if you want to create sockets for inside comunication.
    Those two are the most used, but don't think that there are just
       those. There are more I just don't mention them.
type     -> here you put the kind of socket you want (Stream or Datagram)
      If you want Stream Socket the type must be SOCK_STREAM
      If you want Datagram Socket the type must be SOCK_DGRAM
protocol -> you can just set protocol to 0


socket() gives you a socket descriptor that you can use in later system calls or
it gives you -1 on error (this is usefull for error checking routines).


  6.2. bind()
  


#include <sys/types.h>
#include <sys/socket.h>

int bind(int fd, struct sockaddr *my_addr,int addrlen);



Let's see the arguments:

fd  -> is the socket file descriptor returned by socket() call
my_addr -> is a pointer to struct sockaddr
addrlen -> set it to sizeof(struct sockaddr)

bind() is used when you care about your local port (usually when you use listen() )
and its function is to associate a socket with a port (on your machine). It returns
-1 on error.

You can put your IP address and your port automatically:

server.sin_port = 0;         /* bind() will choose a random port*/
server.sin_addr.s_addr = INADDR_ANY;  /* puts server's IP automatically */


An important aspect about ports and bind() is that all ports

Page : 1 Next >>