I'm using an http client and an http server(listener)
In some cases when i'm having big delay-traffic in my network, http client sends request but it nevers takes a response from http listener.As a result i'm trying to resend my request to server. But, server already has took previous one request and re-runs the new one. In this case, server runs my request twice.
httplistener
HttpListener listener;
Thread t;
private void Form1_Load(object sender, EventArgs e)
{
t = new Thread(new ThreadStart(MyThreadMethod));
t.IsBackground = true;
listener = new HttpListener();
listener.Prefixes.Add("http://192.168.0.214:8282/");
listener.Start();
t.Start();
// label1.Text = "Opened";
}
void MyThreadMethod()
{
while (true)
{
IAsyncResult result = listener.BeginGetContext(new AsyncCallback(ListenerCallback), listener);
result.AsyncWaitHandle.WaitOne();
}
}
public void ListenerCallback(IAsyncResult result)
{
HttpListener listener = (HttpListener)result.AsyncState;
HttpListenerContext context = listener.EndGetContext(result);
string methodName = Convert.ToString(context.Request.Url);
//Here is my code
string Response = "OK";
HttpListenerResponse response = context.Response;
string responseString = Convert.ToString(Response);
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();
}
And here is my httpClient
HttpClient client = new HttpClient();
var content = new StringContent("my Data", Encoding.UTF8, "application/json");
var result = client.PostAsync("http://192.168.0.214:8282/", content).Result;
How can i prevent, when i'm having big delay_ms in my network, http listener running twice my requests?
This is a very common issue for distributed applications. You make a request, someone gets it, sometimes complete the request sometimes can not. Furthermore, sometimes you get the response and sometimes not. To deal with such situations, the rule of thumb is "your commands/requests should be idempotent". I mean, even if you send a request/command several times to a service, the result should not change and the command should only be executed only once. Accomplishing this sometimes can be very complicated but for simple scenarios you can simply accomplish this by adding a command id to your requests and a command log to your server. When server receives the request, it first checks whether this command already executed. If it was executed before, it returns the same success response, otherwise runs the command.
Related
Based on MS example code I wrote a simple HTTP server.
listener = new HttpListener();
listener.Prefixes.Add("http://*:8000/");
while (true)
{
listener.Start();
HttpListenerContext context = listener.GetContext();
HttpListenerRequest request = context.Request;
// Obtain a response object.
HttpListenerResponse response = context.Response;
listener.Stop();
}
It seems that at each loop must start with "listenet.Start" and end with "listener.Stop"
When I used only "listener.Start" before the loop, I stopped getting messages from a working Angular client after 2 messages.
Can you please tell why ?
Thank you,
Zvika
I'm testing HttpListener based on the doc. My code is very simple. It's a console application running under the admin privilege:
[STAThread]
static void Main( string[] args )
{
var prefixes = new[] { "http://localhost:8080/", "http://www.contoso.com:8080/index/" };
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." );
Console.ReadLine();
listener.Close();
}
public static void ListenerCallback( IAsyncResult result )
{
HttpListener listener = (HttpListener)result.AsyncState;
HttpListenerContext context = listener.EndGetContext( result );
HttpListenerRequest request = context.Request;
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();
}
If I try http://localhost:8080/ in a web browser then the callback ListenerCallback is called and the response string "Hello world!" appears in the browser.
For http://www.contoso.com:8080/index/ the callback is never called and the web request timed out.
How can I identify where is the problem? It's a bug in .NET framework or in my code?
One reason is if the ip of www.contoso.com is not a local IP to the computer where you are running the HttpListener on. Usually because the traffic gets somewhere in your network first and is redirected to the computer that runs the HttpListener which is using a private IP address. Check the answers here for more. Don't blindly take wildcard solutions though, as those can have security vulnerabilities depending on your scenario.
I'm using hybrid connections to request data from a listener. If I can write and read to the connection, how can I know that the response I've read from the connection matches the request I've given it? For example:
private HybridConnectionClient _client = new HybridConnectionClient(***);
public override async Task<RelayResponse> SendAsync(RelayRequest request)
{
var stream = await _client.CreateConnectionAsync();
var writer = new StreamWriter(stream) { AutoFlush = true };
var reader = new StreamReader(stream);
var reqestSerialized = JsonConvert.SerializeObject(request);
await writer.WriteLineAsync(reqestSerialized);
string responseSerialized = await reader.ReadLineAsync();
var response = JsonConvert.DeserializeObject<RelayResponse>(responseSerialized);
return response;
}
If the listener on this connection is reading and responding to many requests at the same time, is there anyway to know that the next Readline() we do on the client side to get the response is the one that is associated with the request? Or is that something that has to be managed?
Understanding a bit more about azure relay hybrid connections, I understand this now.
There isn't really any concept of a synchronous request/response in the framework, but if you use a new connection for each request, and respond on that same connection in the listener, you can be sure the response is for the request you sent.
Spawn a new connection for each request, then make sure the response is written to that connection. So looking at Microsoft's listener example code, whenever listener.AcceptConnectionAsync() fires do all the message response on relayConnection, then go back to waiting at await listener.AcceptConnectionAsync();
while (true)
{
var relayConnection = await listener.AcceptConnectionAsync();
if (relayConnection == null)
{
break;
}
ProcessMessagesOnConnection(relayConnection, cts);
}
I'm programming an application for Windows Phone 7. This application firstly sends, and then receives data from a server via HttpWebRequest. Most times it works fine, but sometimes, after receiving a portion of the data properly, I get a NullReferenceException in Stream.Read() function.
The communication starts when the user presses a button. Then I create the HttpWebRequest:
HttpWebRequest request = (HttpWebRequest) WebRequest.Create(sUri);
request.Method = "POST";
request.BeginGetRequestStream(GetRequestStreamCallback, request);
The request callback method:
private void GetRequestStreamCallback(IAsyncResult asynchronousResult)
{
HttpWebRequest request = (HttpWebRequest)asynchronousResult.AsyncState;
postStream = request.EndGetRequestStream(asynchronousResult);
this.bSyncOK = Send(); //This is my method to send data to the server
postStream.Close();
if (this.bSyncOK)
request.BeginGetResponse(GetResponseCallback, request);
else
manualEventWait.Set(); //This ManualResetEvent notify a thread the end of the communication, then a progressbar must be hidden
}
The response callback method:
private void GetResponseCallback(IAsyncResult asynchronousResult)
{
HttpWebRequest request = (HttpWebRequest)asynchronousResult.AsyncState;
using (HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(asynchronousResult) )
{
using (streamResponse = new StreamReader(response.GetResponseStream() ) )
{
this.bSyncOK = Recv(); //This is my generic method to receive the data
streamResponse.Close();
}
response.Close();
}
manualEventWait.Set(); //This ManualResetEvent notify a thread the end of the communication, then a progressbar must be hidden
}
And finally, this is the code where I get the exception reading the stream data:
int iBytesLeidos;
byte[] byteArrayUTF8 = new byte[8];
iBytesLeidos = streamResponse.BaseStream.Read(byteArrayUTF8, 0, 8); //NullReferenceException!!! -Server always send 8 bytes here-
When the application starts, I create a background thread that frequently sends info to the server. Background and Manual communications can run simultaneously. Could this be a problem?
Thanks.
If streamResponse is global variable, it can cause the problem in a case of an access from another thread. Pass your Stream to the Recv as a parameter
using (StreamReader streamResponse = new StreamReader(response.GetResponseStream() ) )
{
this.bSyncOK = Recv(streamResponse); //This is my generic method to receive the data
streamResponse.Close();
}
Where is your streamResponse declared in latter snippet? Is it the same object as in 3d snippet? Maybe you just use another variable, instead of actual stream.
in the second snippet, try to delete "postStream.Close();".
I have been putting together a little embedded HTTP server in a windows service app that listens for updates coming from other devices on the network that speak HTTP.
For each HTTP request, the code that processes the request/response is executed twice, I expect it to run only once. I tried the code using the AsyncGetContext method and using the synchronous version GetContext - the end result is the same.
Code
public void RunService()
{
var prefix = "http://*:4333/";
HttpListener listener = new HttpListener();
listener.Prefixes.Add(prefix);
try
{
listener.Start();
_logger.Debug(String.Format("Listening on http.sys prefix: {0}", prefix));
}
catch (HttpListenerException hlex)
{
_logger.Error(String.Format("HttpListener failed to start listening. Error Code: {0}", hlex.ErrorCode));
return;
}
while (listener.IsListening)
{
var context = listener.GetContext(); // This line returns a second time through the while loop for each request
ProcessRequest(context);
}
listener.Close();
}
private void ProcessRequest(HttpListenerContext context)
{
// Get the data from the HTTP stream
var body = new StreamReader(context.Request.InputStream).ReadToEnd();
_logger.Debug(body);
byte[] b = Encoding.UTF8.GetBytes("OK");
context.Response.StatusCode = 200;
context.Response.KeepAlive = false;
context.Response.ContentLength64 = b.Length;
var output = context.Response.OutputStream;
output.Write(b, 0, b.Length);
output.Close();
context.Response.Close();
}
Is there anything obvious that I am missing, I have run out of ideas to track down the issue.
Ok, the issue was I was using a web browser to test the HTTP connection and by default a web browser also sends a request for favicon.ico. So two requests were actually coming across. Thank you to #Inuyasha for suggesting I check things out with Wireshark.