tags:

views:

420

answers:

1

Hey I'm using the WSAEventSelect for event notifications of sockets. So far everything is cool and working like a charm, but there is one problem.

The client is a .NET application and the server is written in Winsock C++. In the .NET application I'm using System.Net.Sockets.Socket class for TCP/IP. When I call the Socket.Shutdown() and Socket.Close() method, I receive the FD_CLOSE event in the server, which I'm pretty sure is fine. Okay the problem occurs when I check the iErrorCode of WSANETWORKEVENTS which I passed to WSAEnumNetworkEvents. I check it like this

if (listenerNetworkEvents.lNetworkEvents & FD_CLOSE)
    {
     if (listenerNetworkEvents.iErrorCode[FD_CLOSE_BIT] != 0)
     {
      // it comes here
      // which means there is an error
      // and the ERROR I got is
      // WSAECONNABORTED
      printf("FD_CLOSE failed with error %d\n", 
       listenerNetworkEvents.iErrorCode[FD_CLOSE_BIT]);
      break;
     }

     closesocket(socketArray[Index]);
}

But it fails with the WSAECONNABORTED error. Why is that so?

EDIT: Btw, I'm running both the client and server on the same computer, is it because of that? And I received the FD_CLOSE event when I do this:

server.Shutdown(SocketShutdown.Both);   // in .NET C#, client code
+1  A: 

I'm guessing you're calling Shutdown() and then Close() immediately afterward. That will give the symptom you're seeing, because this is "slamming the connection shut". Shutdown() does initiate a graceful disconnect (TCP FIN), but immediately following it with Close() aborts that, sending a TCP RST packet to the remote peer. Your Shutdown(SocketShutdown.Both) call slams the connection shut, too, by the way.

The correct pattern is:

  1. Call Shutdown() with the direction parameter set to "write", meaning we won't be sending any more data to the remote peer. This causes the stack to send the TCP FIN packet.

  2. Go back to waiting for Winsock events. When the remote peer is also done writing, it will call Shutdown("write"), too, causing its stack to send your machine a TCP FIN packet, and for your application to get an FD_CLOSE event. While waiting, your code should be prepared to continue reading from the socket, because the remote peer might still be sending data.

(Please excuse the pseudo-C# above. I don't speak .NET, only C++.)

Both peers are expected to use this same shutdown pattern: each tells the other when it's done writing, and then waits to receive notification that the remote peer is done writing before it closes its socket.

The important thing to realize is that TCP is a bidirectional protocol: each side can send and receive independently of the other. Closing the socket to reading is not a nice thing to do. It's like having a conversation with another person but only talking and being unwilling to listen. The graceful shutdown protocol says, "I'm done talking now. I'm going to wait until you stop talking before I walk away."

Warren Young