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

Thread: Threaded Proxy?

  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

+ Reply to Thread

Tags for this Thread

Bookmarks

Posting Permissions

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



HTML5 Development Center

Click Here to Expand Forum to Full Width