I have a c# application with the following requirements.
- Periodically(700ms) send data to a cgi using a GET.
- The server will respond with only the GET string sent as confirmation.
- Values sent are constantly changing and are not stored, ordered, or retried.
- Only one connection made to the server at a time.
- Timer events that find a previous connection still in progress should simply exit quietly and let the next event carry on.
The client machine is Windows Server 2012. The HTTP server is a black box appliance(believed to be running linux). Environment is low-latency production with extremely tight security(network/policies/etc).
The problem: Periodically, the client will begin throwing exceptions
"The operation timed out"
and the drip feed stops. Simultaneously, Wireshark shows
no connections being made from the client to the server.
However, VisualStudio shows that
every 700ms the client is attempting to connect and is timing out.
When it's not throwing the above exception, it seems to work fine. At no time does the HTTP server appear to be rejecting connections. Sometimes the client will recover, most of the time it will continue to throw exceptions until restarted. AppDomain thread pool is stable. Memory consumption is fine.
To confuse matters, I have identical hardware/software/network without the security in a lab where everything runs flawlessly for days at a time. My code is being fingered as "malfunctory".
I have recently discovered that the HttpWebRequest.Timeout
property bounds the entire life of the transaction, not just the response wait. I am increasing this and it's currently under test.
Anyone see anything glaring(or otherwise) that would cause this problem in the below code?
// timer call back at 700ms interval
void m_postTimer_Elapsed(object sender, ElapsedEventArgs e)
{
try
{
if (Interlocked.Read(ref this.m_isLocked) == 0)
{
if (Monitor.TryEnter(this.m_lock, 10))
{
Interlocked.Exchange(ref this.m_isLocked, 1);
try
{
// value1 & value2 set elsewhere
string url = String.Format("http://1.1.1.1/set.cgi?value1={0}&value2={1}", value1, value2);
this.m_post = (HttpWebRequest)WebRequest.Create(url);
this.m_post.Timeout = 500;
this.m_post.Credentials = new NetworkCredential(this.user, this.pass);
WebResponse response = this.m_post.GetResponse();
response.Close();
Monitor.Exit(this.m_lock);
Interlocked.Exchange(ref this.m_isLocked, 0);
}
catch (WebException ex)
{
// handle web exceptions
// if we've locked earlier and hit an exception,
// the unlock has been skipped. unlock
if (Interlocked.Read(ref this.m_isLocked) > 0)
{
Monitor.Exit(this.m_lock);
Interlocked.Exchange(ref this.m_isLocked, 0);
}
}
}
}
else
{
// indicate that a pre-existing connection is still in progress
}
}
catch (Exception ex)
{
// handle generic exception
// if we've locked earlier and hit an exception,
// the unlock has been skipped. unlock
if (Interlocked.Read(ref this.m_isLocked) > 0)
{
Monitor.Exit(this.m_lock);
Interlocked.Exchange(ref this.m_isLocked, 0);
}
}
}