No route to host (was: Multiplexed Server-nClient architecture) lazarus / 38-Networking and Web Programming ---------------------------------------------------------------------- Ocye · 2012-03-23 12:41 I was running a server with multiple threaded clients corresponding to Synapse's echo demo for some time. But due to changes in data management (and since Linux supports IMHO a maximum of 40 threads per default) I want to change to a multiplexed design. Registration and simple pass through messages work fine. But client's free isn't called until server shutdown. Am I completely wrong with my approach? Code: [Select]TClient=class(TClientInfo)     private       FClientSocket: TTCPBlockSocket;//Synapse       procedure DoStatus(Sender: TObject; Reason: THookSocketReason; const Value: string);     protected       ParentList  : TList; //link to server.clients     public       constructor Create(aSocket:TSocket; aParentList:TList);       destructor Destroy; override;     end; constructor TClient.Create(aSocket: TSocket; aParentList:TList); begin   inherited Create('');   Release:='0.0';   FClientSocket:=TTCPBlockSocket.Create;   FClientSocket.Socket:=aSocket;   FClientSocket.OnStatus:=@DoStatus;   ParentList:=aParentList; end; destructor TClient.Destroy; var   i:integer; begin   writeln(DateTimeToStr(Now),': ',PlayerName,' freed');   FreeAndNil(FClientSocket);   i:=ParentList.IndexOf(self);   if i>-1 then     ParentList.Delete(i);   inherited Destroy; end; procedure TClient.DoStatus(Sender: TObject; Reason: THookSocketReason; const Value: string); begin   if (Reason=HR_SocketClose) then //and assigned(FClientSocket) then   begin     Free;   end; end; Code: [Select]  TCustomTCPServer=class(TThread)     private       FClients  : TList;       FServerSocket  : TTCPBlockSocket; //      FRecvMsg=class(TStringList) -> Values='Sender','Receiver','MessageType','Content' etc.     protected     public       constructor Create(aPort:string);       procedure Execute; override;       property Clients : TList read FClients write FClients;     end; constructor TCustomTCPServer.Create(aPort:string); begin   inherited Create(true);   FServerSocket:=TTCPBlockSocket.Create; //  FServerSocket.EnableReuse(true);   FreeOnTerminate:=true;   FClients:=TList.Create;   Start;//Resume; end; procedure TCustomTCPServer.Execute; var   i,j:integer;   aSender,aReceiver:TClient; begin   FServerSocket.Bind('0.0.0.0', FPort);   //FServerSocket.SetLinger(true, 10);   if FServerSocket.LastError=0 then   begin     FServerSocket.Listen;     while not Terminated do     begin       if FServerSocket.CanRead(100) then       begin         aSender:=TClient.Create(FServerSocket.Accept, FClients);         FClients.Add(aSender);       end;       for i:=0 to FClients.Count-1 do       begin         aSender:=TClient(FClients[i]);         if aSender.ClientSocket.CanRead(10) then         begin           FRecvMsg.DelimitedText:=aSender.ClientSocket.RecvString(1000);           DoSomeThingWithMsg();           for j:=0 to FClients.Count-1 do           begin             aReceiver:=TClient(FClients[j]);             aReceiver.ClientSocket.SendString(FRecvMsg.DelimitedText+CRLF);           end;//for to j         end;       end; //for to i     end;//Terminated   end else     Terminate;//FSocket.LastError<>0 end; Code: [Select]type   TTCPServer=class(TCustomTCPServer)   private     mysql stuff end;   with TTCPServer.Create(cPort,_user,_passwd,_database) do   try     repeat       sleep(10);     until KeyPressed;   finally     Free; //TCPServer   end; ---------------------------------------------------------------------- marcov · 2012-03-23 13:11 I don't know synapse very well, but how long did you wait? TCP/IP timeouts are typically 8-10 minutes. ---------------------------------------------------------------------- Ocye · 2012-03-23 14:11 Client's socket fires HR_SocketClose² event which is connected  (FClientSocket.OnStatus:=@DoStatus;). That was working well in threaded environment. [2] Ararat doc ---------------------------------------------------------------------- ludob · 2012-03-23 20:11 The HR_SocketClose is triggered when the socket is closed. In TClient you wait for HR_SocketClose to close the socket which will never happen. When the remote closes its side of the connection you'll get an error status when trying to send or receive something on the second. This error condition does not trigger a HR_SocketClose. Canread calls select which doesn't not return error information but when a the remote side closes the connection, it will trigger the select for that socket. The next recv will return 0 however and synapse will report WSAECONNRESET . What you need to do is to check for WSAECONNRESET after aSender.ClientSocket.RecvString(1000) and close the socket if true. You should also test for the same error after aReceiver.ClientSocket.SendString(FRecvMsg.DelimitedText+CRLF) because there you can also encounter closed sockets. ---------------------------------------------------------------------- Ocye · 2012-03-24 16:48 Quote from: ludob on March 23, 2012, 09:11:22 pmWhat you need to do is to check for WSAECONNRESET after RecvString(1000)..That works, At least I recognize when a client has been disconnected gracefully. Thanks! ---------------------------------------------------------------------- Ocye · 2012-04-15 10:28 I attach my new issue to this thread because I believe its related to the architecture. With my first multithreaded approach I didn't run into that trouble. My service has some hiccups. It runs well for several hours but delays all traffic for about 10-15min sometimes. My logging points to a routing problem and some other strange (following) errors. QuoteScrabble3D [2012-04-14 23:53:05.563 Debug] HR_ReadCount 50 (udostt) Scrabble3D [2012-04-14 23:53:05.577 Info] : udostt->all: nwRefresh (13ms) Scrabble3D [2012-04-15 00:05:08.283 Debug] HR_WriteCount 1222 (PC WINDOS) Scrabble3D [2012-04-15 00:05:08.283 Debug] HR_ERROR 113,No route to host (PC WINDOS) Scrabble3D [2012-04-15 00:05:08.285 Error] PC WINDOS:No route to host in 722707ms] Scrabble3D [2012-04-15 00:05:08.286 Debug] HR_WriteCount 1486 (udostt) Scrabble3D [2012-04-15 00:05:08.288 Debug] HR_WriteCount 1486 (bummi2005) Scrabble3D [2012-04-15 00:05:08.289 Debug] HR_ERROR 32,Other Winsock error (32) (Petronella) Scrabble3D [2012-04-15 00:05:08.290 Error] Petronella:Other Winsock error (32) in 1ms] Scrabble3D [2012-04-15 00:05:08.291 Debug] HR_WriteCount 1486 (Linuxbussinchen) Scrabble3D [2012-04-15 00:05:08.292 Debug] HR_WriteCount 1486 (opdio) Scrabble3D [2012-04-15 00:05:08.292 Debug] HR_ERROR 32,Other Winsock error (32) (Karl_B) The player with name "PC WINDOS" is located in Tunesia so a "no route to host" makes sense. But how can I catch this issue before the delay? And, what does HR_ERROR 32 means? Should I care about? I believe players have been logged out and in again (they couldn't know whether server or client is responsible for a hiccup) and socket isn't available anymore. Minutes later I got a further delay but I don't have any idea for what reason. QuoteScrabble3D [2012-04-15 00:05:10.968 Info] : manou->group: nwSyncNewGame (1ms) Scrabble3D [2012-04-15 00:05:10.971 Debug] HR_WriteCount 1148 (manou) Scrabble3D [2012-04-15 00:05:11.143 Debug] HR_CanRead  (manou) Scrabble3D [2012-04-15 00:05:11.147 Info] : manou->group: nwSyncNewGame (2ms) Scrabble3D [2012-04-15 00:21:27.863 Debug] HR_WriteCount 478 (manou) Scrabble3D [2012-04-15 00:21:27.864 Debug] HR_ERROR 110,Connection timed out (manou) Scrabble3D [2012-04-15 00:21:27.864 Error] manou:Connection timed out in 976713ms] Scrabble3D [2012-04-15 00:21:27.868 Debug] HR_CanRead  (Karl_B) Scrabble3D [2012-04-15 00:21:27.869 Debug] HR_ReadCount 195 (Karl_B) Scrabble3D [2012-04-15 00:21:27.879 Info] : Karl_B->all: nwRefresh (9ms) Scrabble3D [2012-04-15 00:21:27.880 Debug] HR_ERROR 32,Other Winsock error (32) (Petronella) Scrabble3D [2012-04-15 00:21:27.882 Error] Petronella:Other Winsock error (32) in 1ms] AFAIK manou is French, thus connection should be good. The only problem I see is an internal question - nwSyncNewGame shouldn't be sent twice. I add this second observation to question the "no route" phenomenon. All other traffic was okay for the last 12 hours. ---------------------------------------------------------------------- Ocye · 2012-04-17 15:58 I found the option SetTimeOut(). With a value of 5000 (I assume milliseconds) for both server and client socket the connection times out after 20000ms. Very strange.