delphi - TIdTCPServer not able to send data after re-connection of client -
i using tidtcpserver in application. here hardware acting tcp client. client establishes connection syn command (observed in wire shark tool). application has multiple clients every client connects server. first time connection, data sending & receiving fine. when hardware power off & on happens, server not able send data, hardware, until application restart. following observations regarding this:
1.when first time client connects syn seq no = 0 received, syn ack seq no = 1 send client server
2.data sending & receiving working fine
3.hardware power off happened
4.in command prompt using “netstat” observed there connection established disconnected ip & port number.
5.i send data (in wire shark displayed 6 times retransmission)
6.after in “command prompt” corresponded connection established data not appeared
7.i send data client "connection closed" exception raised idtcpserver (after exception, in on except, closed connection using connection.disconnect in code & deleted particular client locklist of idtcpserver.)
8.hardware powered on & send syn seq no = 0
9.in wire shark syn ack seq no 45678452 sent hardware
10.after in command prompt connection establishment observed
11.i tried send data client, “locklist” not updated client ip& port again data not sent client (my code if ip not present in “locklist” not sending data). there solutions?
following code:
try count := 0 frmtcpserver.idtcpserver1.contexts.locklist.count - 1 begin if tidcontext(frmtcpserver.idtcpserver1.contexts.locklist.items[count]).binding.peerip = destination_ip begin destinationipidx := count; end; end; frmtcpserver.idtcpserver1.contexts.unlocklist; if destinationipidx > -1 begin // sending data here tidcontext(frmtcpserver.idtcpserver1.contexts.locklist.items[destinationipidx]) .connection.iohandler.write(tempbuf, noofbytestosend,0); end; end; on e: eidexception begin tidcontext(frmtcpserver.idtcpserver1.contexts.locklist.items[destinationipidx]).connection.disconnect; frmtcpserver.idtcpserver1.contexts.locklist.delete(destinationipidx); end;
you calling contexts.locklist() way many times. contexts list protected critical section. calls locklist() , unlocklist() must balanced or deadlock server, preventing clients connecting , disconnecting.
locklist() returns actual list. so, should lock once, access items needed, , unlock once.
try more instead:
list := frmtcpserver.idtcpserver1.contexts.locklist; try := 0 list.count - 1 begin ctx := tidcontext(list[i]); if ctx.binding.peerip = destination_ip begin // sending data here try ctx.connection.iohandler.write(tempbuf, noofbytestosend, 0); except on e: eidexception begin ctx.connection.disconnect; end; end; break; end; end; frmtcpserver.idtcpserver1.contexts.unlocklist; end; that being said, if server's onexecute event communicating , forth client not safe directly send data client outside of client's onexecute event, doing. risk corrupting communications. safer give each client context own thread-safe queue of outgoing data, , use onexecute event send data when safe so. example:
type tmycontext = class(tidservercontext) public queue: tthreadlist; ... constructor create(aconnection: tidtcpconnection; ayarn: tidyarn; alist: tthreadlist = nil); override; destructor destroy; override; end; pidbytes := ^tidbytes; constructor tmycontext.create(aconnection: tidtcpconnection; ayarn: tidyarn; alist: tthreadlist = nil); begin inherited; queue := tthreadlist.create; end; destructor tmycontext.destroy; var list: tlist; i: integer; begin list := queue.locklist; try := 0 list.count-1 begin pidbytes(list[i])^ := nil; dispose(list[i]); end; queue.unlocklist; end; queue.free; inherited; end; procedure tfrmtcpserver.formcreate(sender: tobject); begin idtcpserver1.contextclass := tmycontext; end; procedure tfrmtcpserver.idtcpserver1execute(acontext: tidcontext); var queue: tlist; tmplist: tlist; i: integer; begin ... tmplist := nil; try queue := tmycontext(acontext).queue.locklist; try if queue.count > 0 begin tmplist := tlist.create; tmplist.assign(queue); queue.clear; end; tmycontext(acontext).queue.unlocklist; end; if tmplist <> nil begin := 0 tmplist.count-1 begin acontext.connection.iohandler.write(pidbytes(tmplist[i])^); end; end; if tmplist <> nil begin := 0 tmplist.count-1 begin pidbytes(tmplist[i])^ := nil; dispose(tmplist[i]); end; end; tmplist.free; end; ... end; var list: tlist; ctx: tidcontext; i: integer; data: pidbytes; begin list := idtcpserver1.contexts.locklist; try := 0 list.count - 1 begin ctx := tidcontext(list[i]); if ctx.binding.peerip = destination_ip begin new(data); try data^ := copy(tempbuf, 0, noofbytestosend); tmycontext(ctx).queue.add(data); except data^ := nil; dispose(data); end; break; end; end; end; idtcpserver1.contexts.unlocklist; end;
Comments
Post a Comment