Introduction

Communication is a problem I have had plenty of dealings with in work related projects and projects that are just for fun. .NET remoting makes communication easier but if you have ever used it and received one of their "Remoting Exception" errors, you can understand why I don't like it. Hopefully WCF corrects some of these problems. Either case, if you want to communicate P2P (Peer to Peer) then you either have to deal with something like UPNP, VPN, or proxy of some kind. This is my implementation of a Web proxy.

Background

P2P communication is a problem I've run into several times with my applications. I've made several Messenger type applications that communicate with TcpClients and a TcpListener. The only problem with using them is that your communication is limited to your local area network. Recently, I made another Messenger application that communicates with several Web services and it polls them periodically to get a new list of users, messages, etc. This works fine but having communication that is based on a bunch of clients polling a Web server is not so good. Below is an outline of my solution to this problem. The lines represent WebRequests that are made to an HttpHandlerServer.ashx that are waiting for another client to send data to their end point. I modelled this after TcpClient and TcpListener and stuck a Proxy in between their communication. Problem solved, for the most part.

Using the Code

Before you try these objects out, I am assuming you have basic knowledge of socket communication and you have used TcpClients and TcpListeners. Their Proxy counterparts I've made are very similar except that ProxyClient has a SendData method and a Receiving event instead of a Stream that you can read/write to.

The first thing you need to do is get the Proxy Web Server up and running. If you open the Proxy solution, I am talking about the ProxyService Web site. If you modify this at all, make sure the web.config lines below stay put. This registers the HttpHandlerServer.ashx.

Next, you need to make some connections. Make a ProxyListener that will start Listening and a ProxyClient that connects to it. To make things easier, any object you want to send from ProxyClient to ProxyClient needs to inherit from DataMessage in the ProxyCommon project. This gives your object a SendEndPoint, and RecieverEndPoint. If you wanted to do a client / server app, your server side code would look something like this.

Now for the client side. A ProxyListener starts listening based on a ServerName. The proxy server uses this as key and makes an EndPoint for it. When you create a ProxyClient to communicate with the listener, it is connecting to the same ServerName. The proxy server maps the EndPoints and then both ProxyClients are ready to communicate.

Points of Interest

The major difference between the ProxyClient class and the TcpClient class which you may be used to is that you can't get to a single Stream to read / write to. This is because the underlying streams are coming from HttpWebRequest and WebResponse.

This idea has a few flaws in it that I haven't worked out. Since the proxy exists on a Web server and has a message queue, endpoints, and such stored in the app cache, if the Web server ever restarts, your connections are lost and need to be reestablished. This can be a bigger problem if you are using a shared hosting service such as GoDaddy, which seems to restart on me once a day.

This method will definitely work sending P2P information that is small. I would consider sending small files or serialized objects over it but that's about it. Your communication will be slower than connecting directly with sockets because the streams are having to go through the Web server. If you want to really stream lots of data P2P, this is probably not going to be fast enough.

History

20th April, 2008: Initial post

This is my first attempt at writing Client and Listener wrappers for P2P communication. It's a work in progress, so I am open for suggestions. After I get this communication somewhat perfected, I'm planning on writing another communication wrapper that would be better suited for network gaming, video streaming, etc. If anyone has suggestions on how to do P2P communication with UPNP / port forwarding / tunnelling, please let me know.

I wrote a Server/Client application that works inside a company network based on TCP/IP. However, the client program cannot connect to the server program when a computer is logged in through VPN into a company network. In this case, the client program is installed on a computer that is VPNed into the company network. Can any one provide suggestion on how to solve the problem?

If one was to decentralize the server, is there any way to share connection state information? For example, if there was load balancing and a server 'network' with a request distributor that could handle the requests, any ideas on how one might try that?

I'm sure there would be a way to do that.. I just haven't implemented something like that. The only thing that has to change for that to work is were the proxy httphandler stores its message queue and endpoints. If your on a load balanced server, there will be several instances of the httphandler taking request so they would probably need to store the message queue and endpoints in a sql database or something. You just need to make sure all of them are sharing the same info. Does that help?

Actually, you may not need to change anything for this to work with load balancing. Its been a while since I have thought about load balancing I think the web sites Application cache (Application["SomeKey"]) is the same memory even though you are load balancing. If thats the case, then nothing has to change and this will work as is for load balancing.

If you use a shared state provider, indeed application keys would be the same across a set of servers. With good load balancing on the server and some clever code, you could get throughput up substantially by having a geologically distributed server network all tied with load balancing, and instead of doing CPU load, you balanced by connection latency you'd be talking serious throughput. Very interesting.