" WinSock Programming "
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 in VC++5.0, 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 numb