C# problem with HttpListener - c#

I wrote a Windows service using an HttpListener to process the requests from points asynchronously.
It works fine, but sometimes it runs into a problem that requires restarting the service or server to fix. Initially I declared the listener object with:
public HttpListener PointsListener = new HttpListener();
Here is the code of the method, where I starting listening. I'm calling it from the OnStart method of the service:
public string ListenerStart()
{
try
{
if (!PointsListener.IsListening)
{
PointsListener.Prefixes.Add(String.Concat("http://*:", points_port, "/"));
PointsListener.Start();
PointsListener.BeginGetContext(PointProcessRequest, PointsListener);
LogWriter("Http listener activated on port " + points_port);
return "Listener started";
}
else
{
return "Listener is already started!";
}
}
catch (Exception err)
{
LogWriter("Error in LIstenerStart \r\n" + err.ToString());
return ("Error: " + err.Message);
}
}
Here are the methods which process requests:
private void PointProcessRequest(IAsyncResult result)
{
HttpListener listener = (HttpListener)result.AsyncState;
HttpListenerContext context = listener.EndGetContext(result);
HttpListenerRequest request = context.Request;
HttpListenerResponse response = context.Response;
response.KeepAlive = false;
System.IO.Stream output = response.OutputStream;
try
{
//declaring a variable for responce
string responseString = "<html>My Response: request is not allowed by server protocol</html>";
// Commands and actions to set responceString
byte[] buffer = Encoding.UTF8.GetBytes(responseString);
response.ContentLength64 = buffer.Length;
output.Write(buffer, 0, buffer.Length);
}
catch (Exception err)
{
LogWriter("Error in PointProcessRequest: \r\n" + err.ToString());
}
finally
{
try
{
output.Flush();
output.Close();
response.Close();
}
catch (Exception err)
{
LogWriter("Error in PointProcessRequest CLOSING OUTPUT STREAM: \r\n" + err.ToString());
}
finally
{
PointsListener.BeginGetContext(PointProcessRequest, PointsListener);
}
}
}
It is working well some of the time, but the following error appears in the log:
Error in PointProcessRequest:
System.Net.HttpListenerException: The specified network name is no longer available
в System.Net.HttpResponseStream.Write(Byte[] buffer, Int32 offset, Int32 size)
в ARK_Dealer.ark.PointProcessRequest(IAsyncResult result)
[26.01.2011 9:00:54] Error in PointProcessRequest CLOSING OUTPUT STREAM:
System.InvalidOperationException: Cannot close stream until all bytes are written.
в System.Net.HttpResponseStream.Dispose(Boolean disposing)
в System.IO.Stream.Close()
в ARK_Dealer.ark.PointProcessRequest(IAsyncResult result)
I think that problem appears when some point sends the request to server but before the receiving answer looses the connection.
How can I prevent the exception from being thrown? Will be the response object be properly disposed of automatically? How can I solve the problem?

I'm using a HttpListener in production and I've found the nicest way to resolve this issue, without adding a whole bunch of try/catch blocks which do nothing to communicate the logic of the code at hand; is to quite simply to set Listener.IgnoreWriteExceptions = true; and, voilà no more write exceptions!

There is a related question about this.
What you are doing is fine, since there is nothing else that can be done about the other side closing the connection or the connection being dropped. You might want to catch the exact exception and call output.Dispose() and other cleanup or simply let the finalizers handle the release if it doesn't happen very often.

I had the same problem recently, and solved it by wrapping the output in a try/catch:
try
{
byte[] buffer = Encoding.UTF8.GetBytes(responseString);
response.ContentLength64 = buffer.Length;
output.Write(buffer, 0, buffer.Length);
}
catch (HttpListenerException)
{
// Handle error caused by connection being lost
}

Problem solved!!! I just removed this:
finally
{
PointsListener.BeginGetContext(PointProcessRequest, PointsListener);
}
and inserted this command at the begin of PointProcessRequest method!
IAsyncResult _result = listener.BeginGetContext(new AsyncCallback(PointProcessRequest), listener);
Problem solved at 100%!!!

Related

How to detect closed StreamSocket at client side

DataReader.LoadAsync does not detect closed sockets (with InputStreamOptions::Partial)
I am sending data to server via TCP connection and read the response but after and everything is working here. But after 5-6 message my project is hand I didn't find where is error.
Some time i found that connection is closed via host machine
so How can i found that is StreamSocket is connected or not
============Code=============
public async Task<bool> Connect(string host, string port)
{
try
{
socket = new StreamSocket();
HostName hostName = new HostName(host);
CancellationTokenSource _cts = new CancellationTokenSource();
_cts.CancelAfter(5000);
// Connect to the server
await socket.ConnectAsync(hostName, port).AsTask(_cts.Token);
return true;
}
catch (Exception ex)
{
throw ex;
}
}
public async Task<String> SendMessageToServer(string message)
{
try
{
// Create the data writer object backed by the in-memory stream.
using (writer = new DataWriter(socket.OutputStream))
{
writer.WriteString(message);
await writer.StoreAsync();
await writer.FlushAsync();
writer.DetachStream();
return await ReadResponse();
}
}
catch (Exception ex)
{
throw ex;
}
}
private async Task<String> ReadResponse()
{
DataReader reader;
StringBuilder strBuilder = new StringBuilder();
try
{
using (reader = new DataReader(socket.InputStream))
{
uint ReadBufferLength = 1024;
// If task cancellation was requested, comply
//cancellationToken.ThrowIfCancellationRequested();
// Set InputStreamOptions to complete the asynchronous reask(cancellationToken);
reader.InputStreamOptions = Windows.Storage.Streams.InputStreamOptions.Partial;
IAsyncOperation<uint> taskLoad = reader.LoadAsync(ReadBufferLength);
taskLoad.AsTask().Wait(2000);
string msg = string.Empty;
while (reader.UnconsumedBufferLength > 0)
{
strBuilder.Append(reader.ReadString(reader.UnconsumedBufferLength));
msg = strBuilder.ToString();
}
reader.DetachStream();
reader.Dispose();
}
}
catch (Exception ex)
{
return "0";
throw ex;
}
finally
{
// Cleanup once complete
}
return strBuilder.ToString();
}
How can i found that is StreamSocket is connected or not
I tested your code on my side. DataReader/DataWriter are not concerned with "connections" themself as you known. But the connection closed will be detected by method Task.Wait, which is for synchronized waiting on the task completed or throw exceptions. So in your scenario, if the StreamSocked is closed before DataReader.LoadAsync, the taskLoad.AsTask().Wait(2000); will throw the exception:
One or more errors occurred. (An existing connection was forcibly closed by the remote host. )
If the socket connection is closed during DataReader.LoadAsync processed, this time the client cannot detect the closing, it will detect the connection closed next time the client send message to server. In your scenario client will continue sending messages to server which will always catch the connection closing when send new messages. You will got connection closed exception at await writer.StoreAsync(); code line if the server close the connection.
But after 5-6 message my project is hand I didn't find where is error
You may have catch the exception about connection closing. So this may lead by some other reasons. I saw the DataReader in your code snippet only load message one time for length 1024. So if the message send from server is longer than 1024, the client will receive only partial message, and next time when server send new message, the client will still receive the remain message from the last time not the new message. After several times server will back log many data and may lead issues. I recommend you to update the reader.LoadAsync code as follows:
string msg = string.Empty;
var loadsize = await reader.LoadAsync(ReadBufferLength);
while (loadsize >= ReadBufferLength)
{
loadsize = await reader.LoadAsync(ReadBufferLength);
}
if (reader.UnconsumedBufferLength > 0)
{
strBuilder.Append(reader.ReadString(reader.UnconsumedBufferLength));
}
Addtionaly, I strongly recommend you to use StreamReader instead, which will not have the concern as DataReader has, And your ReadResponse() method can just be simply as follows:
private async Task<String> ReadResponse()
{
Stream streamIn = socket.InputStream.AsStreamForRead();
StreamReader reader2 = new StreamReader(streamIn);
string response = await reader2.ReadLineAsync();
return response;
}
More details about StreamSocket in uwp please reference the official sample.

SSLStream reads invalid data + KB3147458 SSLStream bug (?)

I'm having an issue with SSLStream returning some data when the remote client did not send anything. I am having this issue when the server is listening for a new command.
If the server doesn't receive a new request, the ReadMessage() function should catch an IOException due to the Read timeout of the SSLStream. The problem happens when the sslStream.Read() is executed the second time it seems to read 5 bytes which were not sent by the client. So the problem happens in this sequence:
-> ReadMessage() -> sslstream.Read() -> timeout exception caught as expected
-> ReadMessage() -> sslstream.Read() -> timeout exception NOT caught, 5 bytes read even even though the client did not send anything
-> ReadMessage() -> sslstream.Read() -> timeout exception caught as expected
-> ReadMessage() -> sslstream.Read() -> timeout exception NOT caught, 5 bytes read even though client did not send anything...
and so on..
public void ClientHandle(object obj)
{
nRetry = MAX_RETRIES;
// Open connection with the client
if (Open() == OPEN_SUCCESS)
{
String request = ReadMessage();
String response = null;
// while loop for the incoming commands from client
while (!String.IsNullOrEmpty(request))
{
Console.WriteLine("[{0}] {1}", RemoteIPAddress, request);
response = Execute(request);
// If QUIT was received, close the connection with the client
if (response.Equals(QUIT_RESPONSE))
{
// Closing connection
Console.WriteLine("[{0}] {1}", RemoteIPAddress, response);
// Send QUIT_RESPONSE then return and close this thread
SendMessage(response);
break;
}
// If another command was received, send the response to the client
if (!response.StartsWith("TIMEOUT"))
{
// Reset nRetry
nRetry = MAX_RETRIES;
if (!SendMessage(response))
{
// Couldn't send message
Close();
break;
}
}
// Wait for new input request from client
request = ReadMessage();
// If nothing was received, SslStream timeout occurred
if (String.IsNullOrEmpty(request))
{
request = "TIMEOUT";
nRetry--;
if (nRetry == 0)
{
// Close everything
Console.WriteLine("Client is unreachable. Closing client connection.");
Close();
break;
}
else
{
continue;
}
}
}
Console.WriteLine("Stopped");
}
}
public String ReadMessage()
{
if (tcpClient != null)
{
int bytes = -1;
byte[] buffer = new byte[MESSAGE_SIZE];
try
{
bytes = sslStream.Read(buffer, 0, MESSAGE_SIZE);
}
catch (ObjectDisposedException)
{
// Streams were disposed
return String.Empty;
}
catch (IOException)
{
return String.Empty;
}
catch (Exception)
{
// Some other exception occured
return String.Empty;
}
if (bytes != MESSAGE_SIZE)
{
return String.Empty;
}
// Return string read from the stream
return Encoding.Unicode.GetString(buffer, 0, MESSAGE_SIZE).Replace("\0", String.Empty);
}
return String.Empty;
}
public bool SendMessage(String message)
{
if (tcpClient != null)
{
byte[] data = CreateMessage(message);
try
{
// Write command message to the stream and send it
sslStream.Write(data, 0, MESSAGE_SIZE);
sslStream.Flush();
}
catch (ObjectDisposedException)
{
// Streamers were disposed
return false;
}
catch (IOException)
{
// Error while trying to access streams or connection timedout
return false;
}
catch (Exception)
{
return false;
}
// Data sent successfully
return true;
}
return false;
}
private byte[] CreateMessage(String message)
{
byte[] data = new byte[MESSAGE_SIZE];
byte[] messageBytes = Encoding.Unicode.GetBytes(message);
// Can't exceed MESSAGE_SIZE parameter (max message size in bytes)
if (messageBytes.Length >= MESSAGE_SIZE)
{
throw new ArgumentOutOfRangeException("message", String.Format("Message string can't be longer than {0} bytes", MESSAGE_SIZE));
}
for (int i = 0; i < messageBytes.Length; i++)
{
data[i] = messageBytes[i];
}
for (int i = messageBytes.Length; i < MESSAGE_SIZE; i++)
{
data[i] = messageBytes[messageBytes.Length - 1];
}
return data;
}
The very same ReadMessage(), SendMessage() and CreateMessage() functions are used also by the client to send messages to the server. MESSAGE_SIZE constant is also the same and it's set to 2048.
The problem was that I re-used the SSLStream after a timeout. So I solved the problem just by removing the nRetry variable and set a longer timeout. The related MSDN article says that SSLStream will return garbage after a timeout exception (https://msdn.microsoft.com/en-us/library/system.net.security.sslstream(v=vs.110).aspx):
SslStream assumes that a timeout along with any other IOException when one is thrown from the inner stream will be treated as fatal by its caller. Reusing a SslStream instance after a timeout will return garbage. An application should Close the SslStream and throw an exception in these cases.
Another issue is that Windows update KB3147458 (Windows 10 April's update) changes the something in the behaviour of the Read function. It looks like something in the SSLStream implementation changed and now it returns data in 2 parts, 1 byte and the rest of the bytes every single time. Actually the MSDN document doesn't say that the Read() function will return all the requested bytes in one step and the provided example uses a do-while loop in order to read the exact number of bytes. So I suppose that the Read() function doesn't guarantee to read the exact requested number of bytes all at once, more read iterations might be required.
SSLstream works properly so it's NOT BROKEN. You just need to pay attention and use of a do-while loop and check that all the bytes are read correctly.
I changed the code as shown here to address the bugs I had.
public String ReadMessage()
{
if (tcpClient != null)
{
int bytes = -1, offset = 0;
byte[] buffer = new byte[MESSAGE_SIZE];
try
{
// perform multiple read iterations
// and check the number of bytes received
while (offset < MESSAGE_SIZE)
{
bytes = sslStream.Read(buffer, offset, MESSAGE_SIZE - offset);
offset += bytes;
if (bytes == 0)
{
return String.Empty;
}
}
}
catch (Exception)
{
// Some exception occured
return String.Empty;
}
if (offset != MESSAGE_SIZE)
{
return String.Empty;
}
// Return string read from the stream
return Encoding.Unicode.GetString(buffer, 0, MESSAGE_SIZE).Replace("\0", String.Empty);
}
return String.Empty;
}
With regard to the SslStream returning five bytes on a Read() after a timeout, this is because the SslStream class doesn't gracefully handle any IOException from the underlying stream, and this is documented as previously noted.
SslStream assumes that a timeout along with any other IOException when one is thrown from the inner stream will be treated as fatal by its caller. Reusing a SslStream instance after a timeout will return garbage. An application should Close the SslStream and throw an exception in these cases.
https://msdn.microsoft.com/en-us/library/system.net.security.sslstream(v=vs.110).aspx
However, you can fix the problem by creating a wrapper class that sits between the Tcp NetworkStream and the SslStream which catches and suppresses the harmless timeout exception, with (seemingly) no loss of functionality.
The full code of this is in my answer on a similar thread, here https://stackoverflow.com/a/48231248/8915494
With regard to the Read() method returning only part of the payload on each Read(), your answer already fixes this correctly. While this is "recent" behaviour for SslStream, it is unfortunately expected behaviour for all networking and all code needs to create some form of buffer to store the fragments until you have a complete packet. For example, if your data exceeds 1500 bytes (the maximum packet size for most Ethernet adapters, assuming Ethernet transport), you are very likely to receive the data in multiple parts and have to reassemble it yourself.
Hope this helps

Async Server Sockets are Acting Very Strangely

I'm working on a simple debugging proxy server. Everything seems to be working fine, except 70% of requests get actually processed and in the rest I get strange data.
I have 3 functions:
private static void Listen(Object obj)
{
log("**** Listen()");
TcpListener listener = (TcpListener)obj;
try
{
while (true)
{
TcpClient client = listener.AcceptTcpClient();
while (!ThreadPool.QueueUserWorkItem(new WaitCallback(ProxyServer2.ProcessClient), client)) ;
}
}
catch (ThreadAbortException) { MessageBox.Show("ABORT EX"); }
catch (SocketException) { MessageBox.Show("SOCKET EX"); }
catch (Exception ex)
{
MessageBox.Show(ex.Message.ToString());
}
}
private static void ProcessClient(Object obj)
{
log("**** ProcessClient");
TcpClient client = (TcpClient)obj;
try
{
DoHttpProcessing(client);
}
catch (Exception ex)
{
log(ex.Message);
}
finally
{
client.Close();
}
}
private static void DoHttpProcessing(TcpClient client)
{
log("**** DoHttpProcessing");
// handle all the http stuff
}
This is where the weird part starts. When I make a request through the proxy, the request gets executed and returned, when I do it the second time, I get the last 10-30 bytes returned from the previous request.
The strangest is that when I get these garbage bytes, DoHttpProcessing IS NOT being triggered (which doesn't make sense, since it contains the streams that send back response to the browser). Something is sending back the garbage data.. but what?
It almost seems like the browser tries to fetch the new request using the same old connection? Can this be possible?
After DoHttpProcessing is triggered, all the streams are closed, so I don't understand how can server be using the old connection and get this garbage data!?!

Delay when send string via socket

I make an application in android can send character code to server C# when user input on android keyboard.
This is send method in android side:
public Boolean writeMessage(String message) {
try {
printWriter = new PrintWriter(socket.getOutputStream(), true);
printWriter.println(message);
return true;
} catch (Exception ex) {
Log.e(TAG,"write error: " +ex.getMessage());
return false;
}
}
And server listen the messages (C#):
Thread myThread = new Thread(new ThreadStart(ServeClient));
myThread.Start();
void ServeClient(){
StreamReader reader = new StreamReader(tcpClient.GetStream());
while (true)
{
try
{
String message = reader.ReadLine();
if (message != null)
{
Console.WriteLine(message);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
My code works, but when user input faster, the server delay read message in 1,2 or 3 seconds (I have test the method get character when user input, it works fine, not delay). Where is my problem? Thanks in advance!
Your problem may be caused by Nagle's algorithm reducing TCP traffic. Consider setting TCP_NODELAY on your client (and server - TcpClient.Client.NoDelay - if communication is two-way).
Edit: For java it is Socket.setTcpNoDelay method.

NamedPipeServerStream/async reliable disconnect issues

We're using named pipes to communicate between a C# .Net service and a native C++ application. The service creates a message mode pipe, then kicks off a timer.
m_pipeServer = new NamedPipeServerStream ("Cyber_Srv_EventPipe",
PipeDirection.InOut,
1,
PipeTransmissionMode.Message,
PipeOptions.Asynchronous,
4096,
4096,
pipeSa);
m_OutputQueue = new List<My_Message>();
In the timer tick routine is the main service loop, which looks like this:
do
{
if (!m_bClientAttached)
{
try
{
m_pipeServer.WaitForConnection ();
m_bClientAttached = true;
}
catch (InvalidOperationException invope)
{
sDebug = string.Format ("Pipe wait exception InvOpEx: {0}",
invope.Message);
DebugMessage (sDebug);
}
}
// the message-pumping part of the loop.
if (m_bClientAttached)
{
try
{
if (!m_bReadInProgress)
{
m_bReadInProgress = true;
m_pipeServer.BeginRead (byNewRead, 0, byNewRead.GetLength (0),
new AsyncCallback (this.PipeReadComplete),
m_iReadCount);
}
if (m_OutputQueue.Count () > 0)
{
if (!m_bWriteInProgress)
{
m_bWriteInProgress = true;
My_Message opmsg = m_OutputQueue.ElementAt (0);
m_pipeServer.BeginWrite (opmsg.ToByteArray (), 0,
(int)(opmsg.MsgLength),
new AsyncCallback (this.PipeWriteComplete),
m_iWriteCount);
}
}
}
catch (IOException ioe)
{
sDebug = string.Format ("Main loop raised exception: {1}",
ioe.Message);
DebugMessage (sDebug);
DetachClientPipe();
}
Thread.Sleep(1);
}
} while (m_bRunning);
m_pipeServer.Close ();
}
The read and write completion routines look like this:
private void PipeReadComplete (IAsyncResult iAR)
{
string sDebug;
int iByteCount;
My_Message ipmsg = new My_Message();
try
{
iByteCount = m_pipeServer.EndRead (iAR);
if (iByteCount > 0)
{
ipmsg.FromByteArray(byNewRead);
m_bReadInProgress = false;
... process message ...
}
else
{
try
{
DebugMessage ("PRC: Zero bytes read, disconnect pipe");
DetachClientPipe();
}
catch (InvalidOperationException invope)
{
sDebug = string.Format ("PRC - Pipe disconnect exception: {0}",
invope.Message);
DebugMessage (sDebug);
}
}
}
catch (IOException e)
{
sDebug = string.Format ("PRC: Read {0} raised exception: {1}",
(int)(iAR.AsyncState),
e.Message);
DebugMessage (sDebug);
DetachClientPipe();
}
}
// ------------------------------------------------------------------
private void PipeWriteComplete (IAsyncResult iAR)
{
string sDebug;
try
{
m_pipeServer.EndWrite (iAR);
lock (m_OutputQueue)
{
m_OutputQueue.RemoveAt(0);
}
m_bWriteInProgress = false;
}
catch (IOException e)
{
sDebug = string.Format ("Write {0} raised exception: {1}",
(int)(iAR.AsyncState),
e.Message);
DebugMessage (sDebug);
DetachClientPipe();
}
}
// ------------------------------------------------------------------
private void DetachClientPipe()
{
if (m_pipeServer.IsConnected)
{
m_pipeServer.Disconnect();
}
m_bClientAttached = false;
}
The client side code is known good code, re-used. So here's the problem. The client can connect fine. We then shut down the client, everything is fine. We start it up and conect again. All fine, then we close it and start it again. Boom - error 231, pipe busy. the server will now generate pipe busy errors on any connection attempt until hell freezes over, or we restart the service. Then we're back to two connections again.
I've been staring at this code for three straight days now, and I have no idea why it does this. I can't seem to see the wood for the trees, and I could use a fresh pair of eyes or three. Problem is no-one else in the team knows much of any C#.
Update
The reason this fails on the third connect attempt appears to be that on the first disconnect the PipeReadComplete returns and I get zero bytes read, so I detach the pipe and all is well. BUT... on the second disconnection, PipeReadComplete does NOT get called, so I don't force the disconnect. Weird.
Bob, for a quick fix: was wondering, have you tried setting the server instance parameter to more than 1 and see if it still fails after 2 tries? Instead of 1, put 10 and see if it will help things. Also, it will help if you post the unmanaged code as well. I'm currently doing the same thing, windows service plus unmanaged dll IPC.
m_pipeServer = new NamedPipeServerStream ("Cyber_Srv_EventPipe",
PipeDirection.InOut,
10,
PipeTransmissionMode.Message,
PipeOptions.Asynchronous,
4096,
4096,
pipeSa);
Or you actually need to have only one server pipe instance at all times?
Please see this related question for a possible answer. It appears Suma experienced and solved the same issue, and while not in C#, it should be pretty easy to translate.

Categories

Resources