Article View: borland.public.cppbuilder.internet.socket
Article #4841Re: Detecting a client disconnect
From: Paul Machiaverna
Date: Wed, 24 Nov 2004 20:20
Date: Wed, 24 Nov 2004 20:20
86 lines
7690 bytes
7690 bytes
First, I appreciate your taking the time and effort to address all of this.
The network communuication code in the application is from the days from WinShoes with minor modifications to work with Indy. Chad Z. Hower helped me a great deal in getting things working with the non-network communications friendly transmissions that have to be supported. We have serial (RS-232) devices that are connected to RS-232 to TCP/IP-Ethernet converters (device servers). One example is a device that communicates binary data at 19.2 Kbps with NO protocol. It's a raw data dump. This data varies in size, but always starts and ends with known strings, "BEGIN" and "END". The device servers packetize this data at whatever algorithm they choose. A connection to the server (INDY application) whenever data is detected on the serial port. From the server perspective, a client connects and data is read from the socket. Then this data is transferred to a receive buffer that is large enough to hold the entire (maximum) number of bytes. As data is transferred to this buffer each byte is fed through a state machine. This detects the "BEGIN" and "END", which are triggers for sending meta data back towards the device. Since timeouts must be honored (Not those related to TCP/IP), a 1/18 second timer tick is implemented. Upon each of these timer ticks, 3 things happen: 1) timeouts are checked, 2) data is received (if available) and 3) data is tranmitted (if available). Currently, this is all implemented within the context of the OnExecute event handler.
There is yet another layer of complexity to this. When the "END" is received, data processing is performed and there are some situations where a secondary transmission session is started by the server to update parameters in the device. This transmission is protocol driven using an implementation of ASTM.
We all that said, changing over to a different scheme is going to be quite a bit of work. Note that the above scheme has been working very well (extremely stable) for over 5 years. All I'm trying to add is the ability to detect a client disconnect reliably. The reason why this hasn't been an issue in the past is that the server code has been set to call DisconnectSocket after 10 seconds of inactivity. The clients (device servers) have been set to disconnect after 30 seconds of inactivity. We need to change this to setting the server to disconnect after 60 seconds of inactivity. So, the client will disconnect first (normally) and the server side timeout is just a safety. In the case of the server detecting "inactivity", all this means is that it hasn't seen a "BEGIN" within 60 seconds.
Supporting the old transmissions is a pain at best in these days of packetized protocols. We (my company) had called in a few different consultants to talk about how to support our legacy devices in network communications. None of them could tell us how to do it. We had to figure it out on our own with a lot of help from Chad. I'm sure you (Gambit) were involved with some of those message threads and I thank both of you, again, for all your input.
Paul Mac
"Remy Lebeau \(TeamB\)" <no.spam@no.spam.com> wrote:
>
>"Paul Machiaverna" <paul.machiaverna@i-stat.com> wrote in message
>news:41a4e2b4$1@newsgroups.borland.com...
>
>> It has been my understanding that OnExecute (IdTCPServer1Execute)
>> is simply a "start" event much like that of a TThread->Execute, where
>> you stay in the method for as long as it takes to get the task completed
>> and then let that method return (thread execution ends).
>
>That is not correct. It is true that TIdTCPServer.OnExecute is where your
>socket reading/writing should occur. However, it is common practice in
>threaded socket programming to loop the threaded code, which is why the
>OnExecute event is itself looped internally instead of requiring the
>programmer to code his own loop inside the event handler. The
>TIdTCPServer.OnExecute code should performing the operations for only a
>single iteration of TIdTCServer's looping.
>
>> I was calling Readable() to check if there was something to read
>> and then call a read data method.
>
>You should call just the reading method by itself and not Readable() at all.
>The reading method will wait for data to actually arrive before it returns.
>
>> Of course, readable will return false when the client disconnects
>
>Actually, it will return True. A socket becomes readable when the other
>party disconnects. The reading code then immediately returns 0 bytes
>afterwards. That is how blocking sockets indicate disconnects. Indy
>already handles that condition, but you are not seeing it happen because you
>are not using Indy correctly to begin with. See below.
>
>> if ( AThread->Connection->Socket->Binding->Readable( 1 ) )
>> {
>> // Read it.
>> int liCount =
>> AThread->Connection->Socket->Binding->Recv(
>> lpbyBuffer, 1000, 0 );
>> }
>
>Why are you calling Recv() directly? You should be using TIdTCPConnection's
>ReadBuffer() method instead. You are completely bypassing everything that
>Indy implements for you. If you are going to use that kind of code, then
>you may as well just use the WinSock API directly and not use Indy at all.
>You are not benefitting from Indy's extensive socket implementations at all.
>
>> If Recv() isn't called, the client disconnect isn't detected (no exception
>thrown).
>
>Recv() doesn't throw any exceptions to begin with. It is a direct wrapper
>for the WinSock recv() function with no error checking performed. That is
>what the rest of the Indy library is for, but you are not utilizing that
>support at all.
>
>> What I need is another way to read binary data that will return
>> the number of bytes read.
>
>Call TIdTCPConnection's ReadFromStack() method and then check the Size of
>the InputBuffer property.
>
>> Unfortunately, I have no way of knowing in advance how much the client
>> is going to send other than knowing that it won't be more than 18K bytes.
>
>Why not? What kind of data are you receiving to begin with? How are you
>going to know where one packet ends and the next packet begins? Or are you
>only receiving a single packet of data and then the client disconnects? If
>that is the case, then you could use TIdTCPConnection's ReadStream() method.
>It has an AReadUntilDisconnect parameter.
>
>
>Gambit
>
>
Technical Details
Message-ID:
<41a4fb02$1@newsgroups.borland.com>Path:
arc1-ca.pugleaf.net!g2news1.google.com!news2.google.com!proxad.net!news.tele.dk!news.tele.dk!small.news.tele.dk!newsfeed.multikabel.nl!news2.euro.net!216.196.110.149.MISMATCH!border2.nntp.ams.giganews.com!nntp.giganews.com!pe2.news.blueyonder.co.uk!blueyonder!news-peer-test!btnet!newsfeed.bt.es!caladan.landsraad.net!newsgroups.borland.com!not-for-mailReferences:
<41a3a222$1@newsgroups.borland.com> <41a3a429@newsgroups.borland.com> <41a4aed9$3@newsgroups.borland.com> <41a4d9d0$1@newsgroups.borland.com> <41a4e2b4$1@newsgroups.borland.com> <41a4f0e2@newsgroups.borland.com>Show Full Headers
Complete Article Headers
X-Google-Thread: 11508e,2bbc0c2eefeb0788 X-Google-Attributes: gid11508e,public X-Google-Language: ENGLISH,ASCII-7-bit From: "Paul Machiaverna" <paul.machiaverna@i-stat.com> Sender: "Paul Machiaverna" <paul.machiaverna@i-stat.com> Reply-To: "Paul Machiaverna" <paul.machiaverna@i-stat.com> Subject: Re: Detecting a client disconnect Newsgroups: borland.public.cppbuilder.internet.socket X-User-Info: 130.36.11.141 References: <41a3a222$1@newsgroups.borland.com> <41a3a429@newsgroups.borland.com> <41a4aed9$3@newsgroups.borland.com> <41a4d9d0$1@newsgroups.borland.com> <41a4e2b4$1@newsgroups.borland.com> <41a4f0e2@newsgroups.borland.com> NNTP-Posting-Host: 207.105.83.66 Message-ID: <41a4fb02$1@newsgroups.borland.com> Date: 24 Nov 2004 13:20:02 -0700 X-Trace: newsgroups.borland.com 1101331202 207.105.83.66 (24 Nov 2004 13:20:02 -0700) Lines: 87 Path: arc1-ca.pugleaf.net!g2news1.google.com!news2.google.com!proxad.net!news.tele.dk!news.tele.dk!small.news.tele.dk!newsfeed.multikabel.nl!news2.euro.net!216.196.110.149.MISMATCH!border2.nntp.ams.giganews.com!nntp.giganews.com!pe2.news.blueyonder.co.uk!blueyonder!news-peer-test!btnet!newsfeed.bt.es!caladan.landsraad.net!newsgroups.borland.com!not-for-mail