Winsock Programmer's FAQ: Information for New Winsockers
<<

Winsock Programmer's FAQ
Section 2: Information for New Winsockers

>>
2.1 - Are there any sample apps on the Net?

Yes. There are several listed on the Resources page, and the FAQ's Examples section has several more. If you're just getting started with Winsock, you may be especially interested in these samples.

2.2 - Do I need to initialize the WSAData structure before calling WSAStartup?

No, WSAStartup() fills this structure in for you.

2.3 - I'm getting link errors when compiling Winsock programs. What's wrong?

You're most likely not linking with the proper Winsock import library. For 16-bit Windows systems, this is winsock.lib. For 32-bit Windows systems using Winsock 1.1 functions only, it is wsock32.lib. And for programs needing Winsock 2 support, you need to link with ws2_32.lib.

2.4 - If I write a Winsock program, will I be able to communicate with a Unix sockets program?

Absolutely! This common question is the result of confusing protocols with the APIs. Communicating programs need not have been created with the same APIs, as long as they are using the same transport and network protocols.

2.5 - Can I use Winsock with { My Favorite Language }?

Most programming languages these days have some way of accessing Winsock, but Winsock is rarely used directly except from C or C++. There are several reasons for this.

Reason 1: Some languages simply lack the language features to call the Winsock API. Your language needs the following to fully use the Winsock API:

  1. Pointers. (The ability to access a specific piece of memory by its address.)
  2. Bitwise operators. (The ability to change specific bits in a byte.)
  3. Structures or records. (The ability to define a block of memory that is an aggregate of simple data elements, such as two characters followed by a 16-bit integer. This feature must also allow some measure of control as to how the data is laid out in memory.)

Reason 2: Many languages rely on some form of component architecture (e.g. ActiveX) to provide outside services like network access. Often the language environment comes with basic networking components, sufficient for most tasks. If your tool didn't come with the necessary compnents, or the ones it does come with aren't powerful enough, you may be able to find the functionality you need in a third-party library, rather than writing the necessary Winsock code yourself.

Reason 3: Many newer languages - especially cross-platform scripting languages - include language support for networking. (Examples include Java, Perl, Python and Tcl.) From the programmer's point of view, Winsock is rarely a concern when working in these languages.

For these reasons and others, this FAQ is biased towards C++.

If your language allows direct access to the Winsock API, you may be able to translate the C++ code in the FAQ into equivalent code in your chosen language. However, I recommend that you look for sample code in your chosen language via the Web Pages section of the FAQ, so you can study working code before you begin translating.

2.6 - Are there any tools available for debugging Winsock programs?

First, I would like to warn against using the built-in Winsock debugging options, SO_DEBUG and the dt_dll.dll. It'd be nice if these worked, but as this article explains, it's currently so much of a mess that the tools below work better for most people.

There are two categories of debugging tools: network analyzers (colloquially known as "sniffers") and Winsock shims.

Sniffers are usually software packages that run on one of the LAN's workstations and, due to the way typical LANs work, capture all of the traffic going over the LAN. Good sniffers will also decode that traffic by various degrees. One advantage of a sniffer is that it literally sees everything about the conversation, including low level protocol details that aren't available from the Winsock layer. Another is that the good ones are extremely powerful and configurable. For example, some allow you to write "protocol plugins" that will decode any protocol (such as a custom protocol that you've developed).

The disadvantages of sniffers are several:

  1. Software critics call a sniffer "inexpensive" when it costs less than $2000, and they positively gush when they cost less than $1000. This is because hardware sniffers, which are still quite common, are about an order of magnitude more expensive.
  2. There are a few truly inexpensive sniffers, but many have serious limitations: some have rotten or nonexistent user interfaces, few cheap/free sniffers run under Windows, and many are just plain weak.
  3. Some sniffers only work on Ethernet, so they can't sniff conversations going over PPP or other WAN links.

All that aside, however, sometimes a sniffer is the only way to find out what you want to know about your program's behavior. If you've got the cash, a good sniffer is almost always the best tool for the job.

The other tool category is "Winsock shims." A shim sits between your program and Winsock, either by replacing the DLL itself with a proxy DLL, or by "hooking" the Winsock DLL's API. These tools are limited to monitoring events on the Winsock layer itself, and can only monitor traffic to or from a single host. (That is, they can't see the "big picture" of simultaneous conversations between many machines.) Their advantages are that this is usually sufficient, and that the most expensive shims cost less than $200.

The Debugging Resources page has links to several good sniffers and shims. Also, see Debugging TCP for some less-automated methods of debugging a TCP program.

2.7 - How do I get a readable error message from a Winsock error number?

The problem with this question is that it assumes that there is a "good" canned error message for every situation. The reality is that many times, you need to know the program's context before you can turn an error value into a meaningful error message. For example, WSAEFAULT can mean "Bad pointer passed," or "Passed buffer too small," or even "That version of the API is not supported." Since the Winsock spec documents the most likely error values that each function will return, you should use this information to construct intelligent error handlers.

Still, sometimes an API call returns something unexpected, so a cryptic error message is better than none at all. In that case, you can just build a stringtable in your resource file mapping error numbers to error messages. There is one such RC file for the Winsock 1.1 error values available here. Alternately, the basic Winsock tutorial programs in the FAQ include a utility module (ws_util.cpp) that defines a function for translating Winsock error numbers into strings.

Note that some people will tell you that the Win32 FormatMessage() API can be coerced into returning error messages for Winsock error numbers. At best, this is undocumented behavior that only works with some implementations of Winsock. I personally have not been able to get it to work, despite significant time devoted to the problem. My advice is that you're much better off spending your time constructing meaningful error messages than chasing something that could never work very well even if it was documented behavior.

2.8 - Winsock keeps returning the error WSAEWOULDBLOCK. What's wrong with my program?

Not a thing. WSAEWOULDBLOCK is a perfectly normal occurrence in programs using non-blocking and asynchronous sockets. It's Winsock's way of telling your program "I can't do that right now, because I would have to block to do so."

The next question is, how do you know when it's safe to try again? In the case of asynchronous sockets, Winsock will send you an FD_WRITE message after a failed send() call when it is safe to write; it will send you an FD_READ message when it is safe to read after a failed recv() call. Similarly, in a non-blocking sockets program that uses select(), the writefds will be set when it's okay to write, and the readfds will be set if there is data to read.

Note that Win9x has a bug where select() can fail to block on a nonblocking socket. It will signal one of the sockets, which will cause your program to call recv() or send() or similar. That function will return WSAEWOULDBLOCK, which can be quite a surprise. So, a program using select() under Win9x has to be able to deal with this error at any time.

2.9 - What can you tell me about MFC's CSocket and CAsyncSocket?

CAsyncSocket is a not-particularly-fancy asynchronous sockets wrapper. I guess it makes using the asynch Winsock API slightly easier, but I personally prefer smarter wrappers that offer features like buffering. (The same commentary applies to OWL's TSocket class. I have no idea what VCL's socket library looks like, so I can't comment on it.) I suggest that if you want to use a Winsock wrapper, try some of the offerings linked on the Libraries page. I personally use my own Endpoint library, which is freely available, is much smarter than both OWL or MFCs offerings, and is compatible with either class library. See the Libraries page for details.

As for CSocket, all I can say is ick. No, that's not true - I can say much more, but I'll restrain myself. CSocket is a subclass of CAsyncSocket that "fakes" blocking I/O using asynchronous sockets by running a small message pump every time it gets a WSAEWOULDBLOCK error. This is technically cute, but it can cause reentrancy side effects. (While CSocket is "blocking", it's pumping messages, which allows a window message to trigger another call to the blocking CSocket object. The full list of similar and related problems is left as an exercise to the reader.) Plus, various versions of CSocket are known to have problems when used in nontrivial situations (e.g. several CSockets, each in its own thread). The most damning criticism of CSocket, though, is that true blocking sockets are easy to come by: the Winsock API is dead easy to program to when using blocking sockets. CSocket just isn't that much of a help to justify itself.

2.10 - How can I test my Winsock application without setting up a network?

There is a special address called the loopback or localhost address, 127.0.0.1. This lets two programs running on a single machine talk to each other. The server usually listens for connections on all available interfaces, and the client connects to the localhost address. (See the Examples section for basic client and server program code.)

If you have Internet access from your development machine, you're already set up for this.

If you don't, you can try installing Dial Up Networking and pointing it at an unused serial port. This can be quirky, but it's possible to limp by with this method. The main problems are when DUN decides it needs to dial the modem, and finds that there is no modem on the port you chose. To minimize this problem, never use name lookup calls like gethostbyname() and turn off DUN's "automatic dial" feature.

Be warned: behavior through the loopback interface may well be different from behavior on a network, if only because conditions are much simpler within a single machine than over a LAN or WAN. You should try to test your application on a real network, even if you do primary development on a single machine.

2.11 - What's the proper way to close a TCP socket?

The proper sequence for closing a TCP connection is:

  1. Finish sending data.
  2. Call shutdown() with the how parameter set to 1.
  3. Loop on recv() until it returns 0.
  4. Call closesocket().

Skipping the first and third steps above can cause data loss.

Nonblocking or asynchronous sockets complicate the first and third steps. You can either build "finish sending/receiving" logic into your normal I/O loop, or you can temporarily put the socket in blocking mode and do the last bits of I/O that way. The proper choice depends on your program's architecture and requirements.

2.12 - Is it possible to close the connection "abnormally"?

Sure, but it's an evil thing to do. :) The simplest way is to set the SO_LINGER flag to 0 with the setsockopt() call before you call closesocket(). Another method is to call shutdown() with the how parameter set to 2 ("both directions"), possibly followed by a closesocket() call.

"Slamming the connection shut" is only justifiable in a very small number of cases. You must have fairly deep knowledge of the way TCP works before you can properly decide to use this technique. Generally, the perceived need to slam the connection shut comes from a broken program, either yours or the remote peer. I recommend that you try to fix the broken program so you don't have to resort to such a questionable technique.

2.13 - How do I detect when my TCP connection is closed?

All of the I/O strategies discussed in the I/O strategies article have some way of indicating that the connection is closed.

First, keep in mind that TCP is a full-duplex network protocol. That means that you can close the connection half-way and still send data on the other half. An example is a web browser: it sends a short request to the web server, then closes its half of the connection. The web server then sends back the requested data on the other half of the connection, and closes its sending side, which terminates the TCP session.

Normal TCP programs only close the sending half, which the remote peer perceives as the receiving half. So, what you normally want to detect is whether the remote peer closed its sending half, meaning you won't be receiving data from them any more.

With asynchronous sockets, Winsock sends you an FD_CLOSE message when the connection drops. Event objects are similar: the system signals the event object with an FD_CLOSE notification.

With blocking and non-blocking sockets, you probably have a loop that calls recv() on that socket. recv() returns 0 when the remote peer closes the connection. As you would expect, if you are using select(), the SOCKET descriptor in the read_fds parameter gets set when the connection drops. As normal, you'll call recv() and see the 0 return value.

As you might have guessed from the discussion above, it is also possible to close the receiving half of the connection. This won't stop the remote peer from sending you data, but it will stop Winsock from telling you about it. Winsock may just silently drop the data on the floor, or it may send an error back to the remote peer.

See below for information on handling abnormal disconnects.

2.14 - How do I detect an abnormal network disconnect?

The previous question deals with detecting when a protocol connection is dropped normally, but what if you want to detect other problems, like unplugged network cables or crashed workstations? In these cases, the failure prevents notifying the remote peer that something is wrong. My feeling is that this is usually a feature, because the broken component might get fixed before anyone notices, so why force everyone to restart?

If you have a situation where you must be able to detect all network failures, you have two options:

The first option is to give the protocol a command/response structure: one host sends a command and expects a prompt response from the other host when the command is received or acted upon. If the response does not arrive, the connection is assumed to be dead, or at least faulty.

The second option is to add an "echo" function to your protocol, where one host (usually the client) is expected to periodically send out an "are you still there?" packet to the other host, which it must promptly acknowledge. If the echo-sending host doesn't receive its response or the receiving host fails to see an echo request for a certain period of time, the program can assume that the connection is bad or the remote host has gone down.

If you choose the "echo" alternative, avoid the temptation to use the ICMP "ping" facility for this. If you did it this way, you would have to send pings from both sides, because Microsoft stacks won't let you see the other side's echo requests, only responses to your own echo requests. Another problem with ping is that it's outside your protocol, so it won't detect a failed TCP connection if the hardware connection remains viable. A final problem with the ping technique is that ICMP is an unreliable protocol: does it make a whole lot of sense to use an unreliable protocol to add an assurance of reliability to another protocol?

Another option you should not bother with is the TCP keepalive mechanism. This is a way to tell the stack to send a packet out over the connection at specific intervals whether there's real data to send or not. If the remote host is up, it will send back a similar reply packet. If the TCP connection is no longer valid (e.g. the remote host has rebooted since the last keepalive), the remote host will send back a reset packet, killing the local host's connection. If the remote host is down, the local host's TCP stack will time out waiting for the reply and kill the connection.

There are two problems with keepalives:

  1. Only Windows 2000 allows you to change the keepalive time on a per-process basis. On older versions of Windows, changing the keepalive time changes it for all applications on the machine that use keepalives.
  2. Each keepalive packet is 40 bytes of more-or-less useless data, and there's one sent each direction as long as the connection remains valid. Contrast this with a command/response type of protocol, where there is effectively no useless data: all packets are meaningful. In fairness, however, TCP keepalives are less wasteful on Windows 2000 than the "are you still there" strategy above.

Note that different types of networks handle physical disconnection differently. Ethernet, for example, establishes no link-level connection, so if you unplug the network cable, a remote host can't tell that its peer is physically unable to communicate. By contrast, a dropped PPP link causes a detectable failure at the link layer, which propagates up to the Winsock layer for your program to detect.

2.15 - How can I change the timeout for a Winsock function?

Some of the blocking Winsock functions (e.g. connect()) have a timeout embedded into them. The theory behind this is that only the stack has all the information necessary to set a proper timeout. Yet, some people find that the value the stack uses is too long for their application; it can be a minute or longer.

Under Winsock 2, you can set the SO_SNDTIMEO and SO_RCVTIMEO options with setsockopt() to change the timeouts for send() and recv().

Unfortunately, the Winsock spec does not document a way to change many other timeout values, and the above advice doesn't apply to Winsock 1.1.

The solution is to avoid blocking sockets altogether. All of the non-blocking socket methods lend themselves to timeouts:

  • Non-blocking sockets with select() - The fifth parameter to the select() function is a timeout value.
  • Asynchronous sockets - Use the Windows API SetTimer().
  • Event objects - In addition to the Winsock event object, have your networking code also block on a regular Win32 semaphore that is signalled by a separate thread that calls the Win32 Sleep() function.
  • Waitable Timers - These are a new feature in Windows 98 and NT 4.0 SP3 and higher. A waitable timer is an object like a semaphore, except that the OS signals it at a future time that you specify. You create them with the Win32 function CreateWaitableTimers(). So, you could wait on a 5-second timer as well as your event objects; if nothing happens on the sockets within 5 seconds, Windows will signal the timer, thus breaking you out of the WaitForMultipleObjects() call.

Note that with asynchronous and non-blocking sockets, you may be able to avoid handling timeouts altogether. Your program continues working even while Winsock is busy. So, you can leave it up to the user to cancel an operation that's taking too long, or just let Winsock's natural timeout expire rather than taking over this functionality in your code.


<< General Winsock Information Intermediate Winsock Issues >>
Last modified on 29 April 2000 at 15:52 UTC-7 Please send corrections to tangent@cyberport.com.
< Go to the main FAQ page
<< Go to my Programming pages
<<< Go to my Home Page