CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 2 of 2

Thread: Threaded Proxy?

Hybrid View

  1. #1
    Join Date
    Jul 2009
    Location
    London
    Posts
    13

    Lightbulb Threaded Proxy?

    Hi,
    Thanks for reading this!
    For the people who never read any of my posts I am trying to write a proxy server in c#.
    I am trying to "keep it simple" and stay away from asynchronous requests, but is not possible to totally avoid threading and I think I am encountering some multi threading problems.

    The idea is to have a listener socket, binded to a certain prefix. Whatever requests I get there, I append them the correct credentials and send them straight to the (atuthenticated) server on the other side; then I grabb the bytes of the response and show them in the browser. For this I am using the HttpListenerContext class.

    Code:
            public void Start()
            {
                try
                {
                    m_listener.Start();
                    while (true)
                    {
                        try
                        {
                            HttpListenerContext request = m_listener.GetContext();
                            ThreadPool.QueueUserWorkItem(ProcessRequest, request);
                        }
                        catch (Exception e)
                        {
                            System.Diagnostics.Debug.WriteLine(e.ToString());
                        }
                    }
                }
                catch (Exception e)
                {
                    System.Diagnostics.Debug.WriteLine(e.ToString());
                }
                System.Diagnostics.Debug.WriteLine("Listening socket on port " + m_port);
            }
    The function ProcessRequest does the actual job that I wanted. (note that it does it in an asynchronous way!)

    Code:
    	    private void ProcessRequest(object listenerContext)
            {
                try
                {
                    var context = (HttpListenerContext)listenerContext;
    
                    try
                    {
    					// READ ADDRESS HERE...
                        HttpWebRequest request = (HttpWebRequest)WebRequest.Create(address);
    
                        Stream instream = context.Request.InputStream;
                        Stream outstream = response.GetResponseStream();
    					
    					//TRANSFER DATA FROM REQUEST STREAM TO RESPONSE STREAM										
                        // Close streams
                        instream.Close();
                        outstream.Close();
                        context.Response.OutputStream.Close();
                    }
                    catch (Exception ex)
                    {
    
                    }
                }
                catch
                {
                    Restart();
                }
            }
    Normally, everything goes ok; however, whenever I have a client that does a lot of requests very quickly (almost parallely) there is a problem in line writing the output stream (with the bytes that I just grabbed from the server) and an error is thrown:

    An operation was attempted on a nonexistent network connection

    This is misterious; is the network connection referring to the incoming stream (the server that I am comunicating with)? if its there is no apparent problem, because I checked and the connection is still on... or is this connection referring to the output stream? if it is, there is also no apparent problem cause I checked it with the functon CanWrite and it returns true, so it is looks in good health;
    If anybody has any "light" to to bring into this question I would really appreciate it, cause I googled it to exhaustion and did not come to any conclusions irate: :v:

    Anyway, moving on: I caught the error and figure out that I need to somehow close the streams that are opened; I did not find a clean easy way to do it (cause I cannot access the streams anymore), so the "brute-force" approach was to close the actual listener and start it again (so that I can again listen for connections);

    Code:
            private void Restart()
            {
                Stop();
                Start();
            }
    Most of the times, this is ok, but sometimes, when I enter the Start() function, there is a problem with this line:


    Code:
    HttpListenerContext request = m_listener.GetContext();

    and an exception is thrown:

    The I/O operation has been aborted because of either a thread exit or an application request


    and then I am in a bit of a mess.
    Apart from trying to solve this particular errors that cause my application to fail requests once in a while, I am looking at the bigger picture and wondering if the issues I am encountering are from not approaching properly the situation; am I having simultaneous access to the code and no handling properly the multithreading (I actually tried a lock() of the critical section without any improvement...) ? do I need multithreading here? or is it something else?
    As I said, any help here would be much appreciated! Thanks in advance :^:

  2. #2
    Join Date
    Jul 2009
    Location
    London
    Posts
    13

    Re: Threaded Proxy?

    So I think the summary of the situation concerning multithreading in C# is (correct me if I'm wrong):
    - use asynchronous requests and let the system handle the multithreading; (1)
    - use threadPool and let the system handle the multitreading (distribute tasks among worker threads); (2)
    - implement "real" multi threading, handling synchronization, locks, etc; (3)

    I wanted to keep it as simple as possible, without having to write a lot of "thread" of code (unless absolutely necessary), so I tried to stick to option (2), which as Luc Pattyn mentioned, has some limitations but I think I can "live" with them (that is, the app fails sometimes, I can catch the errors and carry on without major implications for the user).

    One thing that I amended in my code, was removing the "restart" of the listener on the event of an exception; there is no need to stop and start the listener on error, and in fact, when I had a lot of threads running, the "restart" of the listener itself was a cause of problems...

    The I/O operation has been aborted because of either a thread exit or an application request

    So, after refactoring my "ProcessRequest" callback, it now looks like this: no restart of the listener and separate handling of different types of exceptions; one important thing is to close the Context.Response after an error, so that it sends a response to the client;

    Code:
           private void ProcessRequest(object listenerContext)
            {
                try
                {
                    byte[] buffer;
                    var context = (HttpListenerContext)listenerContext;
    
                    try
                    {
                        //Make necessary replacements in the host name
                        Uri aUri = context.Request.Url;
                        string url = aUri.AbsolutePath + aUri.Query;
    
                        System.Uri uri = m_service.GetUri();
                        string address = uri.Scheme + "://" + uri.Host + ":" + uri.Port + url;
    
                        // Build Request
                        HttpWebRequest request = (HttpWebRequest)WebRequest.Create(address);
    					
    					//DO STUFF
    					
                        // Close streams
                        instream.Close();
                        outstream.Close();
                        context.Response.OutputStream.Close();
                    }
    
                    catch (System.ArgumentException ex) 
                    {
                        context.Response.StatusCode = int.Parse(ex.Message);
                        context.Response.StatusDescription = GetStatusDescription(context.Response.StatusCode);
    
                        byte[] buff = System.Text.Encoding.UTF8.GetBytes("<HTML><BODY><b>Proxy Failure:</b> (" +
                            context.Response.StatusCode + ") " + context.Response.StatusDescription + "</HTML></BODY>");
    
                        context.Response.ContentLength64 = buff.Length;
                        context.Response.OutputStream.Write(buff, 0, buff.Length);
                    }
                    catch (System.Net.HttpListenerException ex) { }
                    catch (System.Net.WebException ex)
                    {
                        int status = (int)((HttpWebResponse)ex.Response).StatusCode;
    
                        context.Response.StatusCode = status;
                        context.Response.StatusDescription = GetStatusDescription(status);
    
                        context.Response.Close();
                    }
                    catch (Exception ex) { }//Default
                }
                catch (Exception ex)
                {
                    System.Diagnostics.Debug.WriteLine(ex.Message);
                    // It should not come here! Are we having troubles closing the stream?
                }
            }

    It's not the best solution, has it fails to deliver some jobs (not properly handling the multithreading), but its kind of working and is simple.
    cheers,
    Jo

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured