views:

61

answers:

1

I am creating a simple HTTP client/server application on my local machine but I don't know why the ListenerCallback is triggered on the server; however, EndGetContext is not completing while throwing 'Web Exception: Unable to connect to remove server" on the client side. Any ideas? here's the code

    class Server
{
    static void Main(string[] args)
    {
        NonblockingListener(new string[] {"http://192.168.0.55:5432/"});
    }

    public static void NonblockingListener(string[] prefixes)
    {
        HttpListener listener = new HttpListener();
        foreach (string s in prefixes)
        {
            listener.Prefixes.Add(s);
        }
        listener.Start();
        IAsyncResult result = listener.BeginGetContext(new AsyncCallback(ListenerCallback), listener);     
        Console.WriteLine("Waiting for request to be processed asyncronously.");
        result.AsyncWaitHandle.WaitOne();
        Console.WriteLine("Request processed asyncronously.");
        listener.Close();
    }

    public static void ListenerCallback(IAsyncResult result)
    {
        HttpListener listener = (HttpListener)result.AsyncState;
        // Call EndGetContext to complete the asynchronous operation.

        HttpListenerContext context = listener.EndGetContext(result);
        HttpListenerRequest request = context.Request;
        Stream reader = request.InputStream;


        HttpListenerResponse response = context.Response;

        string responseString = "<HTML><BODY> Hello World!</BODY></HTML>";
        byte[] buffer = System.Text.Encoding.UTF8.GetBytes(responseString);

        response.ContentLength64 = buffer.Length;
        System.IO.Stream output = response.OutputStream;
        output.Write(buffer, 0, buffer.Length);

        output.Close();
    }


}


   class Client
{
    public static void Main()
    {
        // Create a request using a URL that can receive a post. 
        HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://192.168.0.55:5432");

        request.UserAgent = "linkToShare - HTTPWebRequest";
        request.Method = "POST";
        // Create POST data and convert it to a byte array.
        string postData = "data data data data.";
        byte[] byteArray = Encoding.UTF8.GetBytes(postData);
        request.ContentType = "application/x-www-form-urlencoded";
        request.ContentLength = byteArray.Length;          
        Stream dataStream = request.GetRequestStream();
        dataStream.Write(byteArray, 0, byteArray.Length);
        dataStream.Close();
        WebResponse response = request.GetResponse();
        Console.WriteLine(((HttpWebResponse)response).StatusDescription);
        dataStream = response.GetResponseStream();
        StreamReader reader = new StreamReader(dataStream);
        string responseFromServer = reader.ReadToEnd();
        Console.WriteLine(responseFromServer);
        reader.Close();
        dataStream.Close();
        response.Close();
    }

}
A: 

The problem with your code is that in the server you are calling EndGetContext method which will set the WaitHandle and immediately close the server before it had any time to send the response.

Here's a slight modification of your code.

Server:

class Program
{
    private static ManualResetEvent _waitHandle = new ManualResetEvent(false);

    static void Main()
    {
        NonblockingListener(new string[] { "http://+:5432/" });
    }

    public static void NonblockingListener(string[] prefixes)
    {
        using (var listener = new HttpListener())
        {
            foreach (string s in prefixes)
            {
                listener.Prefixes.Add(s);
            }
            listener.Start();
            var result = listener.BeginGetContext(new AsyncCallback(ListenerCallback), listener);
            Console.WriteLine("Waiting for request to be processed asyncronously.");

            // Block here until the handle is Set in the callback
            _waitHandle.WaitOne();
            Console.WriteLine("Request processed asyncronously.");
            listener.Close();
        }
    }

    public static void ListenerCallback(IAsyncResult result)
    {
        var listener = (HttpListener)result.AsyncState;
        var context = listener.EndGetContext(result);

        var response = context.Response;
        string responseString = "<HTML><BODY>Hello World!</BODY></HTML>";
        byte[] buffer = Encoding.UTF8.GetBytes(responseString);
        response.ContentLength64 = buffer.Length;
        response.OutputStream.Write(buffer, 0, buffer.Length);
        // Finished sending the response, now set the wait handle
        _waitHandle.Set();
    }
}

Client:

class Program
{
    static void Main(string[] args)
    {
        using (var client = new WebClient())
        {
            client.Headers[HttpRequestHeader.UserAgent] = "linkToShare - HTTPWebRequest";
            var valuesToPost = new NameValueCollection
            {
                { "param1", "value1" },
                { "param2", "value2" },
            };
            var result = client.UploadValues("http://127.0.0.1:5432", valuesToPost);
            Console.WriteLine(Encoding.UTF8.GetString(result));
        }
    }
}
Darin Dimitrov
I copied your exact code in both client/server sides. client.UploadValues gave me this WebException{"Unable to write data to the transport connection: An existing connection was forcibly closed by the remote host."}
Mustafa A. Jabbar
Is the server throwing an exception? Look at the event logs as well.
Darin Dimitrov
I noticed that the server is still closing before the client proceeds the UploadValues
Mustafa A. Jabbar
Hmm, that's strange. It doesn't happen when I tested. The _waitHandle is initialized to `false` meaning that unless someone calls `.Set()` on it it will block and we call .Set() at the end of the `ListenerCallback` method.
Darin Dimitrov
I think I solved it.. I just removed the listener.close from the server side and kept GetContext inside a while(true) to get requests continously
Mustafa A. Jabbar