FIX: Assertion Failed, Line 475 of Sockcore.cpp

ID: Q139692


The information in this article applies to:


SYMPTOMS

An MFC application that uses the socket classes and makes sequential calls to close and create sockets encounters an assertion failure:

In MFC 3.1 and 3.2, the assertion appears as:

Assertion Failed: <app name>: File sockcore.cpp, Line 475
In MFC 2.52, the assertion appears as:
Assertion Failed: <app name>: File sockcore.cpp, Line 456


CAUSE

MFC maintains a map of dead sockets. (A dead socket is a socket that was open but that has been closed.) The purpose of this map is described in further detail in the "More Information" section of this article.

If an application closes and opens sockets in the same thread without yielding to process messages, then it is possible that an attempt will be made to close a socket that has already been closed. MFC does not properly handle this because it can only have one entry in the map of dead sockets. The resulting assertion failure is checking whether there is already an entry in the map of dead sockets:


   ASSERT(CAsyncSocket::LookupHandle(hSocket, TRUE) == NULL);
   // The TRUE means it is looking for a dead socket handle,
   // thus the assertion failure occurs. 


RESOLUTION

There are four possible resolutions:


STATUS

Microsoft has confirmed this to be a bug in the Microsoft products listed at the beginning of this article. This problem was corrected in the version of MFC that ships with Microsoft Visual C++, 32-bit Edition, version 4.0.


MORE INFORMATION

Sending Small Packets of Data

If you are just interested in sending small packets of data back and forth, then opening and closing several STREAM type sockets might not be the best solution. STREAM sockets were created for sending large amounts of data reliably. Two alternate solutions (using one persistent connection or using DATAGRAM sockets) might be more suitable and would probably provide better performance than you would get by opening and closing many STREAM type socket connections.

Using One Persistent Connection

If you are sending this data between the same processes, you can do something like what the Chatter and ChatSrvr samples do. They both have a Message Structure defined. They open a socket connection and leave it open. Then they just send multiple Message Structures back and forth to each other through the socket until one or the other side decides to disconnect permanently. Then the LastMessage bit is set in the Message Structure and sent to the other process. The other process then closes down gracefully.

Using DATAGRAM Sockets

You can open a single unconnected DATAGRAM socket, and use the SendTo and ReceiveFrom functions to send little bits of data between processes.

This might be a better approach because it does not require you to use the overhead of opening or closing a socket connection for every message you send. You can just use an unconnected DATAGRAM socket, and use SendTo when you need to send the data. Additionally, DATAGRAM sockets are generally faster than STREAM sockets. The primary catch here is that DATAGRAM sockets do not guarantee delivery of your data -- although on many systems, they are almost as reliable as STREAM sockets.

The WM_SOCKET_DEAD Mechanism

MFC has a mechanism for preventing a problem that occurs when a socket has been closed while there were still notification messages in the application's message queue that were bound for that socket.

The problem is that a new socket could be opened that has the same handle as the socket that was closed. The messages that still existed in the message queue are eventually received, and they appear to be destined for the newly opened socket. This can cause a variety of problems. For example, OnReceive might be called for a socket that actually has nothing to receive.

MFC's appraoch to handling this problem uses a special message called WM_SOCKET_DEAD. Whenever a socket is closed, the following occurs:

  1. The SOCKET handle is removed from the map of attached sockets.


  2. The SOCKET handle is placed in the map of dead sockets.


  3. The WM_SOCKET_DEAD message is posted to the application's message queue with a wParam indicating the closed SOCKET handle.


NOTE: These first three steps are implemented in CAsyncSocket::KillSocket, in Sockcore.cpp.

  1. The message routing mechanism for MFC's hidden socket notification window ignores all messages for a SOCKET handle while the SOCKET handle is in the map of dead sockets.


  2. The SOCKET handle is not removed from the map of dead sockets until the WM_SOCKET_DEAD message is received.


By POSTING the WM_SOCKET_DEAD message, MFC causes all pending socket messages for that particular SOCKET handle to be ignored until the WM_SOCKET_DEAD message is received. The effect of this is to ignore any notifications that were pending for the now-dead socket. Any messages received after that are notifications for the open socket and those messages will be properly handled.

Additional query words: 2.52 2.10 2.20 3.10 3.20 4.00 CSocket CAsyncSocket


Keywords          : kbMFC kbVC kbWinsock 
Version           : 1.52    | 2.10 2.20
Platform          : NT WINDOWS 
Issue type        : 

Last Reviewed: August 5, 1999