Article View: borland.public.cppbuilder.internet.socket
Article #379TClientSocket handling a bad connection
From: Lesley Anne
Date: Mon, 31 Mar 2008 22:34
Date: Mon, 31 Mar 2008 22:34
123 lines
5982 bytes
5982 bytes
(BCB6)
I have two apps, one using TClientSocket, one using TServerSocket, both in
non-blocking mode. Across a LAN, it works. Across a WAN, it sometimes
works, but we get the following failure about once each day:
1) Client tries to connect to the server.
Both Client and Server get OnConnect event.
2) Client calls SendText to send a message to the server.
Server sees nothing.
Client gets OnError event with: ErrorEvent == eeSend, ErrorCode == 10038
(WSAENOTSOCK)
Within the OnError event handler, Client calls Socket->Close()
No OnDisconnect events occur, and Client remains Active.
3) Every second, the Client calls SendText a few more times.
Nothing reaches the server.
4) After 5 minutes, the server times out, deciding that this connection
(which it hasn't received anything on) is bad, so closes it.
Server gets OnDisconnect event.
Client sees nothing.
5) Client (which is still Active and has never gotten an OnDisconnect event)
continues trying to send on this connection which had never worked properly
and which now no longer even exists at the server's end.
I think part of the fix is likely to be that I should redesign the client
app to be multi-threaded so that I can use blocking sockets. That way at
least the client will be able to recognize that the SendText didn't work in
time for me to avoid removing the message from the FIFO queue I use for
spooling messages that need to be sent. That's more of a symptomatic fix,
though. It doesn't really address the issue of why the error is occurring
in the first place.
Both sides of the connection did see the OnConnect event. Shouldn't that
indicate that the connection was established successfully? So why does the
client get the WSAENOTSOCK error when it tries to send? And why does it
never get the OnDisconnect event? If the connection is down, how can I
force the client to recognize that it's down, so that I can stop sending and
try to reconnect until I get a working connection? (Calling Socket->Close
from the OnError event was an attempt to do this. I was hoping that would
bring down the client side of the non-functioning "connection", so I could
re-establish it.)
I'm not quite sure which is the most relevant part of the code, but sending
is where the error occurs, so here's where I get to the SendText call from
the client. I could include other parts of the source, but they don't do
much. The OnConnect and OnDisconnect events just update status indicators
on the screen and write to a logfile to let me know they happened. The
OnError event does the same, plus calls Socket->Close() as I already
mentioned.
(BESpoolHead is a global pointer to the first node in a linked list. It's a
FIFO queue of messages that need to be sent.)
// -----------------------------------------------------------------------
void __fastcall TCnamForm::PerSecondTimer(TObject *Sender)
{
TStringSpoolNode *TempNode;
for (int i=0; BESpoolHead && (i<500); i++) {
if (SendToBE(BESpoolHead->Data)) {
TempNode = BESpoolHead->Link;
delete BESpoolHead;
BESpoolHead = TempNode;
}
else break;
}
}
// -----------------------------------------------------------------------
bool TCnamForm::SendToBE(AnsiString Message)
{
bool Success = false;
if (BEClientSocket->Active) {
try {
BEClientSocket->Socket->SendText(Message + "\n");
Success = true;
}
catch (Exception &E) {
LogMessage("ERROR Sending to Back End. Exception: " + E.Message);
}
}
return Success;
}
// -----------------------------------------------------------------------
One of my problems here is that, since I'm in non-blocking mode, that
try-catch around SendText isn't really doing anything very useful. That's
why I think I need to redesign this to use blocking sockets, so I can see
whether the send really was successful before deciding whether I can take
the message off of the spool.
Oh, here's another part of the code that looks relevant. I have a timer
that runs continuously and re-establishes the connection if it's down and
needs to be up. (The BEIndicator->Brush->Color it references gets set to
clLime during OnConnect and set to clRed in either the OnError or
OnDisconnect event. NeedBEConnect is a global bool which is true throughout
the time that all this is happening.)
// -----------------------------------------------------------------------
void __fastcall TCnamForm::ReconnectTimerTimer(TObject *Sender)
{
bool BackEndIsDown = ((!BEClientSocket->Active) ||
(BEIndicator->Brush->Color != clLime));
if (NeedBEConnect && BackEndIsDown) {
try {
BEClientSocket->Close();
BEClientSocket->Open();
}
catch (Exception &E) {
LogMessage("ERROR Opening Back End Socket. Exception: " +
E.Message);
}
}
}
// -----------------------------------------------------------------------
Technical Details
Message-ID:
<47f16766$1@newsgroups.borland.com>Path:
arc1-ca.pugleaf.net!g2news1.google.com!news3.google.com!proxad.net!feeder1-2.proxad.net!194.25.134.126.MISMATCH!newsfeed01.sul.t-online.de!t-online.de!newsgroups.borland.com!not-for-mailShow Full Headers
Complete Article Headers
X-Google-Thread: 11508e,74b475fd14f26423,start X-Google-Attributes: gid11508e,domainid0,public,usenet X-Google-Language: ENGLISH,ASCII-7-bit From: "Lesley Anne" <mspfila (dash) brl (at) yahoo (dot) com> Newsgroups: borland.public.cppbuilder.internet.socket Subject: TClientSocket handling a bad connection Date: Mon, 31 Mar 2008 18:34:12 -0400 Lines: 125 X-Priority: 3 X-MSMail-Priority: Normal X-Newsreader: Microsoft Outlook Express 6.00.2900.3138 X-RFC2646: Format=Flowed; Original X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2900.3198 NNTP-Posting-Host: 144.160.5.25 Message-ID: <47f16766$1@newsgroups.borland.com> X-Trace: newsgroups.borland.com 1207002982 144.160.5.25 (31 Mar 2008 15:36:22 -0700) Path: arc1-ca.pugleaf.net!g2news1.google.com!news3.google.com!proxad.net!feeder1-2.proxad.net!194.25.134.126.MISMATCH!newsfeed01.sul.t-online.de!t-online.de!newsgroups.borland.com!not-for-mail