With related to NetTcpBinding, I have also implemented NetPeerTcpBinding, which is based on peer-to-peer communication.
NetPeerTcpBinding involves a lot of complicated things, so I'm not likely to explain a lot.
Peer to peer channel overview
NetPeerTcpBinding itself is a binding for duplex messaging with binary message encoders (like NetTcpBinding) and its own transport, namely PeerTransportBindingElement. It also involves a "peer resolver" which is used to manage peer node statuses.
PeerTransportBindingElement is a transport binding element like HttpTransportBindingElement or TcpTransportBindingElement. While HTTP endpoint is a typical http URI (locally it is most likely only about the port), and TCP endpoint is about an IP endpoint (I forgot to mention yesterday, but its URI is like "net.tcp://localhost:808"), peer transport endpoint is about a "mesh" name which is handled by a "peer resolver". Its URI looks like "net.p2p://mymesh/" . Messages are transmitted to all the "peer nodes" in the specified peer "mesh".
(If you read PeerTransportBindingElement API, you'd notice that it takes an IP endpoint for listening peer connections. But it is not the endpoint - peer transport indirectly uses it, unlike an IP endpoint for TCP endpoint.)
Actually, a peer resolver, which is represented as PeerResolverBindingElement, is more inportant to know the actual peer transport destination. On .NET there are (nominally) two ways to "resolve" peer nodes to transmit messages: (1) PNRP, represented as PnrpPeerResolverBindingElement is Windows peer node resolution protocol, and (2) custom resolver, represented as PeerCustomResolverBindingElement, is resolver-instance-by-user peer resolver with IPeerResolverContract and CustomPeerResolverService API.
With PNRP you don't have to specify anything to resolve peers. It is however not available in Mono (PNRP is Windows specific and I haven't spent any time to implement it). With custom resolver, you have to (only) specify a service endpoint (Binding and EndpointAddress) to IPeerResolverContract service, which is typically CustomPeerResolverService.
Having your host is simple. Just create a ServiceHost with CustomPeerResolverService and add a service endpoint for IPeerResolverContract.
(NOTE: As it depends on NetTcpBinding and it has some blocking issues right now, this binding does not likely work fine either.)
I haven't written any cool net-peer application beyond simple tests. Instead, I used chat application which used to be the top Google results for "WCF application". The server isn't really a peer channel server but rather a custom peer resolver, but the clients show basic use of net-peer communication.
The example code makes use of PeerNode and its interface IOnlineStatus.
The public peer resolver API does not tell much, but its internals are complicated. It has to provide several operations such as, register node to the target mesh (Register), resolve nodes in the target mesh (Resolve), updates node availability statuses (Refresh) and unregister the node from the mesh (Unregister).
In .NET, CustomPeerResolverService internally uses PNRP to implement IPeerResolverContract, So, while "nominally" custom peer resolver is one of the two peer resolver kinds, there is actually only PNRP on .NET.
In Mono, I created BasicHttpBinding-based ad-hoc peer resolver service that is launched within a mono process that uses custom resolvers (the internal "LocalPeerResolverService" class in System.ServiceModel.dll implements the service). It checks port 8931 availability, and if it is already used then it premises as if it were occupied by another custom resolver of our implementation. This behavior may change in future versions.
It is a trivia I found during NetPeerTcpBinding hacking. You cannot expose WSDL for IPeerResolverContract using ServiceMetadataBehavior (see Day 5) because of duplicate global element for 'http://schemas.microsoft.com/net/2006/05/peer:Update' . 99.999% of WCF users wouldn't have to do it though (say, you don't have to implement CustomPeerResolverService).
The reason for this is complicated: it is because RegisterResponseInfo and UpdateInfo have conflicting return element name "Update" (in the same XML namespace) due to its MessageBodyMemberAttribute. That's my guess though - as IPeerResolverContract methods use message contracts for its argument and return value types. But as the contract there wouldn't be other possibilities so it should be almost precise.
The above story is almost nothing for you. But this kind of faulty contract design could happen by chance and it cannot be checked very obviously. The only way I can suggest to try to avoid such problem is to check WSDL generation frequently (like, every time you change the message contract).