I am working on a .NET application which would enable pairs of computers located anywhere on the Internet (and usually behind NATs) to exchange messages between each other in parallel. I did some research for possible solutions and came to the conlsuion that maybe WCF duplex P2P connectivity would be suitable for what I need. Since I am new to WCF, I created a small test application and it seems to work well in general with one exception - peer which sends particular message to the other side also gets a call on its own interface and receives it back. Here is the code
using System;
using System.Threading.Tasks;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
[ServiceContract(CallbackContract = typeof(IDataChannel))]
public interface IDataChannel
{
[OperationContract(IsOneWay = true)]
void SendData(string data);
}
public class WCFP2PTransport : IDataChannel
{
private IDataChannel m_outChannel = null;
private DuplexChannelFactory<IDataChannel> m_factory = null;
private Task m_completion;
private string m_name;
public WCFP2PTransport(string service, string name)
{
m_name = name;
try
{
var binding = new NetPeerTcpBinding();
binding.Security.Mode = SecurityMode.None;
var endpoint = new ServiceEndpoint(
ContractDescription.GetContract(typeof(IDataChannel)),
binding,
new EndpointAddress("net.p2p://" + service));
m_factory = new DuplexChannelFactory<IDataChannel>(
new InstanceContext(this),
endpoint);
m_outChannel = m_factory.CreateChannel();
m_completion = Task.Factory.FromAsync(((ICommunicationObject)m_outChannel).BeginOpen, ((ICommunicationObject)m_outChannel).EndOpen, null);
}
catch (Exception ex)
{
Console.WriteLine(ex);
var tsk = new TaskCompletionSource<bool>();
tsk.SetException(ex);
m_completion = tsk.Task;
}
}
public Task ChannelOpened
{
get
{
return m_completion;
}
}
public void SendToPeer(string data)
{
m_outChannel.SendData(data);
}
// IDataChannel method(s), handle incoming traffic
public void SendData(string data)
{
Console.WriteLine("{0} Received data: {1}", m_name, data);
}
// cleanup code omitted for brevity
}
class Program
{
static void Main(string[] args)
{
var peer1 = new WCFP2PTransport("WCF_P2P_Test", "Peer1");
var peer2 = new WCFP2PTransport("WCF_P2P_Test", "Peer2");
Task.WaitAll(peer1.ChannelOpened, peer2.ChannelOpened);
peer1.SendToPeer("Packet1");
peer2.SendToPeer("Packet2");
Console.ReadKey();
}
}
Output of this application is
Peer1 Received data: Packet1
Peer2 Received data: Packet1
Peer1 Received data: Packet2
Peer2 Received data: Packet2
while I would like to see
Peer2 Received data: Packet1
Peer1 Received data: Packet2
Of course I can do some tricks in my application to filter out unwanted incoming traffic but before doing that I would like to know
Is it possible to configure WCF to not call the peer back in response to its own call?
What is the best way to restrict peers to only connect in pairs and each peer connecting to specific peer only? I can think of using unique P2P service name for each pair that is why there is an argument providing it to the peer class constructor?