Udostępnij za pośrednictwem


Socket Duplication - Part 1

Socket Duplication is a new feature supported in Whidbey.  So I thought a series on this feature will be very helpful to those who are going to use this API.

 

In this series, I will discuss how duplication is done in the unmanaged world, how it translates to managed code, some samples on how to do duplication and what you have to watch out for while duplicating....OK now let us get started with Part 1 of the series .

 

Socket Duplication API is just a thin wrapper around the underlying winsock call WSADuplicateSocket

 

Unmanaged World:

Typically in the unmanaged world, to duplicate a socket in Process A and to make it available in Process B,

  1. Process A calls WSADuplicateSocket with B's process ID  and gets a structured blob data corresponding to the duplicated socket.
  2. Process A then transmits the blob to B by some IPC mechanism.
  3. Process B then uses the blob to construct a new socket descriptor for the same socket through the WSASocket call.
  4. Both the processes A & B can now use the same socket -> that is the socket is now shared.

The descriptors that reference a shared socket can be used independently for I/O, which means both the processes sharing the socket can read from and write to the socket simultaneously.  OS does not implement any access control mechanism and the coordination has to be done by the processes. But the general usage is to have one process incharge of creating connections and duplicating and transferring to another process which uses this socket.

 

Managed World:

So to make it easy, in managed code, once a socket has been duplicated by a process, it is automatically closed at the source process end. Since duplication increases the reference count on the handle of the socket, the socket is valid even when one of the descriptors is closed.  Hence the API  name DuplicateAndClose. 

 

Here is the API                       public SocketInformation DuplicateAndClose ( int targetProcessId )

 

Given a targetProcessID, the API returns SocketInformation object, the information about the socket that can be passed on to the target process. The target process can then recreate the socket using an overload in the socket constructor that accepts socketInformation

 

                                                public Socket ( SocketInformation socketInformation)

This api can also be used to share sockets across different appdomains – in which case the targetProcessID is the same as the ID of the duplicating process. The SocketInformation class is serializable – which makes it is easy to transfer the object across appdomains.

 

The following example shows how to duplicate a socket and transfer it to a new appdomain .

 

namespace socketDuplication

{

    public class DuplicationSample

    {

        public static void Main()

        {

            //create a socket

Socket sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

            //listen on an ipaddress and port

            sock.Bind(new IPEndPoint(ipAddress, port));

            sock.Listen(5);

            //Duplicate the socket

SocketInformation socketInfo = sock.DuplicateAndClose(Process.GetCurrentProcess().Id);

            //create a new appdomain

AppDomain TestDomain = AppDomain.CreateDomain("DuplicateSocketsTest");

DuplicationNewAppDomain newAppDomain = (DuplicationNewAppDomain)TestDomain.CreateInstanceAndUnwrap(Assembly.GetExecutingAssembly().FullName, "SocketDuplication. DuplicationNewAppDomain");

            //transfer socketinfo to the new appdomain

            newAppDomain.TransferSocket(socketInfo);

        }

    }

    public class DuplicationNewAppDomain : MarshalByRefObject

    {

        void TransferSocket(SocketInformation sockInfo)

        {

        }

    }

}