Newsgroups : Borland : borland.public.delphi.internet.winsock : 2006 Apr : Re: Connection lost due to "connection reset by peer"-error
| Subject: | Re: Connection lost due to "connection reset by peer"-error |
| Posted by: | "Remy Lebeau (TeamB)" (no.spam@no.spam.com) |
| Date: | Mon, 24 Apr 2006 13:32:03 |
"Shiva" <shiva@gonzo.com> wrote in message
news:444ba933@newsgroups.borland.com...
> I'm writing a program that intercepts and manipulates certain
> newsgroups messages. It acts as a "gateway" between a client
> like Outlook Express (OE) and the newsserver of the ISP.
Is there any particular reason why you are using TIdTCPServer and
TIdTCPClient directly for that instead of TIdMappedPortTCP? It does all of
the forwarding work back and forth for you automatically.
> The (current test-)program has a TIdTCPServer component and is
> being tested with OE. It works well, but OE causes an "connection
> reset by peer" exception if the user tries to refresh the headers of a
> newsgroup and suddenly moves to another newsgroup while OE had
> not finished receiving all the headers.
That suggests to me that OE is simply disconnecting the socket abnormally on
its end so that it can abort the header download as fast as possible, and is
then reconnecting to the server with a new socket so that its connection
state is clean for the next group. A dirty hack at best, but since when is
Microsoft known for clean and reliable programming? ;-)
There is nothing you can do about it in your server, other than to let the
exception happen, and don't block it so that it escapses back into
TIdTCPServer so it can clean up the lost connection.
> The exception causes the server-client connection to be disconnected (?).
As it should be. The connection was lost on OE's side, so the server has to
close its side of the now-invalid socket.
> But now the problem: OE does not reestablish a connection!
Then that is OE's problem. That is not an Indy problem.
> OE displays the message "The TCP/IP connection was unexpectedly
> terminated by the server"
Which is not true. The "peer" in the exception means that the connection
was lost on OE's side, not the server's side. Which doesn't surprise methat
OE would be buggy, since most Microsoft software is buggy.
> Here's the source of my test-program:
All I can tell you right now is that your code is not thread-safe, not even
close. You need to serious re-write your code to be safer to multiple
threads, or else unforseen things can happen. For example:
interface
uses Forms, IdTCPClient, IdTCPServer, IdThreadMgrPool;
type
TMyNNTPThread = class(TIdPeerThread)
private
fClient: TIdTCPClient;
public
constructor Create(ACreateSuspended: boolean True); override;
destructor Destroy; override;
procedure Connect(const AHost: String; APort: Integer);
property OutboundClient: TIdTCPClient read fClient;
end;
TForm1 = class(TForm)
IdTCPServer1: TIdTCPServer;
IdThreadMgrPool1: TIdThreadMgrPool;
procedure IdTCPServer1Connect(AThread: TIdPeerThread);
procedure IdTCPServer1Exception(AThread: TIdPeerThread;
AException: Exception);
procedure IdTCPServer1Disconnect(AThread: TIdPeerThread);
procedure IdTCPServerExecute(AThread: TIdPeerThread);
public
{ Public declarations }
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
end;
var
Form1: TForm1;
procedure LogMessage(aMess: string);
implementation
uses IdThreadSafe;
{$R *.dfm}
type
TLogFile = class(TIdThreadSafe)
private
fLog: textfile;
public
constructor Create; override;
destructor Destroy; override;
procedure Write(const AMsg: String);
end;
var
LogFile: TLogFile = nil;
constructor TLogFile.Create;
begin
inherited Create;
assignfile(fLog, 'c:\test.txt');
rewrite(fLog);
end;
destructor TLogFile.Destroy;
begin
Lock;
try
closefile(fLog);
finally
Unlock;
end;
inherited Destroy;
end;
procedure TLogFile.Write(const AMsg: string);
begin
Lock;
try
writeln(fLog, Format('(%10u) %s', [GetCurrentThreadId(),
AMsg]));
finally
Unlock;
end;
end;
constructor TMyNNTPThread.Create(ACreateSuspended: boolean True);
begin
fClient := TIdTCPClient.Create(nil);
inherited Create(ACreateSuspended);
end;
destructor TMyNNTPThread.Destroy;
begin
FreeAndNil(fClient);
inherited Destroy;
end;
procedure TMyNNTPThread.Connect(const AHost: String; APort: Integer);
var
s: String;
begin
fClient.Host := AHost;
fClient.Port := APort;
fClient.Connect;
s := fClient.ReadLn;
Connection.WriteLn(s);
LogFile.Write('Connect='+ s);
end;
constructor TForm1.Create(AOwner: TComponent);
begin
IdTCPServer1.ThreadClass := TMyNNTPThread;
IdTCPServer1.Active := true;
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
IdTCPServer1.Active := false;
end;
procedure TForm1.IdTCPServer1Connect(AThread: TIdPeerThread);
begin
TMyNNTPThread(IdTCPClient1).Connect('somehost', 12345);
end;
procedure TForm1.IdTCPServer1Exception(AThread: TIdPeerThread;
AException: Exception);
begin
LogFile.Write('Error=' + AException.Message);
end;
procedure TForm1.IdTCPServer1Disconnect(AThread: TIdPeerThread);
begin
LogFile.Write('Disconnected');
end;
procedure TForm1.IdTCPServer1Execute(AThread: TIdPeerThread);
var
Command, RespPlanet: string;
I: Integer;
LThread: TMyNNTPThread;
begin
LThread := TMyNNTPThread(AThread);
Command := LThread.Connection.ReadLn;
LThread := LThread.OutboundClient.WriteLn(Command);
LogFile.Write('command outlook=' + Command);
I := Pos(' ', Command);
if I > 0 then
Command := Copy(Command, 1, I-1);
if AnsiSameText('ARTICLE', Command) or AnsiSameText('XOVER',
Command) then
begin
repeat
RespPlanet := LThread.OutboundClient.ReadLn;
LogFile.Write('LOOP response planet =' + RespPlanet);
if not LThread.Stopped then
LThread.Connection.WriteLn(RespPlanet);
until RespPlanet = '.';
end
else begin
RespPlanet := LThread.OutboundClient.ReadLn;
LogFile.Write('response planet=' + RespPlanet);
LThread.Connection.WriteLn(RespPlanet);
end;
end;
initialization
LogFile := TLogFile.Create;
finalization
FreeAndNil(LogFile);
end.
Gambit