Autor |
Beitrag |
RBiniasch
Hält's aus hier
Beiträge: 11
|
Verfasst: Mo 14.07.08 16:31
Hallo,
für die interne Kommunikation einer verteilten Anwendung verwende ich die Indy-Komponenten. Der gesamte Nachrichtenaustausch läuft über einen kleinen Kommunikationsserver, an welchem sich alle Dienste anmelden und über den das Konfigurationsprogramm Zugriff auf diese Dienste erhält.
Damit das klappt fordert der Kommunikationsserver bei jedem Connect von dem Client erstmal ein LogOn an. In dieser Anforderung erhält der Client auch seine Session-ID.
So weit, so gut. Leider gibt es bei diesem Schritt immer wieder Aussetzer die sich derart äussern, dass der Indy-Server behauptet, er habe die Anforderung zum Client übertragen, dort aber nichts ankommt.
Die Funktionen sehen wie folgt aus.
OnConnect des Servers.
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61:
| procedure TtoIFCommServer.OnServerConnect(toThread: TIdPeerThread); var recRequest : TrecMsgHeader; recReply : TrecMsgLogOn;
pNewConnection : PrecIFConnection;
cardMinWait : Cardinal;
siCounter : SmallInt; begin LogEvent(Format(g_astrIFComBase[4], [toThread.Connection.LocalName]), IF_CONST_LOGCONNECT, etInfo, IF_CONST_LOGLEVEL_MIN);
GetMem(pNewConnection, SizeOf(TrecIFConnection));
pNewConnection.strDNS := toThread.Connection.LocalName; pNewConnection.dtConnStart := Now; pNewConnection.dtLastAction := pNewConnection.dtConnStart; pNewConnection.pConnection := toThread;
cardMinWait := GetTickCount + IF_CONST_WAITAFTERCONNECT;
repeat pNewConnection.iSessionID := Random(IF_CONST_SESSIONIDRANGE); until F_tolConThreads.SessionIDIsUnique(pNewConnection.iSessionID);
toThread.Data := TObject(pNewConnection);
recRequest := F_toComBase.CreateMsgHeader(IF_CONST_TCPIPHOST, EmptyStr, EmptyStr, svctCommSvr, mtRequestLogOn, pNewConnection.iSessionID); ZeroMemory(@recReply, SizeOf(recReply));
while GetTickCount < cardMinWait do g_procProcessMessages;
if F_toComBase.ExchangeMsgs(toThread.Connection, @recRequest, @recReply, SizeOf(recRequest), SizeOf(recReply)) = frOK then begin pNewConnection.strName := recReply.recHeader.strClientname; pNewConnection.strTargetname := recReply.recHeader.strTargetname; pNewConnection.secClientType := recReply.recHeader.secClientType; pNewConnection.bLoggedOn := TRUE; end else begin pNewConnection.strName := g_astrIFComBase[31]; pNewConnection.strTargetname := g_astrIFComBase[31]; pNewConnection.secClientType := svctUnknown; pNewConnection.bLoggedOn := FALSE; end; end; |
ExchangeMsgs aus dem OnConnect.
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23:
| function TtoIFComBase.ExchangeMsgs(toConnection: TIdTCPConnection; pSend, pReply: Pointer; iSendLength, iReplyLength: Integer; bExpectMsgHeader: Boolean): TsecFuncResult; begin Result := frError;
if Assigned(toConnection) then begin if Assigned(pSend) then begin if Assigned(pReply) then begin try if SendData(toConnection, pSend, iSendLength)then begin Sleep(IF_CONST_MINWAITFORREPLY); Result := ReadData(toConnection, pReply, iReplyLength, bExpectMsgHeader); end; except Result := frError; end; end; end; end; end; |
Mit der Funktion SendData beginnt das Problem.
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13:
| function TtoIFComBase.SendData(toConnection: TIdTCPConnection; pData: Pointer; cardDataLength: Cardinal): Boolean; begin Result := TRUE; try if (Assigned(toConnection)) and (toConnection.Connected) then toConnection.WriteBuffer(pData^, cardDataLength, TRUE) else Result := FALSE; except Result := FALSE; end; end; |
Im WriteBuffer wird keine Exception ausgelöst. Die Funktion läuft einfach durch und alles scheint gut ...
Auf Client-Seite sieht das OnExecute so aus :
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19:
| procedure TService_IFSendMsg.ContactExecute(AThread: TIdPeerThread); var recMsgHeader : TrecMsgHeader; begin ShowMessage('Execute'); if AThread.Connection.Socket.Binding <> nil then begin F_toIFCom.ReadData(AThread.Connection, @recMsgHeader, SizeOf(TrecMsgHeader));
LogEvent(F_toIFCom.GetMsgInfo(recMsgHeader), IF_CONST_LOGEXECUTE, etInfo, IF_CONST_LOGLEVEL_MED); . . . |
Grundsätzlich scheint das zu funktionieren. Ich habe schon ein LogOn bekommen. Aber in über 90% der Fälle kommt leider rein gar nichts an. Im Log ist nichts zu sehen und auch das ShowMessage springt nicht an (rein prophylaktisch, ja, der Dienst darf mit dem Desktop interagieren und er tut es auch. Ich habe ihm aus anderer Quelle Nachrichten geschickt und die Messagebox war zu sehen).
Falls irgendwer eine Idee hat, wo das Problem liegen könnte wäre das toll.
Schon mal danke fürs Lesen und bis denn,
Ralf Biniasch
|
|
Narses
      

Beiträge: 10183
Erhaltene Danke: 1256
W10ent
TP3 .. D7pro .. D10.2CE
|
Verfasst: Mo 14.07.08 16:37
Moin und  im Forum!
Ich hätte da noch ein paar Rückfragen:
RBiniasch hat folgendes geschrieben: | Delphi-Quelltext 1: 2: 3: 4:
| procedure TtoIFCommServer.OnServerConnect(toThread: TIdPeerThread); while GetTickCount < cardMinWait do g_procProcessMessages; | |
Was hat dieser Code für einen Sinn und was tut g_procProcessMessages?
RBiniasch hat folgendes geschrieben: | Delphi-Quelltext 1: 2: 3: 4: 5: 6:
| procedure TService_IFSendMsg.ContactExecute(AThread: TIdPeerThread); LogEvent(F_toIFCom.GetMsgInfo(recMsgHeader), IF_CONST_LOGEXECUTE, etInfo, IF_CONST_LOGLEVEL_MED); | |
Was passiert hier genau (thread-save und keine VCL-Zugriffe?)
cu
Narses
_________________ There are 10 types of people - those who understand binary and those who don´t.
|
|
RBiniasch 
Hält's aus hier
Beiträge: 11
|
Verfasst: Mo 14.07.08 16:58
Hallo und danke für die rasche Reaktion.
Die Prozedur g_procProcessMessages sorgt nur dafür, dass während der Wartezeit weiterhin Windowsmessages abgearbeitet werden.
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10:
| procedure g_procProcessMessages; var msgActWinMessage : TMsg; begin while PeekMessage(msgActWinMessage, 0, 0, 0, PM_REMOVE) do begin TranslateMessage(msgActWinMessage); DispatchMessage(msgActWinMessage); end; end; |
LogEvent schreibt das Ereignislog in eine Datenbank.
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17:
| procedure TService_IFSendMsg.LogEvent(strMessage, strKey: String; secEventType: TsecEventTypes; byLogLevel: Byte); var csLock : TCriticalSection; begin csLock := TCriticalSection.Create; try csLock.Acquire;
F_toSvcBase.LogEvent(strMessage, strKey, secEventType, byLogLevel); finally csLock.Release; FreeAndNil(csLock); end; end; |
Das dürfte beides keinen Einfluss auf die TCP/IP-Kommunikation haben. Insbesondere da die Verarbeitung das LogEvent beim Client nicht erreicht.
Bis denn,
Ralf Biniasch
|
|
Narses
      

Beiträge: 10183
Erhaltene Danke: 1256
W10ent
TP3 .. D7pro .. D10.2CE
|
Verfasst: Mo 14.07.08 19:29
Moin!
RBiniasch hat folgendes geschrieben: | Die Prozedur g_procProcessMessages sorgt nur dafür, dass während der Wartezeit weiterhin Windowsmessages abgearbeitet werden. |
Aber das ist doch evtl. nicht im GUI-Thread der Anwendung, oder?  Du scheinst nicht grad erst mit Programmieren und TCP/IP angefangen zu haben, deshalb würde es mich wundern, wenn du nicht wüsstest, dass die VCL nicht threadsave ist und deshalb sowas potentiell ein Problem darstellt.  Schonmal diesen Teil einfach entfernt? Indy arbeitet doch mit blocking-socket-calls und threads, da sollte es wegen nicht vorhandener Daten doch eigentlich keine Timingprobleme geben...
RBiniasch hat folgendes geschrieben: | Das dürfte beides keinen Einfluss auf die TCP/IP-Kommunikation haben. Insbesondere da die Verarbeitung das LogEvent beim Client nicht erreicht. |
Ja, das sehe ich auch so.  War nur für die Sicherheit.
cu
Narses
_________________ There are 10 types of people - those who understand binary and those who don´t.
|
|
RBiniasch 
Hält's aus hier
Beiträge: 11
|
Verfasst: Di 15.07.08 09:57
Hallo nochmal,
ja, du hast natürlich völlig recht  .
Da hat der Autopilot zugeschlagen. Die Funktion kloppe ich standardmäßig in den Code wenn ich vermute, dass es Timingprobleme geben könnte ...
Gestern Abend kam mir dann auch der Gedanke, dass das Probleme bereiten könnte und ich habe die Warteschleife heraus genommen. Das macht aber leider keinen Unterschied. Nach wie vor kommt die Nachricht nicht beim Client an.
Mit welchem Programm schaue ich denn am besten, ob überhaupt eine Nachricht rausgeht? Ich habe den Wireshark probiert, weiß aber nicht wie ich den korrekt konfiguriere.
Bis denn,
Ralf Biniasch
|
|
Narses
      

Beiträge: 10183
Erhaltene Danke: 1256
W10ent
TP3 .. D7pro .. D10.2CE
|
Verfasst: Di 15.07.08 10:19
Moin!
RBiniasch hat folgendes geschrieben: | ich habe die Warteschleife heraus genommen. Das macht aber leider keinen Unterschied. Nach wie vor kommt die Nachricht nicht beim Client an. |
Schade.
RBiniasch hat folgendes geschrieben: | Mit welchem Programm schaue ich denn am besten, ob überhaupt eine Nachricht rausgeht? Ich habe den Wireshark probiert, |
Das hätte ich dann jetzt auch vorgeschlagen.
RBiniasch hat folgendes geschrieben: | weiß aber nicht wie ich den korrekt konfiguriere. |
Puh, sowas macht hier immer mein Kollege, ich schaue mir dann nur idR die Logs an...  sorry, kann ich dir nicht bei helfen... jaja, ich sollte mich langsam mal mit dem Kabelhai auseinandersetzen... *seufz* sagt mein Kollege auch immer... *g* Wenn ich das mal selbst machen musste, habe ich das mit dem cmd-Tool WinDump gemacht (basiert auch auf WinPCap).
Du könntest aber einfach mal in ein Logfile auf dem Serverdateisystem festhalten, an welchen Codestellen er so beim Connect vorbeirauscht, dann kann man zumindest da mal den Verlauf nachvollziehen. Leider ist der Debugger IMHO bei timingsensitiven Problemen bei der Netzwerkkommunikation nur sehr beschränkt brauchbar, deshalb verfolge ich sowas normalerweise lieber mit Logs.
cu
Narses
_________________ There are 10 types of people - those who understand binary and those who don´t.
|
|
RBiniasch 
Hält's aus hier
Beiträge: 11
|
Verfasst: Di 15.07.08 10:37
Hi,
ich habe auch einen Kollegen zu Hilfe gerufen, der den ollen Hai ein wenig besser kennt  .
Sowas ist immer ein guter Plan ...
Falls das neue Erkenntnisse bringt sage ich nochmal bescheid.
Bis denn,
Ralf Biniasch
--- Moderiert von Narses: Beiträge zusammengefasst---
Hallo nochmal,
so, nun ist es offiziell. Die LogOn-Anforderung geht raus, kommt auch beim Client an (zumindest sendet er ein ACK), löst aber nicht das Execute-Ereignis aus.
Mit den Innereien der Indys habe ich mich noch so gar nicht auseinander gesetzt. Und der Debugger weigert sich leider dort hinein zu schauen.
Mal schauen was ich da finde. Wie immer ist jeder Tipp willkommen ...  .
Bis denn,
Ralf Biniasch
--- Moderiert von Narses: Beiträge zusammengefasst---
Hallo,
ok, wie immer saß das Problem 60cm vor dem Monitor  .
Ich hatte die Kommunikationsstruktur umgestellt und dabei die Zuweisung der OnExecute-Funktion verhunzt. Die war gar nicht mehr in den ganzen Ablauf eingebunden und konnte dementsprechend auch nicht anspringen ...
Danke für die guten Ideen und sorry für die verschwendete Zeit,
Ralf Biniasch
|
|
|