Archive

Archive for the ‘tcp’ Category

TCP Proxy in C# using Task Parallel Library

April 27, 2011 9 comments

Every now and then I have the need to proxy TCP communications, handy for things like viewing network traffic or proxying Silverlight or Flash requests. C# makes this pretty easy, and the Task Parallel Library (add-on to .NET 3.5 & shipped with .NET 4) simplifies the code with a nice fluent interface.

Here’s a quick example that works for proxying a VNC connection. There is one task for reading from the client and sending data to the server and another task for reading server responses and sending them to the client.

static TcpListener listener = new TcpListener(IPAddress.Any, 4502);

const int BUFFER_SIZE = 4096;

static void Main(string[] args) {
    listener.Start();
    new Task(() => {
        // Accept clients.
        while (true) {
            var client = listener.AcceptTcpClient();
            new Task(() => {
                // Handle this client.
                var clientStream = client.GetStream();
                TcpClient server = new TcpClient("10.0.1.5", 5900);
                var serverStream = server.GetStream();
                new Task(() => {
                    byte[] message = new byte[BUFFER_SIZE];
                    int clientBytes;
                    while (true) {
                        try {
                            clientBytes = clientStream.Read(message, 0, BUFFER_SIZE);
                        }
                        catch {
                            // Socket error - exit loop.  Client will have to reconnect.
                            break;
                        }
                        if (clientBytes == 0) {
                            // Client disconnected.
                            break;
                        }
                        serverStream.Write(message, 0, clientBytes);
                    }
                    client.Close();
                }).Start();
                new Task(() => {
                    byte[] message = new byte[BUFFER_SIZE];
                    int serverBytes;
                    while (true) {
                        try {
                            serverBytes = serverStream.Read(message, 0, BUFFER_SIZE);
                            clientStream.Write(message, 0, serverBytes);
                        }
                        catch {
                            // Server socket error - exit loop.  Client will have to reconnect.
                            break;
                        }
                        if (serverBytes == 0) {
                            // server disconnected.
                            break;
                        }
                    }
                }).Start();
            }).Start();
        }
    }).Start();
    Debug.WriteLine("Server listening on port 4502.  Press enter to exit.");
    Debug.ReadLine();
    listener.Stop();
}

This is for illustrative purposes only. If you decide to use this in production, you’ll need to use TcpListener.BeginAcceptTcpClient() for async connections, you’ll need error handling and logging, and you’ll want some sort of pool to manage (and clean up) client socket connections. Have fun, and let me know if you have concerns or suggestions.

Categories: C#, Task, tcp, TPL Tags: , , ,