I know of two techniques that could be applied here.
Technique 1
UDP Hole Punching
UDP Hole Punching uses a server as a "lobby".
The clients you want to engage a P2P connection with first connect to the server using the UDP protocol, the clients therefor require a port to be opened ("hole") to be able to receive data.
Because UDP is a connection-less protocol you can set the clients up to accept packets incoming from the "lobby"-server and each other.
After both clients have established connection the server will provide them with their partner's IP and matching "hole"-port.
A pretty straight-forward implementation can be found in the answers here.
Technique 2
Universal Plug-n-Play
My least favourite of the two, as it requires the clients' routers to have uPnP support and to have it enabled.
uPnP in C#.NET can be easily done by including the NATUPNPLib COM-library
(don't forget to disable "Embed Interop Types" in the Reference settings)
A simple implementation would be like this:
public const int upnp_port = 3075;
private static UPnPNATClass pnp = new UPnPNATClass();
private static IStaticPortMappingCollection mapc = pnp.StaticPortMappingCollection;
public static IPAddress local_ip()
{
foreach (IPAddress addr in Dns.GetHostEntry(string.Empty).AddressList)
if (addr.AddressFamily == AddressFamily.InterNetwork)
return addr;
return null;
}
public static void upnp_open()
{
mapc.Add(upnp_port, "UDP", upnp_port, local_ip().ToString(), true, "P2P Service Name");
}
public static void upnp_close()
{
mapc.Remove(upnp_port, "UDP");
}
PLEASE take note that this is quickly-written code and it will need overlooking/optimisation, definitely the local_ip()
function as it can become unreliable with several network adapters installed.