I've got an app that downloads from several concurrent threads.
Occasionally, I get an expcetion trying to read the HttpWebResponse
stream...
Sorry, the code isn't short, but I figured best to provide the whole method.
This is run within its own thread. "Job" is a class that receives the
information about the downloaded pages. The exception happens on the read
where it says "EXCEPTION HERE"
private static void DownloadPage(Job job)
{
HttpWebRequest req = null;
try
{
Debug.WriteLine("Beginning HTTP request of: " + job.URL);
req = (HttpWebRequest) HttpWebRequest.Create(job.URL);
req.UserAgent = _browserID;
if (job.Referrer != null)
{
req.Referer = job.Referrer;
}
req.CookieContainer = job.Cookies;
req.Timeout = _timeout;
}
catch(UriFormatException ex)
{
job.Status = JobStatus.Error;
job.ReportError(-1, ex.Message);
_threadMgr.RemoveJob(job);
return;
}
try
{
job.BeginDownload();
using (HttpWebResponse resp = req.GetResponse() as HttpWebResponse)
{
using (Stream pageStream = resp.GetResponseStream())
{
byte[] readBuffer = new byte[BUFFERSIZE];
byte[] retBuffer = null;
int readCount = -1;
int lastReadCount = -1;
// EXCEPTION HERE
while ((readCount = pageStream.Read(readBuffer, 0,
BUFFERSIZE)) 0)
{
if (retBuffer == null)
{
retBuffer = new byte[readCount];
for(int index = 0; index < retBuffer.Length;
index++)
{
retBuffer[index] = readBuffer[index];
}
lastReadCount = readCount;
}
else
{
byte[] tempBuffer = new byte[readCount +
retBuffer.Length];
int index = 0;
for(index = 0; index < retBuffer.Length; index++)
{
tempBuffer[index] = retBuffer[index];
}
for(index = 0; index < readCount; index++)
{
tempBuffer[index + retBuffer.Length] =
readBuffer[index];
}
retBuffer = tempBuffer;
lastReadCount = readCount;
}
if (retBuffer != null)
{
job.UpdateProgress(retBuffer);
}
}
Thread.Sleep(100);
job.SetData(retBuffer);
job.Status = JobStatus.CompletedSuccessful;
job.Enabled = false;
job.DownloadComplete();
_threadMgr.RemoveJob(job);
}
}
}
catch(WebException ex)
{
job.Status = JobStatus.Error;
job.ReportError((int) ((HttpStatusCode) ex.Status), ex.Message);
job.Enabled = false;
job.SetData(null);
_threadMgr.RemoveJob(job);
}
catch(Exception ex)
{
Debug.WriteLine("Unexpected Exception: " + ex.Message);
job.Status = JobStatus.Error;
job.ReportError(-1, ex.Message);
job.Enabled = false;
_threadMgr.RemoveJob(job);
}
lock(_oldThreads.SyncRoot)
{
_oldThreads.Add(Thread.CurrentThread);
}
job.ExecutingThread = null;
}
The outer exception is an "Unable to read data from the transport
connection". The inner is a null referenceexception that has the following
stack:
StackTrace "
at System.Net.OSSOCK.closesocket(IntPtr socketHandle)\r\n
at System.Net.Sockets.Socket.Dispose(Boolean disposing)\r\n
at System.Net.Sockets.Socket.System.IDisposable.Dispo se()\r\n
at System.Net.Sockets.Socket.Close()\r\n
at System.Net.Sockets.NetworkStream.Dispose(Boolean disposing)\r\n
at System.Net.Sockets.NetworkStream.System.IDisposabl e.Dispose()\r\n
at System.Net.Sockets.NetworkStream.Close()\r\n
at System.Net.Connection.CloseConnectionSocket(WebExc eptionStatus status,
ConnectionReturnResult& returnResult)\r\n
at System.Net.Connection.HandleError(WebExceptionStat us webExceptionStatus,
ConnectionFailureGroup failureGroup, ConnectionReturnResult&
returnResult)\r\n
This ends up eventually causing a Win32 exception and I can't seem to catch
it and bring my whole app crashing down.
I'm assuming closesocket is dying on this line:
int num = UnsafeNclNativeMethods.OSSOCK.closesocket(this.m_H andle);
and I suspect m_Handle is what's null and that must be causing the unhandled
Win32 exception
Is there any way around this? Am I just doing something wrong???
As for all the byte at a time copying of the arrays, I send the array back
to the GUI thread via the job.UpdateProgress(retBuffer). To keep the GUI
from stepping on the arrays used during the download, I'm simply creating a
new copy of the array for the gui... There's probably a faster way to copy
them, but this doesn't seem too slow...
Anyway, please, if you have any ideas, I'd like to hear them. This is
driving me nuts.