You are on page 1of 14

BASIC C Soc et 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.s http://blac sun.box.s

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

CONTENTS =======================================

6.1. soc et() 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 soc et programming? Or do you thin that it's hard stu ff? Well, then you must read this basic tutorial to get basic ideas and concepts and to start to wor with soc ets. Don't expect to be a "soc et programming master" after rea

1. 2. 3. 4. 5. 6.

Introduction Different types of Internet Soc ets Structures Conversions IP Addresses Important Functions

ding 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 soc et is. In a very simple way, a soc et is a way to tal to other computer. To be more precise, it's a way to tal to other compu ters using standard Unix file descriptors. In Unix, every I/O actions are done by writing o r reading to a file descriptor. A file descriptor is just an integer associated with an op en file and it can be a networ connection, a terminal, or something else. About the different types of internet soc ets, there are many types but I'll jus t describe two of them - Stream Soc ets (SOCK_STREAM) and Datagram Soc ets (SOCK_DGRAM). "And what are the differences between this two types?" you may as . Here's the a nswer: et three B,C" ; they use TCP ("Transmission Control Protocol") - this p rotocol assures the items' order. Datagram Soc ets - they use UDP ("User Datagram Protocol"); they're connec tionless because you don't need to have an open connection as in Stream Soc ets - you build a pac et with the destination infor mation and send it out. A lot more could be explained here about this two ind of soc ets, but I thin t his is enough to get the basic concept of soc et. Understanding what a soc et is and this two types of internet soc ets is a good start, but you need to learn how to "wor " 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 a re they used in C soc et programming. If you don't now what a structure is, my advice i s 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 t

items "A,B,C", they will arrive in the same order - "A,

Stream Soc ets - they're error free; if you send through the stream soc

ogether into a single user-defined type. Structures are used in soc et programming to hold information about the address. The first structure is struct soc addr that holds soc et information.

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

But, there's another structure (struct soc addr_in) that help you to reference t o the soc et's elements.

r */ };

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 soc addr_in then I do client.sin_addr = (...) Here's the structure anyway: struct in_addr { unsigned long s_addr; };

Finally, I thin it's better tal about struct hostent. In the Stream Client Exa mple, you can see that I use this structure. This structure is used to get remote host informa tion. Here it is:

struct soc addr_in { short int unsigned short int struct in_addr unsigned char

sin_family; sin_port; sin_addr; sin_zero[8];

/* /* /* /*

Address family */ Port */ Internet Address */ Same size as struct soc add

struct hostent { char *h_name; char **h_aliases; int h_addrtype; int h_length; char **h_addr_list; */ */ };

/* /* /* /* /*

Official name of host. */ Alias list. */ Host address type. */ Length of address. */ List of addresses from name server.

#define h_addr h_addr_list[0] /* Address, for bac ward 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 th em. To see how you can use them chec the examples (section 8 and 9).

4. CONVERSIONS ======================================= There are two types of byte ordering: most significant byte and least significan t byte. This former is called "Networ Byte Order" and some machines store their numbers internally in Networ Byte Order. There are two types you can convert: short and long. Imagine you want to convert a long from Host Byte Order to Networ Byte Order. W hat would you do? There's a function called htonl() that would convert it =) The following fun ctions are used to convert :

You must be thin ing why do you need this. Well, when you finish reading this do cument, 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 soc addr_in) must be in Networ Byte Order (you'll see in the examples the functions described here to convert a nd you'll start to understand it). 5. IP ADRESSES ======================================= In C, there are some functions that will help you manipulating IP addresses. We' ll tal about

htons() htonl() ntohs() ntohl()

-> -> -> ->

"Host to "Host to "Networ "Networ

Networ Networ to Host to Host

Short" Long" Short" Long"

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 soc addr_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 Networ 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 o f this document =) To see examples of these functions, you can chec the stream client and stream server source code (Sections 8 and 9) 6.1. soc et() ============= #include <sys/types.h> #include <sys/soc et.h> int soc et(int domain,int type,int protocol); Let's see the arguments: domain net protocols) or "AF_UNIX" if you want to create soc ets for insid -> you can set "AF_INET" (set AF_INET to use ARPA inter

e comunication. ere are just Datagram) REAM DGRAM those. There are more I just don't mention them. -> here you put the ind of soc et you want (Stream or If you want Stream Soc et the type must be SOCK_ST If you want Datagram Soc et the type must be SOCK_ protocol -> you can just set protocol to 0 soc et() gives you a soc et descriptor that you can use in later system calls or it gives you -1 on error (this is usefull for error chec ing routines). 6.2. bind() =========== #include <sys/types.h> #include <sys/soc et.h> int bind(int fd, struct soc addr *my_addr,int addrlen); Let's see the arguments: fd -> is the soc et file descriptor returned by soc et() call my_addr -> is a pointer to struct soc addr addrlen -> set it to sizeof(struct soc addr) bind() is used when you care about your local port (usually when you use listen() ) and its function is to associate a soc et 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; ndom port*/ server.sin_addr.s_addr = INADDR_ANY; /* puts server's IP automa tically */ An important aspect about ports and bind() is that all ports bellow 1024 are reserved. You can set a port above 1024 and bellow 65535 (unless the ones being u sed by other programs). 6.3. connect() ============== #include <sys/types.h> #include <sys/soc et.h> /* bind() will choose a ra

type

Those two are the most used, but don't thin

that th

int connect(int fd, struct soc addr *serv_addr, int addrlen); Let's see the arguments: fd -> is the soc et file descriptor returned by soc et() call serv_addr -> is a pointer to struct soc addr that contains desti nation IP addrlen address and port -> set it to sizeof(struct soc addr)

connect() is used to connect to an IP address on a defined port. It retu rns -1 on error. 6.4. listen() ============= #include <sys/types.h> #include <sys/soc et.h> int listen(int fd,int bac log); Let's see the arguments: fd -> is the soc et file descriptor returned by soc et() call bac log -> is the number of allowed connections listen() is used if you're waiting for incoming connections, this is, if you want someone to connect to your machine. Before calling listen(), you must ca ll bind() or you'll be listening on a random port =) After calling listen() you mu st call accept() in order to accept incoming connection. Resuming, the sequence of system calls is:

t() */ As all functions above described, listen() returns -1 on error. 6.5. accept() ============= #include <sys/soc et.h> int accept(int fd, void *addr, int *addrlen); Let's see the arguments: fd -> is the soc et file descriptor returned by listen() call addr -> is a pointer to struct soc addr_in where you can dete rmine which host is calling you from which port

1. 2. 3. 4.

soc et() bind() listen() accept() /* In the next section I'll explain how to use accep

addrlen -> set it to sizeof(struct soc addr_in) before its addre ss is passed to accept() When someone is trying to connect to your computer, you must use accept( ) to get the connection. It's very simple to understand: you just get a connection if you accept =) Next, I'll give you a little example of accept() use because it's a litt le different from other functions. (...) sin_size=sizeof(struct soc addr_in); if ((fd2 = accept(fd,(struct soc addr *)&client,&sin_size))==-1){ /* c alls accept() */ printf("accept() error\n"); exit(-1); } (...) From now on, fd2 will be used for add send() and recv() calls. 6.6. send() =========== int send(int fd,const void *msg,int len,int flags); Let's see the arguments:

This function is used to send data over stream soc ets or CONNECTED data gram soc ets. If you want to send data over UNCONNECTED datagram soc ets you must use sendto(). send() returns the number of bytes sent out and it will return -1 on err or. 6.7. recv() =========== int recv(int fd, void *buf, int len, unsigned int flags); Let's see the arguments:

fd -> msg len flags

is the soc et descriptor where you want to send data to -> is a pointer to the data you want to send -> is the length of the data you want to send (in bytes) -> set it to 0

As I said above about send(), this function is used to send data over st ream soc ets or CONNECTED datagram soc ets. If you want to send data over UNCONNECTED da tagram soc ets you must use recvfrom(). recv() returns the number of bytes read into the buffer and it'll return -1 on error. 6.8. sendto() ============= int sendto(int fd,const void *msg, int len, unsigned int flags, const struct soc addr *to, int tolen); Let's see the arguments: fd -> msg len flags to tolen the -> -> -> -> -> same as send() the same as send() the same as send() the same as send() is a pointer to struct soc addr set it to sizeof(struct soc addr)

As you can see, sendto() is just li e send(). It has only two more argum ents : "to" and "tolen" =) sendto() is used for UNCONNECTED datagram soc ets and it returns the num ber of bytes sent out and it will return -1 on error. 6.9. recvfrom() =============== int recvfrom(int fd,void *buf, int len, unsigned int flags struct soc addr *from, int *fromlen); Let's see the arguments: fd buf len flags from fromlen d to sizeof(struct soc addr) recvfrom() returns the number of bytes received and it'll return -1 on e rror. -> -> -> -> -> -> the same as recv() the same as recv() the same as recv() the same as recv() is a pointer to struct soc addr is a pointer to a local int that should be initialise

fd -> is the soc buf -> is the len -> is the flags -> set it

et descriptor to read from buffer to read the information into maximum length of the buffer to 0

6.10. close() ============= close(fd); close() is used to close the connection on your soc et descriptor. If yo u call close(), it won't be no more writes or reads and if someone tries to read/write w ill receive an error. 6.11. shutdown() ================ int shutdown(int fd, int how); Let's see the arguments:

When how is set to 2, it's the same thing as close(). shutdown() returns 0 on success and -1 on error. 6.12. gethostname() =================== #include <unistd.h> int gethostname(char *hostname, size_t size); Let's see the arguments: hostname -> is a pointer to an array that contains hostname size -> length of the hostname array (in bytes) gethostname() is used to get the name of the local machine.

7. SOME WORDS ABOUT DNS ======================================= I created this section, because I thin you should now what DNS is. DNS stands for "Domain Name Service" and basically, it's used to get IP addresses. For example, I need to now the IP address of queima.ptlin .net and through DNS I'll get 212.13.37.13 . This is important, because functions we saw above (li e bind() and connect()) wo r with IP

fd how

-> is the soc et file descriptor you want to shutdown -> you put one of those numbers: 0 -> receives disallowed 1 -> sends disallowed 2 -> sends and receives disallowed

addresses. To see you how you can get queima.ptlin .net IP address on c, I made a little ex ample: /* <---- SOURCE CODE STARTS HERE ----> */ #include #include #include #include #include <stdio.h> <netdb.h> /* This is the header file needed for gethostbyname() */ <sys/types.h> <sys/soc et.h> <netinet/in.h>

int main(int argc, char *argv[]) { struct hostent *he; if (argc!=2){ printf("Usage: %s <hostname>\n",argv[0]); exit(-1); } if ((he=gethostbyname(argv[1]))==NULL){ printf("gethostbyname() error\n"); exit(-1); } printf("Hostname : %s\n",he->h_name); /* prints the hostname */ printf("IP Address: %s\n",inet_ntoa(*((struct in_addr *)he->h_addr))); /* prin ts IP address */ } /* <---- SOURCE CODE ENDS HERE ----> */

8. A STREAM SERVER EXAMPLE ======================================= In this section, I'll show you a nice example of a stream server. The source cod e is all commented so that you ain't no possible doubts =) Let's start: /* <---- SOURCE CODE STARTS HERE ----> */ #include #include #include #include <stdio.h> <sys/types.h> <sys/soc et.h> <netinet/in.h> /* These are the usual header files */

#define PORT 3550 #define BACKLOG 2 main() {

/* Port that will be opened */ /* Number of allowed connections */

int fd, fd2; /* file descriptors */ struct soc addr_in server; /* server's address information */ struct soc addr_in client; /* client's address information */ int sin_size; if ((fd=soc et(AF_INET, SOCK_STREAM, 0)) == -1 ){ /* calls soc et() */ printf("soc et() error\n"); exit(-1); } server.sin_family = AF_INET; server.sin_port = htons(PORT); /* Remember htons() from "Conversions" sectio n? =) */ server.sin_addr.s_addr = INADDR_ANY; /* INADDR_ANY puts your IP address autom atically */ bzero(&(server.sin_zero),8); /* zero the rest of the structure */ if(bind(fd,(struct soc addr*)&server,sizeof(struct soc addr))==-1){ /* calls b ind() */ printf("bind() error\n"); exit(-1); } if(listen(fd,BACKLOG) == -1){ /* calls listen() */ printf("listen() error\n"); exit(-1); } while(1){ sin_size=sizeof(struct soc addr_in); if ((fd2 = accept(fd,(struct soc addr *)&client,&sin_size))==-1){ /* calls acc ept() */ printf("accept() error\n"); exit(-1); } printf("You got a connection from %s\n",inet_ntoa(client.sin_addr) ); /* print s client's IP */ send(fd2,"Welcome to my server.\n",22,0); /* send to the client welcome messag e */ close(fd2); /* close fd2 */ } } /* <---- SOURCE CODE ENDS HERE ----> */

9. A STREAM CLIENT EXAMPLE ======================================= /* <---- SOURCE CODE STARTS HERE ----> */ #include <stdio.h>

#define PORT 3550 #define MAXDATASIZE 100

int main(int argc, char *argv[]) { int fd, numbytes; /* files descriptors */ char buf[MAXDATASIZE]; /* buf will store received text */ struct hostent *he; /* structure that will get information about remot e host */ struct soc addr_in server; /* server's address information */ if (argc !=2) { /* this is used because our program will need one argument (IP) */ printf("Usage: %s <IP Address>\n",argv[0]); exit(-1); } if ((he=gethostbyname(argv[1]))==NULL){ printf("gethostbyname() error\n"); exit(-1); } /* calls gethostbyname() */

if ((fd=soc et(AF_INET, SOCK_STREAM, 0))==-1){ /* calls soc et() */ printf("soc et() error\n"); exit(-1); } server.sin_family = AF_INET; server.sin_port = htons(PORT); /* htons() is needed again */ server.sin_addr = *((struct in_addr *)he->h_addr); /*he->h_addr passes "*he"' s info to "h_addr" */ bzero(&(server.sin_zero),8); if(connect(fd, (struct soc addr *)&server,sizeof(struct soc addr))==-1){ /* ca lls connect() */ printf("connect() error\n"); exit(-1); } if ((numbytes=recv(fd,buf,MAXDATASIZE,0)) == -1){ /* calls recv() */ printf("recv() error\n"); exit(-1); } buf[numbytes]='\0'; printf("Server Message: %s\n",buf); /* it prints server's welcome message =) */ close(fd); } /* <---- SOURCE CODE ENDS HERE ----> */ /* close fd =) */

#include #include #include #include

<sys/types.h> <sys/soc et.h> <netinet/in.h> <netdb.h>

/* netbd.h is needed for struct hostent =) */ /* Open Port on Remote Host */ /* Max number of bytes of data */

10. LAST WORDS ======================================= As I'm just a simple human, it's almost certain that there are some errors on th is document. When I say errors I mean English errors (because my language is not the English) but also technical errors. Please email me if you detect any error =) But you must understand that this is the first version of this document, so , it 's natural not to be very complete (as matter of fact I thin it is ) and it's also very natura l to have stupid errors. However, I can be sure that source code presented in this documen t wor s fine. If you need help concerning this subject you can email me at <BracaMan@clix.pt> SPECIAL THANKS TO: Ghost_Rider (my good old mate), Raven (for letting me write t his tutorial) and all my friends =)

11. COPYRIGHT ======================================= All copyrights are reserved. You can distribute this tutorial freely, as long yo u don't change any name or URL. You can't change a line or two, or add another lines, and then claim that this tutorial is yours. If you want to change something, please email me at <BracaMan @clix.pt>.

You might also like