Winsock Fundementals

By: Mat Duafala

Abstract: This article covers the basic requirements to create a socket connection and send data across it.

What are the basics of writing a WinSock application?

The basic steps required to write a WinSock application are analagous to those required to write a program that manipulates the contents of a file. Once you see how WinSock programming parralells File/IO, writing WinSock applications should become fairly easy. Note that this is a general overview. For a client application you only need to call the socket, and connect functions to establish a socket connection. For a server on the other hand, you have to call socket, bind, listen, and accept to establish a connection. Once the connection is established, you can then call send and recv for either. Also of note is that the server must call closesocket twice, once to close the connection, and once to close the listening socket.

The basic steps are as follows:

1. Open the Socket with the socket() function call.

2. Name the socket using the bind() function.

3. Associate that socket. (This is a little more complicated than calling a function, more about that later...)

4. Send and recieve the data between the sockets using the send() and recv() functions.

5. Close the socket using the closesocket() function.

Now that I have given the basic steps, I will go into more detail about each one in turn. socket()

The socket function takes three arguments, the first is af, or the protocol suite; the second is type, and the third is protocol. The af parameter has three possible values, PF_INET, AF_IPX, and AF_APPLETALK. The PF_INET value is the one that you will want to use for TCP/IP communication. The AF_IPX would be used for communication to Novell machines, and the AF_APPLETALK is used for connecting to Macintosh machines.

The second parameter is the type parameter. This argument determines (implicitly) the protocol within the address family that you will be using. Possible values are SOCK_DGRAM, SOCK_STREAM, or SOCK_RAW. If you are using the SOCK_DGRAM, it will always indicate that you are using a UDP connection; whereas, if you are using the SOCK_STREAM argument, then that would indicate that you are using a TCP/IP connection. If such cases where the protocol is determined by the type argument, the third parameter (protocol) is ignored. In those cases, you should just pass in 0 to be on the safe side.

You may be wondering what the SOCK_STREAM argument is for. The winsock specification defines this value, however, implimentations aren't required to use it. Therefor its use is discouraged for compatibility reasons. Just in case you were wondering what it would be use for, the SOCK_RAW type would give you complete access to the stream, including things like TCP/IP headers.

Once you have called the socket() function, it will return the socket descriptor to you. If the call failed for some reason then it will return INVALID_SOCKET. From here on out we will only concern ourselves with TCP/IP applications.

After you have created the socket, you need to associate that with a name using the bind() function. The bind() function takes three arguments, the first of which is the socket descriptor that was returned from our previous call to the socket function. The second value is a sockaddr_in structure. The sockaddr_in structure has four fields. The first is the protocol family (in this case it is PF_INET), the second value is the port number that we want to access. The fourth field is the IP address of the machine that we want to connect to. The fourth field is unused, so don't worry about it. The third value that it takes is the length of the aformentioned sockaddr_in structure using the sizeof() function.

Once you have named the socket structure you need to associate that socket with another socket on the remote machine. This is accomplished with a TCP/IP connection by calling the listen() function. The listen() function only takes two parameters, the first is the socket that was returned by the first function call, and the second is the backlog value. A complete description of the backlog parameter is beyond the scope of the document, but suffice it to say, setting this value to 3 should be fine for most applications.

Now that we have established a connection between our socket and the remote machine, we can start sending data between them. To accomplish this, we use the send() function. For this function call you should pass in our socket, the buffer that we want to send (cast to a char *), the length of the data, and a 0. If you want to receive data from the remote socket you can do so with the recv() function. It takes the same parameters as the send() function.

After you have send and recieved data to your hearts content, you have to close the socket before exiting the program. There are two functions that you have to call to close a TCP/IP connection. The first function that you need to call is shutdown. This function takes two parameters. The first is our trusty socket, and the second is the value 2. For now don't worry about the second value, its discussion is beyond the scope of this article. After you call shutdown you need to call closesocket(). The only argument that closesocket() takes is the socket that we have been using all along.

I hope that after reading this, you get a good overview of the steps necessary to write a simple TCP/IP socket application. If you would like to learn more about socket programming, there are several good books out there, as well as articles at http://msdn.microsoft.com .


Server Response from: ETNASC03