What is the maximum numeric value for a socket, and what is the maximum number of sockets a Windows program can create?


A customer had a problem with their application that used network sockets, and they wanted to know what the maximum numeric value for a socket is. "The program uses a signed integer to hold the socket descriptor, and we found in our testing that the numeric value of INVALID_SOCKET is 0xFFFFFFFF. What is the maximum value?"

In addition to being a vague question, it's also a strange question, so we asked for more information about the problem they are having, in the hopes that we could both understand how the problem led them to asking the strange question, and so we could try to solve the problem.

The customer explained that they have a multithreaded application that uses thousands of network sockets. After running for several days, the customer observed that socket operations are failing with INVALID_SOCKET, and WSA­Get­Last­Error returns error 10038: WSA­E­NOT­SOCK. Since the error is intermittent, the customer is under the impression that the application may have created so many sockets that their socket numbers have exceeded the maximum legal numeric value for a socket, resulting in the INVALID_SOCKET error.

The customer added, "According to this link, the maximum number of sockets that a program can use is determined at compile time by the manifest constant FD_SET­SIZE. However, we cannot find where this constant is defined."

Okay, it's not clear where the customer is getting the impression that a single program cannot use more than FD_SET­SIZE sockets. Indeed, the documentation they referenced says quite the opposite:

The maximum number of sockets that a Windows Sockets application can use is not affected by the manifest constant FD_SETSIZE.

(Emphasis mine.)

The documentation continues:

This value defined in the Winsock2.h header file is used in constructing the FD_SET structures used with select function. The default value in Winsock2.h is 64.

Which conveniently answers the customer's third question.

What the FD_SET­SIZE constant determines is the maximum number of sockets that can be passed in a single call to the select function. The total number of sockets available to a program is not limited by FD_SET­SIZE.

And as the documentation notes, you can make FD_SET­SIZE bigger if you need to. The point is that the fd_set structure is a variable-sized structure, but for compatibility with Unix programs, it is formally defined as a fixed-size structure so that programs can pass them around.

Okay, now back to the original question: Is it possible that the socket function is returning socket numbers that are not legal, and that's why the program gets INVALID_SOCKET when it tries to perform socket operations on those sockets?

This is another case of starting with the assumption that you found an operating system bug instead of starting with the assumption that you have a bug in your program.

While it's possible that there is a bug in the operating system code that does socket management that causes it to hand out invalid socket handles, a much more likely reason that your program is being told that it is using invalid socket handles is, um, because it is using invalid socket handles.

Verify that the handle being passed really is a valid socket. Maybe it was closed prematurely elsewhere. Maybe there is a bug in some other part of the code that is double-closing a handle (and the second time it closes, it accidentally closed your socket handle). Or maybe there is a bug in some other part of the code that is closing an uninitialized handle variable, so it's basically rolling the dice, and most of the time it gets ERROR_INVALID_HANDLE, but once in a while, the uninitialized handle variable happens to contain a value that numerically matches one of your socket handles, and it ended up accidentally closing your socket.

If you really believe that the socket function is returning invalid sockets, I guess you can add debugging code that takes the return value of every call to socket and (if it is not INVALID_SOCKET indicating that the system could not create a socket) call getsockopt to read an arbitrary-selected socket option, and see whether it fails with WSA­E­NOT­SOCK.

I bet it won't. The socket handle was probably good at the point the system gave it to you. You probably did something to make it go bad. Application Verifier can help you find out what.

Comments (16)
  1. David Haim says:

    Out of the description alone (after few days of usage, our program go crazy) you might suspect the opposite – they don’t close the socket properly having a handle leak. after few days the kernel is exhausted and returns INVALID_SOCKET is it can’t produce anymore sockets.
    I bet that one of this cases of “We write our application in C++, but we don’t think in RAII” .

  2. kantos says:

    I had always assumed that since SOCKET is a typedef of UINT_PTR that it was a HANDLE behind the scenes that was constrained to the safe casting range (e.g. the where sign extension does not occur) for an int for “compatibility” with code originally written for *nix systems. That said I also don’t believe in sharing sockets code across APIs. WINSOCK is not POSIX compatible because of type issues and vice versa. That said I really do hope the C++ standards committee gets around to finalizing the Networking TS, and it gets implemented by MSVC and GCC, so I can stop caring about such details.

  3. Ben Craig says:

    I am a bit disappointed that the first question in the headline wasn’t answered “What is the maximum numeric value for a socket”. I’ve seen plenty of code out there that uses an int on 64-bit Windows to hold a socket handle. A socket handle is 64-bits though. Maybe the loss of bits is fine, so long as the maximum numeric value is below INT_MAX.

    1. kantos says:

      Not just 64bits, but unsigned too. So there is an implicit conversion issue that invokes potentially implementation defined behavior. Personally I think this is something that POSIX and WINSOCK can fix by doing a SOCKET_DEFINE macro to let the developer know that they can use a SOCKET type that corresponds correctly to the platform.

    2. alegr1 says:

      “What is the maximum numeric value for a socket”
      This is one of those questions if you ask them, you’re doing things wrong.

    3. ErikF says:

      The article entitled “Porting Socket Applications to Winsock” (‘Socket Data Type’ section) I believe gives you the answer: “Socket handles may take any value in the range 0 to INVALID_SOCKET–1.” [1] In addition, it notes that the SOCKET type is unsigned and lists the gotchas that can occur if you blithely cast away the differences.

      Given the information (the SOCKET type is unsigned and not necessarily small, the range excludes a single value, and the size is not specified), I would interpret the SOCKET type as opaque and not assume anything else about it. (As an aside, I’ve seen older example Unix code that checks for values less than 1024 for socket validity: this can fail unexpectedly when the system’s FD ulimit is increased!)

      [1] https://msdn.microsoft.com/en-us/library/windows/desktop/ms740516(v=vs.85).aspx

  4. Karellen says:

    “This is another case of starting with the assumption that you found an operating system bug instead of starting with the assumption that you have a bug in your program.”

    But… that’s such a convenient and ego-soothing assumption to make! After all, OS bugs do exist, and my code is always right! I mean, except for all those other times I got something wrong, obviously, but those were silly mistakes and don’t count. Besides, I’ve re-read the code this time, and even though I have missed many other bugs on previous multiple re-readings in the past, I’m *sure* I haven’t missed anything this time.

    So it must be an OS bug. Or a compiler bug – those happen too, right?

    (Besides, the universe has a dark sense of humour. Only after it’s spent the better part of a decade beating all the hubris out of your silly human brain, and you have finally learned that it’s *always* a bug in your own code, will it give you an OS bug to beat your head against. For some reason, I’m suddenly imagining an IT version of House, set in a dev shop where young idealistic developers being mentored by a misanthropic greybeardhair, whose catchphrases include “The Client Always Lies” and “It’s Never An OS Bug”.)

    1. Except for that ONE time that it WAS lupus… i mean, an OS bug

    2. Rutger says:

      For some reason, I’m suddenly imagining an IT version of House, set in a dev shop where young idealistic developers being mentored by a misanthropic greybeardhair, whose catchphrases include “The Client Always Lies” and “It’s Never An OS Bug”.)

      That sounds like our 3rd line department. Customers lie, the truth is in the logfiles. Compared to some of our consultants House is a naive and ignorant little puppy :)

      1. Mark (The Other Mark) says:

        Could be a CPU Bug. Did you check the latest CPU Errata? Or maybe it’s a new CPU bug. That could explain why Microsoft isn’t helping- They might have different CPUs. It’s probably best to start with Intel, because it’s not your code.

        1. The application developer says “it must be a bug in the library.”
          The library developer says “it must be a bug in the OS.”
          The OS developer says “it must be a bug in the hardware.”
          The hardware developer says “it must be a bug in physics.”

  5. Andrew says:

    I miss the part where Raymond’s psychic debugging is proved correct and the customer walks away shamed. That’s part of why I come here.

  6. Joshua says:

    Wait a minute … You can wait for more than 64 sockets at once?!! Does this mean there’s some undocumented API that can wait for more than 64 handles at once or is ws2_32.dll doing something wild?

    A documented solution for waiting for N handles at once (where N >> 64) would be really useful for quite a few applications.

    1. Ben Voigt (Visual Studio and Development Technologies MVP with C++ focus) says:

      Sockets aren’t kernel handles.

      The event handle passed to WSAEventSelect doesn’t have to be unique. You could create one event, link it to all the sockets using WSAEventSelect, then WaitForSingleObjectEx on that event.

      Of course, when it returns you need to actually test all the sockets to see which should be reported as having activity, but you needed to do that anyway, since neither WaitForMultipleObjects(bWaitAll := false) nor WaitForMultipleObjects(bWaitAll := true) has the same semantics as select.

    2. smf says:

      “And as the documentation notes, you can make FD_SET­SIZE bigger if you need to. The point is that the fd_set structure is a variable-sized structure, but for compatibility with Unix programs, it is formally defined as a fixed-size structure so that programs can pass them around. ”

      google for increasing FD_SETSIZE and you’ll find an example.

    3. RichardCox says:

      > A documented solution for waiting for N handles at once (where N >> 64) would be really useful for quite a few applications.

      Use I/O Completion Ports. There is no limited (other than overall system resources) to how many I/O operations can be associated to one IOCP. Of course you need a rather different structure to your program.

Comments are closed.

Skip to main content