Handling post requests in HttpListener - c#

private void ListenerCallback(IAsyncResult ar)
{
_busy.WaitOne();
try
{
HttpListenerContext context;
try
{ context = _listener.EndGetContext(ar); }
catch (HttpListenerException)
{ return; }
if (_stop.WaitOne(0, false))
return;
var sr = new StreamReader(context.Request.InputStream);
string x = sr.ReadToEnd();
Console.WriteLine("{0} {1}", context.Request.HttpMethod, x);
//context.Response.SendChunked = true;
using (TextWriter tw = new StreamWriter(context.Response.OutputStream))
{
//for (int i = 0; i < 5; i++)
{
//tw.WriteLine("<p>{0} # {1}</p>", i, DateTime.Now);
tw.WriteLine("<html><head></head><body>");
tw.WriteLine("Server Response");
tw.WriteLine("</body></html>");
tw.Flush(); //Catch http exception if client exists halfway through
//Thread.Sleep(1000);
}
}
}
finally
{
if (_maxThreads == 1 + _busy.Release())
_idle.Set();
}
}
Above is my code, I can go to the URL with Chrome and few the reply even though the server shows it takes 2 get requests, I want to be able to handle POST requests, when I send a post request it reads it properly but the client doesn't get the reply.

You should add ctx.Response.ContentLength64=....
(you may also need ctx.Response.Close())

Related

Connection Reset by Peer C#

So I have windows task scheduler that runs my executable every x minutes.
The executable does the following:
See if any new messages need to sent to the server using sockets.
If there are new messages then make a connection to the server
and send each message.
If there are no new messages then exit the
executable.
Problem:
My executable does not exit and keeps running. So the when windows task scheduler runs again it can't execute because an instance of the executable is still running.
The server where I sent the message told me in the error log they see this:
11-12-19 15:34:09 TCP/IP receive failed; errno 73 - Connection reset by peer.
My code:
namespace TransportMessage
{
class Program
{
static void Main(string[] args)
{
var systemUserId = 1
try
{
using (var dbContext = new DBContext())
{
var unsentRecords = dbContext.Records.Where(x => x.status == "QUEUED").ToList();
if (unsentRecords != null && unsentRecords.Count > 0)
{
var portNumber = 45454;
var dnsName = "xxxx.xxx.xxx.xxx";
IPAddress[] ipAddresses = Dns.GetHostAddresses(dnsName);
Socket soc = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPAddress ipAdd = System.Net.IPAddress.Parse(ipAddresses[0].ToString());
IPEndPoint remoteEP = new IPEndPoint(ipAdd, portNumber);
soc.Connect(remoteEP);
foreach (var rec in unsentRecords)
{
try
{
byte[] byData = System.Text.Encoding.ASCII.GetBytes(rec.message_text);
var numberOfBytesSent = soc.Send(byData);
byte[] buffer = new byte[8000];
int iRx = soc.Receive(buffer);
char[] chars = new char[iRx];
Decoder d = Encoding.UTF8.GetDecoder();
int charLen = d.GetChars(buffer, 0, iRx, chars, 0);
string recv = new string(chars);
rec.sent_ack_message = recv;
rec.number_of_bytes_sent = numberOfBytesSent;
var ackMessageStatus = rec.AckMessageStatus();
if (!String.IsNullOrEmpty(ackMessageStatus))
{
if (ackMessageStatus == "NNN")
{
//Sent successfully. NNN= Good
rec.status = Status.SENT.ToString();
}
else
{
//User received anything else which means something bad in the message.
rec.status = Status.FAILED.ToString();
rec.last_failed_date = DateTime.Now;
rec.last_failed_reason = "Message format incorrect. Please contact IT Operations. Ack Message status " + ackMessageStatus + ".";
}
}
else
{
rec.status = Status.QUEUED.ToString();
rec.last_failed_date = DateTime.Now;
rec.last_failed_reason = "Message sent but no acknowledgment message was received. Message sent back to queued state to try again.";
}
rec.last_modified_by = systemUserId;
rec.last_modified_date = DateTime.Now;
rec.status_date = DateTime.Now;
rec.sent_date = DateTime.Now;
rec.sent_attempt_count = rec.sent_attempt_count + 1;
dbContext.SaveChanges();
}
catch (Exception e)
{
rec.status = Status.FAILED.ToString();
rec.last_modified_by = systemUserId;
rec.last_modified_date = DateTime.Now;
rec.status_date = DateTime.Now;
rec.last_failed_date = DateTime.Now;
rec.last_failed_reason = e.ToString();
rec.sent_attempt_count = rec.sent_attempt_count + 1;
dbContext.SaveChanges();
}
}
}
}
}
catch (System.Net.Sockets.SocketException e)
{
Util.LogError(LogType.FAILED_CONNECTION, e.Message, e.StackTrace);
}
catch (System.Data.DataException e)
{
Util.LogError(LogType.FAILED_TO_CONNECT_TO_DATABASE, e.Message, e.StackTrace);
}
catch (Exception e)
{
//General error if its not database or a socket exception issue.
Util.LogError(LogType.ERROR, e.Message, e.StackTrace);
}
}
}
}
Question:
How do I handle when I get a connection reset by the peer?
I was thinking maybe after I call soc.Connect(remoteEP). I check to see if soc.Connected is false. If so then I disconnect.
if (!soc.Connected)
{
soc.Disconnect(true);
}
Note:
I was disconnecting the socket after I sent my messages but the admin working on the server told me not to do that. Also the executable has been running fine for 3 weeks. No errors or anything.

.Net DownloadFileTaskAsync robust WPF code

The WPF code below hangs forever when network connection is lost for 3 or more minutes. When connection is restored it neither throws nor continues downloading nor timeouts. If network connection is lost for a shorter period say half a minute, it throws after connection is restored. How can i make it more robust to survive network outage?
using System;
using System.Net;
using System.Net.NetworkInformation;
using System.Windows;
namespace WebClientAsync
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
NetworkChange.NetworkAvailabilityChanged +=
(sender, e) => Dispatcher.Invoke(delegate()
{
this.Title = "Network is " + (e.IsAvailable ? " available" : "down");
});
}
const string SRC = "http://ovh.net/files/10Mio.dat";
const string TARGET = #"d:\stuff\10Mio.dat";
private async void btnDownload_Click(object sender, RoutedEventArgs e)
{
btnDownload.IsEnabled = false;
btnDownload.Content = "Downloading " + SRC;
try {
using (var wcl = new WebClient())
{
wcl.Credentials = System.Net.CredentialCache.DefaultNetworkCredentials;
await wcl.DownloadFileTaskAsync(new Uri(SRC), TARGET);
btnDownload.Content = "Downloaded";
}
}
catch (Exception ex)
{
btnDownload.Content = ex.Message + Environment.NewLine
+ ((ex.InnerException != null) ? ex.InnerException.Message : String.Empty);
}
btnDownload.IsEnabled = true;
}
}
}
UPDATE
Current solution is based on restarting Timer in DownloadProgressChangedEventHandler, so the timer fires only if no DownloadProgressChanged events occur within the timeout. Looks like an ugly hack, still looking for a better solution.
using System;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
namespace WebClientAsync
{
public partial class MainWindow : Window
{
const string SRC = "http://ovh.net/files/10Mio.dat";
const string TARGET = #"d:\stuff\10Mio.dat";
// Time needed to restore network connection
const int TIMEOUT = 30 * 1000;
public MainWindow()
{
InitializeComponent();
}
private async void btnDownload_Click(object sender, RoutedEventArgs e)
{
btnDownload.IsEnabled = false;
btnDownload.Content = "Downloading " + SRC;
CancellationTokenSource cts = new CancellationTokenSource();
CancellationToken token = cts.Token;
Timer timer = new Timer((o) =>
{
// Force async cancellation
cts.Cancel();
}
, null //state
, TIMEOUT
, Timeout.Infinite // once
);
DownloadProgressChangedEventHandler handler = (sa, ea) =>
{
// Restart timer
if (ea.BytesReceived < ea.TotalBytesToReceive && timer != null)
{
timer.Change(TIMEOUT, Timeout.Infinite);
}
};
btnDownload.Content = await DownloadFileTA(token, handler);
// Note ProgressCallback will fire once again after awaited.
timer.Dispose();
btnDownload.IsEnabled = true;
}
private async Task<string> DownloadFileTA(CancellationToken token, DownloadProgressChangedEventHandler handler)
{
string res = null;
WebClient wcl = new WebClient();
wcl.Credentials = System.Net.CredentialCache.DefaultNetworkCredentials;
wcl.DownloadProgressChanged += handler;
try
{
using (token.Register(() => wcl.CancelAsync()))
{
await wcl.DownloadFileTaskAsync(new Uri(SRC), TARGET);
}
res = "Downloaded";
}
catch (Exception ex)
{
res = ex.Message + Environment.NewLine
+ ((ex.InnerException != null) ? ex.InnerException.Message : String.Empty);
}
wcl.Dispose();
return res;
}
}
}
You need to implement proper timeout for that download. But you don't need to use timer, just use Task.Delay and Task.WaitAny. For example:
static async Task DownloadFile(string url, string output, TimeSpan timeout) {
using (var wcl = new WebClient())
{
wcl.Credentials = System.Net.CredentialCache.DefaultNetworkCredentials;
var download = wcl.DownloadFileTaskAsync(url, output);
// await two tasks - download and delay, whichever completes first
await Task.WhenAny(Task.Delay(timeout), download);
var exception = download.Exception; // need to observe exception, if any
bool cancelled = !download.IsCompleted && exception == null;
// download is not completed yet, nor it is failed - cancel
if (cancelled) {
wcl.CancelAsync();
}
if (cancelled || exception != null) {
// delete partially downloaded file if any (note - need to do with retry, might not work with a first try, because CancelAsync is not immediate)
int fails = 0;
while (true) {
try {
File.Delete(output);
break;
}
catch {
fails++;
if (fails >= 10)
break;
await Task.Delay(1000);
}
}
}
if (exception != null) {
throw new Exception("Failed to download file", exception);
}
if (cancelled) {
throw new Exception($"Failed to download file (timeout reached: {timeout})");
}
}
}
Usage:
const string SRC = "http://ovh.net/files/10Mio.dat";
const string TARGET = #"d:\stuff\10Mio.dat";
// Time needed to restore network connection
TimeSpam TIMEOUT = TimeSpan.FromSeconds(30);
DownloadFile(SRC,TARGET, TIMEOUT); // might want to await this to handle exceptions
Update in response to comment. If you want timeout based on received data, not on whole operation time, it's also possible with Task.Delay. For example:
static async Task DownloadFile(string url, string output, TimeSpan timeout)
{
using (var wcl = new WebClient())
{
wcl.Credentials = System.Net.CredentialCache.DefaultNetworkCredentials;
DateTime? lastReceived = null;
wcl.DownloadProgressChanged += (o, e) =>
{
lastReceived = DateTime.Now;
};
var download = wcl.DownloadFileTaskAsync(url, output);
// await two tasks - download and delay, whichever completes first
// do that until download fails, completes, or timeout expires
while (lastReceived == null || DateTime.Now - lastReceived < timeout) {
await Task.WhenAny(Task.Delay(1000), download); // you can replace 1 second with more reasonable value
if (download.IsCompleted || download.IsCanceled || download.Exception != null)
break;
}
var exception = download.Exception; // need to observe exception, if any
bool cancelled = !download.IsCompleted && exception == null;
// download is not completed yet, nor it is failed - cancel
if (cancelled)
{
wcl.CancelAsync();
}
if (cancelled || exception != null)
{
// delete partially downloaded file if any (note - need to do with retry, might not work with a first try, because CancelAsync is not immediate)
int fails = 0;
while (true)
{
try
{
File.Delete(output);
break;
}
catch
{
fails++;
if (fails >= 10)
break;
await Task.Delay(1000);
}
}
}
if (exception != null)
{
throw new Exception("Failed to download file", exception);
}
if (cancelled)
{
throw new Exception($"Failed to download file (timeout reached: {timeout})");
}
}
}
Personally, if I were to make a robust download solution, I would add a Network connection monitor because that's what we are actually waiting for. For simplicity, something like this will be enough.
online = true;
NetworkChange.NetworkAvailabilityChanged += NetworkChange_NetworkAvailabilityChanged;
_isNetworkOnline = NetworkInterface.GetIsNetworkAvailable();
void NetworkChange_NetworkAvailabilityChanged(object sender, NetworkAvailabilityEventArgs e)
{
online = e.IsAvailable;
}
Then you can actually check for network availability and wait as appropriate before you attempt to download or progress... I will definitely accept that a simple ping solution seems to work better than this at times based on experience.
Depending on the size of what you're downloading, monitoring the network speed may also help so you can decide how to chunk in case of choppy connections. Take a look at this project for ideas.

How to handle client disconnect in Socket Programming?

I have written a server side code using Sockets, Its working fine but have one problem I don't know how to handle this scenario: if client just closes application without sending Disconnect request, my server side program crashes. What do I need to do to avoid this? Please guide me I am new to Socket programming.
private void OnReceive(IAsyncResult result)
{
try
{
Socket clientSocket = (Socket)result.AsyncState;
clientSocket.EndReceive(result);
command = responseMessage = string.Empty;
command = ByteToString(receviedData);
receviedData = new byte[30];
if (command=="Connect")
{
ClientInfo clientInfo = new ClientInfo();
clientInfo.socket = clientSocket;
clientInfo.IP = clientSocket.RemoteEndPoint.ToString();
connectedClients.Add(clientInfo);
responseMessage = "Connection established...";
}
else if (command=="Disconnect")
{
for (int i = 0; i < connectedClients.Count; i++)
{
if (connectedClients[i].socket == clientSocket)
{
connectedClients.RemoveAt(i);
break;
}
}
clientSocket.Close();
}
else
{
responseMessage = "Error";
}
byte[] responseStatus = StringToByte(responseMessage);
for (int i = 0; i < connectedClients.Count; i++)
{
if (connectedClients[i].socket==clientSocket)
{
connectedClients[i].socket.BeginSend(responseStatus, 0, responseStatus.Length,SocketFlags.None, new AsyncCallback(OnSend), connectedClients[i].socket);
break;
}
}
}
catch(Exception ex)
{
throw new Exception(ex.Message);
}
}
Your application crashes, because you throw an exception in the catch block of your method.
If you don't want your application to crash, you need to remove the throw new Exception(ex.Message); line from the catch block.
Replace it with code that handles the error and gracefully restores your application to a safe state. From reading your code, this should be done by removing the clientSocket from connectedClients
Secondly, it is better to just use throw; instead of throw new Exception(ex.Message);. throw; will re-throw the original exception object and thus preserve the stack trace and other vital information that helps in debugging your software.
Using new Exception("Message") will create a completely new exception object with the current stack trace.
private void OnReceive(IAsyncResult result)
{
try
{
Socket clientSocket = (Socket)result.AsyncState;
clientSocket.EndReceive(result);
command = responseMessage = string.Empty;
command = ByteToString(receviedData);
receviedData = new byte[30];
if (command=="Connect")
{
ClientInfo clientInfo = new ClientInfo() {
socket = clientSocket,
IP = clientSocket.RemoteEndPoint.ToString(),
};
connectedClients.Add(clientInfo);
responseMessage = "Connection established...";
}
else if (command=="Disconnect")
{
removeClientInfo(clientSocket);
clientSocket.Close();
}
else
{
responseMessage = "Error";
}
byte[] responseStatus = StringToByte(responseMessage);
for (int i = 0; i < connectedClients.Count; i++)
{
if (connectedClients[i].socket==clientSocket)
{
connectedClients[i].socket.BeginSend(responseStatus, 0, responseStatus.Length,SocketFlags.None, new AsyncCallback(OnSend), connectedClients[i].socket);
break;
}
}
}
catch(Exception ex)
{
// add error handling and gracefully recover
// caution: The way done here, might work, but it smells :-/
removeClientInfo((Socket)result.AsyncState);
((Socket)result.AsyncState).Close();
}
}
/// removes the client info from the connectedClients enumerable
private void removeClientInfo(Socket socket)
{
for (int i = 0; i < connectedClients.Count; i++)
{
if (connectedClients[i].socket == socket)
{
connectedClients.RemoveAt(i);
break;
}
}
}
You are throwing a new exception inside the catch block, which doesn't make much sense unless you're doing some logging or similar. Change the catch block like:
catch(SocketException)
{
}
Also, you should check the number of bytes read returned from EndReceive. If you receive zero bytes, that means the client has shutdown the connection:
int numReceived = clientSocket.EndReceive(result);
if(numReceived == 0)
{
//client has shutdown the connection
}

From C# to Android via Socket. Can't find my mistake

The problem - I can't get this functions working. I see in LogCat that socket is connected to c# server, but I don't see received data. What I'm doing wrong?
Here is c# function with MessageBoxes for checking:
private void receiveConnection(){
Socket myHandler = null;
bool isConnected = false;
while (true)
{
if (!isConnected)
{
myHandler = wSocket.Accept();
isConnected = true;
MessageBox.Show("We have client!");
}
if (sendDataToAndroid)
{
try
{
sendDataToAndroid = false;
NetworkStream stream = new NetworkStream(myHandler);
StreamWriter sw = new StreamWriter(stream);
string myMsg = "";
myMsg += temp_F.Length + " ";
temp_F[0] = 3.151F;
temp_F[1] = 1.415F;
temp_F[2] = 5.572F;
temp_F[3] = 6.320F;
for (int i = 0; i < temp_F.Length; i++)
{
myMsg += temp_F[i] + " ";
}
byte[] msg = Encoding.ASCII.GetBytes(myMsg);
MessageBox.Show("Data to send: " + myMsg);
try
{
myHandler.Send(msg);
MessageBox.Show("Data has been sent!");
}
catch (Exception e) {
MessageBox.Show("Error while sending data!");
}
}
catch (Exception e)
{
isConnected = false;
myHandler.Close();
myHandler = null;
MessageBox.Show("Error while sending data...");
}
}
}
}
And here is Android function which is always trying to receive data:
public class SendThread implements Runnable {
public void run()
{
Socket socket = null;
BufferedReader in = null;
while (true)
{
// Loop until connected to server
while (socket == null){
try{
socket = new Socket ("192.168.137.1", 808);
}
catch (Exception e) {
socket = null;
}
}
// Get from the server
try {
Log.d("Connection: ", "connected");
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String line = null;
while ((line = in.readLine()) != null) {
Log.d("Socket:", line);
NumberFormat nf = new DecimalFormat ("990,0");
String[] tokens = line.split(" ");
int currTempSize = Integer.parseInt(tokens[0]);
currentTemp = new double[currTempSize];
for (int i = 0; i < currTempSize; i++)
currentTemp[i] = (Double) nf.parse(tokens[i+1]);
//Toast.makeText(getApplicationContext(), "Received data:", duration)
for (int i = 0; i < currTempSize; i++){
Log.d("Converted data: currentTemp["+i+"] = ", currentTemp[i]+"");
}
}
}
catch (Exception e) {
socket = null;
in = null;
Log.d("Connection: ", "lost.");
}
}
}
}
Your Java code reads a line at a time but you never sent a line terminator from C#.
You could append one to myMsg manually, or you could use the sw.WriteLine() method on your StreamWriter (which don't otherwise seem to be using). After calling sw.WriteLine() you will probably have to call sw.Flush().

.NET Proxy Support - HTTPWebRequest

Okay I need help, again! For some reason it is not working, no idea why.. nothing even appears on my catch request..
public void load(object sender, DoWorkEventArgs e)
{
int repeat = 1;
int proxyIndex = 1;
if (listBox1.Items.Count == proxyIndex) //If we're at the end of the proxy list
{
proxyIndex = 0; //Make the selected item the first item in the list
}
try
{
int i = 0;
while (i < listBox1.Items.Count)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(textBox1.Text);
string proxy = listBox1.Items[1].ToString();
string[] proxyArray = proxy.Split(':');
WebProxy proxyz = new WebProxy(proxyArray[0], int.Parse(proxyArray[1]));
request.Proxy = proxyz;
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
{
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
{
string str = reader.ReadToEnd();
}
}
/*HttpWebRequest request = (HttpWebRequest)WebRequest.Create(textBox1.Text);
string proxy = listBox1.Items[i].ToString();
string[] proxyArray = proxy.Split(':');
WebProxy proxyz = new WebProxy(proxyArray[0], int.Parse(proxyArray[1]));
request.Proxy = proxyz;
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
StreamReader reader = new StreamReader(response.GetResponseStream());
string str = reader.ReadToEnd();
Thread.Sleep(100);
{
if (str != null)
{
listBox2.Items.Add("Starting connection.");
Thread.Sleep(1000);
{
listBox2.Items.Add("Waiting..");
Thread.Sleep(500);
{
listBox2.Items.Add("Connection closed.");
repeat++;
continue;
}
}
}
else if (str == null)
{
listBox2.Items.Add("Reply was null, moving on.");
proxyIndex++;
repeat++;
}
}
*/
}
}
catch (Exception ex) //Incase some exception happens
{
MessageBox.Show(ex.Message);
return;
// listBox2.Items.Add("Error:" + ex.Message);
}
}
How can I get it to work?
It looks like you're trying to use a BackgroundWorker to perform this operation, and in the absence of any more detailed information on what isn't working, I'd guess it's because you aren't assigning any result or errors which can be picked up by main thread.
You should assign the results of the request in the case of success:
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
{
e.Result = reader.ReadToEnd();
}
Since you seem to be making multiple requests you should probably make the result a List<string> or similar.
You should remove the try/catch block and deal with any errors in the RunWorkerCompleted event of the BackgroundWorker:
private void BackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if(e.Error != null)
{
MessageBox.Show("Error in async operation: " + ex.Message);
}
else
{
//process results
}
}

Categories