Programming Windows TCP Sockets in C
Programming Windows TCP Sockets in C
Introduction
There really is not a lot of material on this subject (I believe) that explains the use of
Windows sockets sufficiently enough for a beginner to understand and begin to
program them. I still remember the hassle that I went through trying to find a
proper tutorial that didn't leave me hanging with many questions after I started
programming with them myself.
That was a long time ago now, and it was quite a challenge for me to program my
first application that could communicate with other computers over the Internet
even though my first introduction to sockets was through Visual Basic; a high-level
and very user-friendly programming language. Now that I have long since switched
to the more powerful C++, I rapidly found that the labor I had expended to code
sockets in VB was nothing compared to what awaited!
Thankfully, after many hours searching various web pages on the Internet, I was
able to collect all the bits and pieces, and finally compile my first telnet program in
C++. My goal is to collect all the necessary data in one place; right here, so the
reader doesn't have to recollect all the data over the Internet. Thus, I present this
tutorial in hopes that it alone will be sufficient information to begin programming.
Before we begin, you will need to include winsock.h and link libws2_32.a to your
project in order to use the API that are necessary for TCP/IP. If this is not possible,
use LoadLibrary() to load ws2_32.dll at runtime, or some similar method.
All the code in this article was written and tested using "Bloodshed Dev-C++
4.9.8.0"; but generally, it should work with any compiler with minimal modifications.
What the Heck are Threads, Ports, and Sockets?
Actually, we can use the word-picture presented to us by the name "socket" in a
similar fashion to illustrate what they are and how they work. In an actual
mechanical socket, you may recall that it is the female, or "receiving" end of a
connection. A "thread" is a symbolic name for a connection between your computer
and a remote computer, and a thread is connected to a socket.
In case I've lost you with all that proper terminology, you might think of a thread as
an actual, physical, sewing-type thread stretched from one computer to the other,
as the common analogy goes. In order for the threads to be attached to each
computer, however, there must be a receiving object that attaches to the threads,
and these are called sockets.
A socket can be opened on any "port"; which is simply a unique number to
distinguish it from other threads, because more than just one connection can be
made on the same computer. A few of these ports have been set aside to serve a
specific purpose. Beyond these ports, there are quite a large number of other ports
that can be used for anything and everything: over 6,000, actually. A few commonly
used ports are listed below with their corresponding services:
Port
Service
Ping
13
Time
15
Netstat
22
SSH
23
Telnet (default)
25
43
79
80
110
119
NNTP
513
There are many more ports used for specific purposes that are not shown here.
Typically though, if you wish to use a port that has no specific assigned service, any
port from 1,000 to 6,535 should be just fine. Of course, if instead you want to listen
in on messages sent to and from service ports, you can do that too.
Are you connected to the Internet now? Let's say you are, and you have Internet
Explorer or some other web page service running, as well as AOL or some other chat
program. On top of that (as if the connection wasn't slow enough already) you're
trying to send and receive email. What ports do you think are opened, sending and
receiving data?
Internet Explorer (etc.) sends and receives data via port 80
AOL and other instant messaging programs usually like to hang out in the higher
unassigned ports up in the thousands to be safe from interference. Each chat
program varies, as there is no specific "chat" service and multiple messaging
programs may run at the same time
When you're sending your email, you and the remote mail server are
communicating using port 25
And, when you receive email, your mail client (such as Microsoft Outlook) uses port
110 to retrieve your mail from the mail server
And onward extends the list.
It's not enough just to know what port number we're using, obviously; we need to
know what remote computer/server we're connecting to. Just like we find out the
home address of the people we visit before we get in the car, we have to know the
"IP address" of the host we are connecting to, if we are connecting and not just
listening (a chat program needs to be able to do both).
An IP address is an identification number that is assigned to each computer on the
network, and consists of four sets of digits separated by periods. You can view your
IP address by running ipconfig.exe at the MSDOS prompt.
For the examples shown throughout this tutorial, we will be using what is called the
"loop-back address" to test our chat program without being connected to the
Internet. This address is 127.0.0.1. Whenever you try to make a connection to this
IP, the computer loops the request back to you computer and attempts to locate a
server on the specified port. That way, you can have the server and client running
on the same computer. Once you decide to connect to other remote computers, and
you've worked the bugs out of your chat program, you will need to get the unique IP
address of each to communicate with them over the Internet.
Because we as humans are very capable of forgetting things, and because we
couldn't possibly hope to remember a bunch of numbers for every web site we visit,
some smart individuals came up the wonderful idea of "domain names". Now, we
have neat little names like www.yahoo.com and www.cia.gov that stand for IP
addresses that are much easier to remember than clunky sets of digits. When you
type one of these names in your browser window, the IP address for that domain
name is looked up via a "router", and once it is obtained (or the host is "resolved"),
the browser can contact the server residing at that address.
For example, let's say I call an operator because I can't remember my girlfriend's
phone number (fat chance). So, I just tell the operator what her name is (and a few
other details, but that's not important) and she happily gives me the digits. That's
kind of what happens when a request is made for an IP address of any domain
name.
We have two API that accomplish this task. It's a good idea to make sure and check
to see if whoever uses you program types a domain name instead of an IP address,
so your program can look up the correct IP address before continuing. Most people,
anyway, won't want to remember any IP addresses, so most likely you'll need to
translate domain names into IP addresses before you can establish a connection
which requires that the computer must be connected to the Internet. Then, once
you have the address, you're all set to connect.
think of the port number as the shorter number, and the IP as the longer number
(which is true an IP address consists of four sets of up to three digits separated by
periods, versus a single port number).
Firing Up Winsock
OK, now that we've finally covered the basics, hopefully you are starting to see light
at the end of the tunnel and we can move on. Don't worry if you don't understand
every aspect of the procedure, for many supplementary facts will be brought to light
as we progress.
The first step to programming with windows sockets (A.K.A "Winsock") is starting up
the Winsock API. There are two versions of Winsock; version one is the older, limited
version; and version 2 is the latest edition and is therefore the version we prefer to
specify.
Hide Copy Code
#define SCK_VERSION1
0x0101
#define SCK_VERSION2
0x0202
wVersion;
WORD
wHighVersion;
char
szDescription[WSADESCRIPTION_LEN+1];
char
szSystemStatus[WSASYS_STATUS_LEN+1];
unsigned short
iMaxSockets;
unsigned short
iMaxUdpDg;
char *
}
WSADATA;
lpVendorInfo;
#define SOCK_STREAM
#define SOCK_DGRAM
#define SOCK_RAW
#define AF_INET
2
3
#define IPPROTO_TCP
default address family. This parameter specifies how the computer addresses will be
interpreted.
There is more than just one type of socket; actually, there are many more. Three of
the most common ones include: Raw Sockets, Stream Sockets, and Datagram
Sockets. Stream sockets, however, are what we are using in this tutorial, since we
are dealing with TCP protocols, so we will specify SOCK_STREAM as the second
parameter to socket().
We're close, so close! We've got the "nitty gritty" stuff done and over with, so let's
move on the more exiting parts of Winsock programming.
Connecting to a Remote Host (Acting as the Client)
Let's try out what we've gone over with a simple program that can connect to a
remote computer. Doing this will help you to understand much better how
everything works, and helps to prevent information overload!
You'll need to fill out information about the remote host that you are connecting to,
and then pass a pointer to this structure to the magic function, connect(). This
structure and the API are listed below. Note that the sin_zero parameter is unneeded
and is thus left blank.
Hide Copy Code
struct sockaddr_in
{
short
sin_family;
u_short
sin_port;
struct
char
in_addr sin_addr;
sin_zero[8];
};
Copy Code
#include <winsock.h>
//Try connecting...
The first parameter of listen() must be the handle to a socket that you have
previously initialized. Of course, whatever port this socket is attached to is the port
that you will be listening on. You can then specify, with the next and final
parameter, how many remote computers can communicate with your server at the
same time. Generally, however, unless you want to exclude all but one or a few
connections, we just pass SOMAXCONN (SOcket MAX CONNection) as the final
parameter to listen(). If the socket is up and working fine, all should go well, and
when a connection request received, listen() will return. This is your clue to call
accept(), if you wish to establish a connection.
Hide Shrink
Copy Code
#include <windows.h>
#include <winsock.h>
SOCKET s;
WSADATA w;
if (error)
{
return false; //For some reason we couldn't start Winsock
}
addr.sin_family = AF_INET;
// Address family
if (s == INVALID_SOCKET)
{
return false; //Don't continue if we couldn't create a //socket!!
}
//made
listen(s, SOMAXCONN);
Copy Code
#define MY_MESSAGE_NOTIFICATION
case FD_CONNECT:
case FD_READ:
//Incoming data; get ready to receive
break;
case FD_CLOSE:
//Lost the connection
break;
}
}
break;
//And so forth
C:\Documents and Settings\Cam>netstat -an
Active Connections
Proto
Local Address
Foreign Address
State
TCP
0.0.0.0:135
0.0.0.0
LISTENING
TCP
0.0.0.0:445
0.0.0.0
LISTENING
TCP
0.0.0.0:5225
0.0.0.0
LISTENING
TCP
0.0.0.0:5226
0.0.0.0
LISTENING
TCP
0.0.0.0:8008
0.0.0.0
LISTENING
TCP
127.0.0.1:1025
0.0.0.0
LISTENING
TCP
127.0.0.1:1035
127.0.0.1:5226
ESTABLISHED
TCP
127.0.0.1:5226
127.0.0.1:1035
ESTABLISHED
TCP
127.0.0.1:8005
0.0.0.0
LISTENING
UDP
0.0.0.0:445
*:*
UDP
0.0.0.0:500
*:*
UDP
0.0.0.0:4500
*:*
UDP
127.0.0.1:123
*:*
UDP
127.0.0.1:1031
*:*
UDP
127.0.0.1:1032
*:*
UDP
127.0.0.1:1900
*:*
If your server is working correctly, you should see under "Local Address" something
like, "0.0.0.0:Port#," where Port# is the port that you are listening on, in a
LISTENING state. Incidentally, if you forget to use htons() to convert the port
number, you might find a new port has been opened, but it will be on a completely
different port than what you expected.
Don't worry if it takes you a couple of tries to get everything working right; it
happens to all of us. You'll get it with a couple of tries. (Of course, if you try without
avail for a couple weeks, burn this report and forget who wrote it!)
Sending and Receiving Data
Up to this section, all you've got for a server is a deaf mute! Which, not surprisingly,
does not do you a lot of good in the real world. So, let's take a look at how we can
communicate properly and effectively with any computer that decided to chat with
us. As always, a few API calls come to the rescue when we're stumped:
Hide Copy Code
//Send text data to a remote computer
int PASCAL send(SOCKET,const char*,int,int);
char buffer[80];
memset(buffer, 0, sizeof(buffer)); //Clear the buffer
//Allocate memory for the text in your Text Edit, retrieve the text,
//(see the source code for this) and then pass a pointer to it
These two API allow you to communicate with any one remote computer without
tipping your hand to everyone else that is connected. There is an extra parameter
that accepts a pointer to a sockaddr_in structure in these advanced functions, which
you can use to specify the IP address of any remote computer that you want to
communicate with exclusively. This is an important skill to know if you are building a
full-fledged chat program, or something similar, but beyond giving you the basic
idea of how these functions work, I'll let you figure them out on your own. (Don't
you hate it when authors say that? Usually it's because we don't have the slightest
clue ourselves but really, it shouldn't take much to implement them if you decide
that you need to.)
Some Final Notes
Well, by now you should have a decent understanding of Windows sockets or a
profound hatred of them but at any rate, if you're looking for a much better
explanation than I can give you here, please take a look at the example source code
provided with this article. Practice will do much more for you than reading any
article.
Additionally, I have found that if you try to copy and paste code, or just compiling
someone else's code you found on the Internet, you won't come close to the level of
understanding you will gain if you type in all the examples by hand yourself. A big
pain, I know! But if you take the time to do it, you'll save yourself a lot of trouble in
the long run.
Have fun, and let me know what you think of this article by posting feedback.
This article (not including the accompanying source code) is copyrighted 2006 by
the author, and cannot be modified, sold, and redistributed for personal gain
without prior explicit permission from him. It is provided free of charge for the
benefit of the public. You are allowed, however, to make and distribute as many
copies of it as you like, provided that you do not modify the original content in any
way. Thanks!
<a href="http://pubads.g.doubleclick.net/gampad/jump?
iu=/6839/lqm.codeproject.site/General-Programming/InternetNetwork/Beginners&sz=300x250&c=420640"><img
src="http://pubads.g.doubleclick.net/gampad/ad?
iu=/6839/lqm.codeproject.site/General-Programming/InternetNetwork/Beginners&sz=300x250&c=420640" width="300px" height="250px"
target="_blank"/></a>
License
This article, along with any associated source code and files, is licensed under The
Creative Commons Attribution-ShareAlike 2.5 License