Custom Transport question

Hi,

I am looking for some adviceon writing a custom WCF Transport.

I amusing the June CTP UDP Transport sample as my starting point. I noticed that each ChannelListenercreates a new Socket and binds to it. I would like to use the same IP and port for multiple Service Contracts on the server side like the following:

ServiceHost service1 = new ServiceHost(typeof(InterfaceAImpl));
service1.AddServiceEndPoint(typeof(InterfaceA), whateverBinding, new Uri(“net.udp://localhost:8080/A”));
service1.Open();

ServiceHost service2 = new ServiceHost(typeof(InterfaceBImpl));
service2.AddServiceEndPoint(typeof(InterfaceB), whateverBinding, new Uri(“net.udp://localhost:8080/B”));
service2.Open();

First, the sample code won’t work because it will try to bind to the same port. That’s fine as I can specify “ReuseAddress” on the socket. But I think this is not a good idea for design and performance reasons because the 2 ChannelListener instances will get the same data from the socket, parse the data and dispatch them (one of them will go no where).

To do this properly,itseems like I have to write my own multiplex/de-multiplex code (and make sure only 1 socket with the same IP and port is created). The incoming "Message" will be dispatched to the appropriate ChannelListener based on the URI of the Message.

Am I on the right track? OrdoesWCF alreadyprovide asolution, but it’s not being used in the UDP Transport sample?

Thanks very much.
W Wong

[3528 byte] By [WWong] at [2007-12-22]
# 1

*IMO*, What you are experiencing about the UDP sample is

true (it is still a sample ;)). So yes, you have to implement the multiplexing/demultiplexing

logic in your protocol implementation. But this implementation is actually can

be done in two ways depending on your requirements.

For example, if your service hosts are running in the same

process things will be a bit easy ;-). Essentially, you have to have a protocol

implementation which has the necessary API to register and un-register

listeners. So this implementation should listen to the actual network traffic

and your listener’s should use that API to register/un-register their

respective URI’s in the protocol listener. When data is available protocol

listener should look at the address [usually address/port/uniquename] and demux

the traffic appropriately. The protocol listener should also take the necessary

actions to write the address to outgoing traffic appropriately.

However, if you want to use same address/port combination

across multiple processes; then you will need a 3rd process to sit between the

processes sharing the same address/port combination and do the dumuxing.

A good example for this is the Net.Tcp Port sharing service

that comes with net.tcp protocol implementation of WCF. When port sharing is

enabled tcp transport listeners do not directly sit on the sockets. Instead

they invokes the necessary functions in the port sharing service to register

their desired URI and the port sharing service listens to the actual network

traffic on behalf of these subscribed processes. When some data is available,

it demuxes them by inspecting the address field. So essentially, this is

similar to moving the logic you had in the former case to a separate process.

I was also thinking along these lines… actually because I

thought about implementing a sample protocol listener in the kernel because I

think that would help to gain some perf (something similar to HTTP.sys)…

So that was my 2 cents. But before coming to a conclusion I recommend

that you wait for some more details from the team because they might verify

what I’ve said here and might provide more interesting thoughts ;-).

Cheers,

BuddhikedeSilva at 2007-8-30 > top of Msdn Tech,Visual Studio Orcas,Windows Communication Foundation (Indigo)...
# 2

As Buddhike notes, this _is_ a sample :)

We support the behavior you are requesting in our WCF TCP Transport, both through the port-sharing service as well as directly on top of a socket. Demuxing when on top of a socket directly can only be shared by services within the app-domain of course.

We could have written the sample so that multiple Listeners could share a UDP port. In that case we would have mapped the base address of the listener to a user-mode demux table, and had to match incoming messages based on either some framing information or some information in the Message. Given the construction of the sample (where there is no framing added), you would likely use Message.Headers.To for the user-mode demux.

I also would recommend longest-prefix match for your user-mode dispatch in order to provide consistency with the WCF built-in transports as well as http.sys.

Lastly, to Buddhike's thought on a kernel mode TCP/UDP listener -- the advantage would be the setup time of new connections with the downside being security/stability risks if anything went wrong in the kernel. Since we duplicate the socket handle into the worker process, steady-state throughput is the same for standalone and port-sharing over TCP. The difference is at channel initiation time (where we either need to validate the cached connection or dup over the new connection).

Hope this helps.

KennyWolf at 2007-8-30 > top of Msdn Tech,Visual Studio Orcas,Windows Communication Foundation (Indigo)...
# 3

Thanks very much Buddhike and Kenny! Don't get me wrong, I am not complaining about the UDP sample :) I just want to make sure I am on the right track.

I already have the UDP port sharing working in my custom transport. Now I have another question regarding custom encoder and hope to get some help too.

My application code will be transferring lots of binary data using WCF service contracts. If I am right, I think the default encoding method is base64 in the SOAP message. Is there any way to force it not to use base64 encoding or maybe hook into the runtime getting the raw data and use my own binary encoding?

I don't want the runtime to spend time doing base64 encoding for me if I don't want base64. I know I can build a custom encoder, but it seems like when I first get the WCF Message object, it's already base64 encoded. Is that mean I have to decode the data and then do my own encoding? To be specific, when my custom OutputChannel's Send method is invoked, the Message object is already base64 encoded. Maybe I am missing something...

Thanks in advance!
W Wong

WWong at 2007-8-30 > top of Msdn Tech,Visual Studio Orcas,Windows Communication Foundation (Indigo)...
# 4

The outbound message is not base 64 encoded until it reaches the encoder. If you plug in a custom encoder and provide an XmlWriter that does optimizations in WriteBase64 then you can optimize this path. Let me know if you have problems with that approach.

--Kenny

KennyWolf at 2007-8-30 > top of Msdn Tech,Visual Studio Orcas,Windows Communication Foundation (Indigo)...

Visual Studio Orcas

Site Classified