[TServerSocket] Empfangspuffer für jeden verbundenen Client



  • Mal sehen ob ich verstanden habe was du meinst. Das Hauptformular soll sich nur um VCL relevante Operationen der Objekte kümmern. Demnach gehört ein neu initialisiertes TClientSocket nicht in die Klasse ClientSession sondern in die Hauptklasse die durch den Programmthread
    verwaltet wird. Wird ein Objekt im Hauptthread freigegeben, so wird dieses Objekt evenfalls von der Windows Message Queue "abgemeldet"

    ServerHandleReceivedPackets soll demnach auch keine Memberfunktion der Haupt VCL Klasse sein da dies auf einer anderen Ebene stattfindet. Eine strikte Trennung zwischen Objekten und Verarbeitungsroutinen um diese zu kapseln und für andere Projekte wiederverwertbar zu machen.

    Richtig?



  • Schwierig zu erklären, da müsste ich jetzt wirklich viel schreiben. Ich versuch´s mal mit ´ner Skizze:

    Binärdaten                 Telegramme
    Schicht 0  <------------>  Schicht 1  <------------>  Schicht 2
    

    Schicht 0 ist nur für die Datenübertragung verantwortlich und kennt weder Zweck noch Inhalt der Daten. Diese Schicht bietet Funktionen zum Schreiben von Daten und benutzt das Observer Pattern, um als Subject Änderungen zu veröffentlichen.

    Schicht 1 meldet sich als Observer an Schicht 0 an. Schicht 1 ist für die Umsetzung des Protokolls verantwortlich, d.h. sie baut aus den Telegrammen Binärdaten zusammen und übergibt sie an Schicht 0, die die Daten dann versendet.
    Außerdem benutzt sie ebenfalls das Observer Pattern, um als Subject die darüberliegende Schicht über den Empfang von Telegrammen zu informieren.
    Schicht 1 kümmert sich nur um das Senden und Empfangen von Telegrammen, ohne irgendwas mit ihnen anzustellen.

    Schicht 2 meldet sich wieder als Observer an Schicht 1 an und ist für die Behandlung und Interpretation der eingehenden Telegramme verantwortlich.
    Schicht 2 meldet sich als Observer an Schicht 1 an, um über eingehende Telegramme informiert zu werden.

    Implementieren kann man sowas z.B. per Komposition, die Implementation des Observer Patterns lasse ich mal außen vor.

    Pseudocode:

    //
    // Schicht 0
    //
    class TCPIPServer
    {
       TNotifyDataEvent  OnData_;   // Event Publisher, müssen implementiert werden
       TNotifyErrorEvent OnError_;
    
    public:
       void send( char* Data, unsigned int Length )
       {
          // Daten versenden
       }
    
       // dient als Event Handler für Socket Events und wird aufgerufen, wenn
       // Daten vom Socket gelesen werden können.
       void on_data( char* Data, unsigned int Length )
       {
          // Observer informieren
          OnData.fire( Data, Length );
       }
    
       void on_error( unsigned int ErrorCode )
       {
          // Observer informieren
          OnError.fire( ErrorCode );
       }
    };
    
    //
    // Schicht 1
    //
    class MyTelegramTCPIPServer
    {
       TCPIPServer           Server_;
       TNotifyTelegramEvent  OnData_;   // Event Publisher, müssen implementiert werden
       TNotifyErrorEvent    OnError_;
    
    public:
       MyTelegramTCPIPServer()
       {
          // als Observer an TCPIPServer anmelden
          Server_.OnError.subscribe( on_error );
          Server_.OnData.subscribe( on_data );
       }
    
       void send_telegram( const Telegram& T )
       {
          // Telegrammdaten zu Binärdaten umwandeln
          char* BinData = ...;
          unsigned int Length = ...;
          Server_.send( BinData, Length );
       }
    
       void on_data( const char* Data, unsigned int Length )
       {
          // Binärdaten wieder zu Telegrammen zusammensetzen und  
          // Observer benachrichtigen
          Telegram t = ...;
          OnTelegram.fire( t );
       }
    
       void on_error( unsigned int ErrorCode )
       {
          OnError.fire( ErrorCode );
       }
    };
    
    //
    // Schicht 2
    //
    class MyForm : public TForm
    {
    public:
       MyForm()
       {
          // als Observer an TCP/IP Server anmelden
          MyTelegramTCPIPServer.OnError.subscribe( on_error );
          MyTelegramTCPIPServer.OnTelegram.subscribe( on_telegram );
       }
    
       ~MyForm()
       {
          // Observer an TCP/IP Server abmelden
          MyTelegramTCPIPServer.OnError.unsubscribe( on_error );
          MyTelegramTCPIPServer.OnTelegram.unsubscribe( on_telegram );
       }
    
       void on_telegram( const Telegram& T ) 
       {
          // mach was mit T, z.B. in Memo eintragen, etc.
       }
    
       void on_error( unsigned int ErrorCode )
       {
          // informiere den Benutzer über einen Fehler
       }
    
       void OnClickButton()
       {
          Telegram t = ...;
          MyTelegramTCPIPServer.send( t );
        }
    };
    

    Das ist nur zur Übersicht gedacht und bei Weitem nicht vollständig. Ich hoffe aber, dass es dir weiterhilft.

    Edit:
    Flüchtigkeitsfehler korrigiert



  • Das nenne ich mal sauber gekapselt. Das dachte ich mir das du in etwa so vorgehst nach dem vorhergegangenen Post. Der Vorteil ist klar ersichtlich, da man die Schichten immer wieder verwenden kann und muss für spätere Projekte nur minimale Anpassungen vornehmen, wenn überhaupt. Die Daten verbleiben in jeder Schicht, eine Message geht raus das Daten vorhanden sind und die überliegende Schicht holt sie sich ab, verarbeitet sie und meldet wiederum an die untere Schicht, dass sie abgearbeitet sind - Schicht säubert die Puffer oder ggf. genutzte Objekte der Instanz und weiter gehts... Ich danke dir für das Beispiel und bietet mir noch mehr worüber ich mir Gedanken mache 🙂

    Gestern Nacht habe ich mal ein Quick and Dirty Verfahren geschrieben um zu sehen ob meine Idee überhaupt funktioniert. Mir ist es gelungen die Clientverbindung zum Master Server über den implementierten Serverlayer vollständig als gekapselte Instanz zu tunneln. Bis auf ein kleines Timing Problem bei der Initialisierung der Clientverbindung als Tunnel zwischen Serverlayer und Masterserver läuft das sehr gut. Das Timing Problem ist nebensächlich da der Authentifizierungshandshake noch nicht so programmiert ist wie er final sein soll - dann ist das Timing Problem nicht mehr vorhanden.

    Deinen Einwand im Bezug zur Löschung eines Objektes und der Message Queue habe ich letzte Nacht mal auf die Spitze getrieben um zu sehen wie sich das Programm im Fall der Fälle verhalten würde. Ein Konstruktor initialisiert ein Socket, weist die Notifier zu und öffnet die Verbindung. Der Destruktor schliesst falls eine Verbindung besteht und gibt das Socket wieder frei. Alle Notifier (Onblablabla) waren public Klassenmember sowie die Paketverarbeitungsroutinen und Puffer private. Alles innerhalb einer Klasse. Dann habe ich mehrere Clients verbunden und angefangen Pakete hin und her zu ballern. Wärend dessen habe ich einfach Clients disconnected (löst den Destruktor aus) und der Runtime Debugger/Codegard haben nicht einmal gemeckert. Es gab keinerlei Auffäligkeiten oder Exceptions.

    Nächster Schritt ist erstmal neben der Clientklasse noch eine Serverklasse zu bauen, wie schon von dir vorgeschlagen. Den Server kapsele ich so erstmal ganz aus dem Hauptprogramm aus, da mir meine bisherige Implementierung nachdem was wir besprochen haben ein wenig unsauber ausschaut.



  • Weiterer Ansatzpunkt:

    Die Klasse der Schicht 0 als Interface auslegen und als TCP/IP Server implementieren. Wenn das funktioniert kannst du weitere Schicht 0 Implementationen umsetzen, z.B. Kommunikation über Pipes oder die serielle Schnittstelle.



  • Die Socket Objekte zu Schichten habe ich erstmal aussen vor gelassen. Dies implementiere ich später. Das heisst zwar alles wieder auseinander klamüsern aber ich verliere sonst den Überblick ohne die vorhergehenden Sachen erstmal intus zu haben.

    Ich habe nun eine Server Klasse und eine Client Klasse und bin noch einen Schritt weiter gegangen ohne std::map Zuordnungen zwingend machen zu müssen, da die Client Klasse den ServerReadBuffer und den Pointer des erstellendem ServerSockets beinhaltet:

    Bei jeder Verbindung auf dem Server erstellt OnAccept eine Instanz von der ClientKlasse. Jeder Konstruktoraufruf der ClientKlasse initialisiert sein eigenes Socket innerhalb seiner Instanz und weist über

    Socket->Data = this
    

    den Pointer seiner eigenen Instanz zu (std::map kommt hier noch falls später iteriert werden muss). Die ClientKlasse speichert die SocketHandleId des ServerSockets, von dem sie erstellt wurde.

    Empfängt der Server nun ein Paket hole ich mir über Socket->Data den Zeiger auf die jeweilige ClientKlasse Instanz und fülle am ServerSocket den ServerReadbuffer und am Client den ClientReadbuffer. Da beide Buffer innerhalb einer Klasse liegen, kann man für den Tunnel die Pakete wesentlich einfacher zuordnen und über die Pointer die jeweiligen Sockets der Instanzen identifizieren. Nach einem längeren Testlauf kann ich nun sagen, dass dies hervorragend funktioniert.

    Edit: trotzdem grosser Fehler. Ich schreibe gerade das ganze um



  • Doc, du hattest vollkommen Recht. Ohne z.B std::map oder einer TObjectList stösst man bei diesem vorhaben schnell an seine Grenzen. Die Idee den Serversammler in die Clientklassen Instanz zu integrieren war ebenfalls nur unfug. Es funktionierte alles bis auf das Szenario wenn der "Master" serverseitig die Verbindung geschlossen wird oder ein Socketerror entsteht. Der Versuch die Verbindung vom Serverlayer aus zum eigentlichen Client zu beenden hat seinen Lesepuffer unter den Füssen bedingt durch den Destruktor weggezogen, woraufhin die Windows Message Queue eine Zugriffsverletzung auslöste. Da mein Vorhaben nur unter bestimmten Bedingungen versagt, habe ich gestern angefangen alles umzustrukturieren. Die Clientklasse initialisiert ihr Socket, stellt Ressourcen bereit. Die Serverklasse kümmert sich um die Ressourcen ihres Sockets. Die std::map Verknüpft als pair die Pointer beider Instanzen da diese eine Einheit bilden um den Tunnel zu realisieren. Findet in einer der beiden ein Socketerror oder Disconnect statt kommt die map ins Spiel um beide Instanzen auf einen Schlag zu säubern und freizugeben.

    Dazu 2 Fragen:
    std::map.erase löst die Destruktoren des pairs aus oder wie geht da erase vor?

    Warum kann eine Klasse kein Owner eines Sockets sein?

    std::map habe ich gestern Abend schon implementiert. Zunächst mit Pointer auf die Socketobjekte, was aber auch nicht korrekt war. Jeder Klasseninstanz ist der Pointer zu seinem Socket bereits bekannt, also unfug. Heute Abend wird die std::map jeweils 2 Zeiger auf die Klasseninstanzen als pair beherbergen. Das Serversocket binde ich wieder ins Hauptprogramm ein weil dies ohnehin nur einmalig ausgeführt wird. Beide Klassen baue ich vollständig in sich gekapselt wieder um so wie es sein muss.



  • Ich habe ein massives Problem mit den Destruktoren. Sobald am ServerSocket eine Clientverbindung geschlossen wird, wird der Destruktor der Klasse ClientSession wie in einer Endlosschleife ausgelöst bis das Programm vollständig abstürzt.
    Erkennt jemand von euch den Fehler?

    Edit: @DocShoe: Deine Anmerkungen sind keinesfalls in Vergessenheit geraten. Ich versuche zunächst erstmal die Grundfunktion herzustellen bevor ich deine Anmerkungen implementiere. Die std::map hatte ich hier erstmal wieder entfernt.

    //----------------------------------------------------------------------------------------
    //----------------------  Klassen
    //----------------------------------------------------------------------------------------
    
    class ServerSession
    {
     friend class ClientSession;
    
       public:
    	ServerSession(ClientSession *,TCustomWinSocket *);
    	~ServerSession();
    
       ClientSession *myclientsession;
       TCustomWinSocket *myserversocket;
       std::vector<unsigned char> ServerPaketsammler;
       void __fastcall ServerHandleReceivedPackets(TCustomWinSocket*);
    };
    
    class ClientSession
    {
    
    friend class ServerSession;
    
    public:
       ClientSession(TCustomWinSocket *);
       ~ClientSession();
    
       void __fastcall ClientSocket1Connect(TObject *Sender,
    	  TCustomWinSocket *Socket);
       void __fastcall ClientSocket1Read(TObject *Sender,
    	  TCustomWinSocket *Socket);
       void __fastcall ClientSocket1Disconnect(TObject *Sender,
    	  TCustomWinSocket *Socket);
       void __fastcall ClientSocket1Error(TObject *Sender,
    	  TCustomWinSocket *Socket, TErrorEvent ErrorEvent, int &ErrorCode);
    
       TClientSocket *SessionClient1;
       TCustomWinSocket *myserversocket;
       ServerSession *myserversession;
    
    private:
       void __fastcall ClientHandleReceivedPackets(TCustomWinSocket *);
       std::vector<unsigned char> ClientPaketsammler;
    
    };
    

    ClientSession

    //----------------------------------------
    //---Konstruktor der Klasse ClientSession
    //----------------------------------------
    ClientSession::ClientSession(TCustomWinSocket *serversocket)
     :myserversocket(serversocket)
    {
    
      Form1->Memo4->Lines->Add("Konstruktor ClientSession");
    
      SessionClient1 = new TClientSocket(NULL);
      SessionClient1->Socket->Data = this;
      SessionClient1->ClientType = ctNonBlocking;
      SessionClient1->Host = "90.123.44.5";
      SessionClient1->Port = 25505;
      SessionClient1->OnConnect = ClientSocket1Connect;
      SessionClient1->OnDisconnect = ClientSocket1Disconnect;
      SessionClient1->OnError = ClientSocket1Error;
      SessionClient1->OnRead = ClientSocket1Read;
      SessionClient1->Open();
    
    }
    //----------------------------------------
    //--- Destruktor der Klasse ClientSession
    //----------------------------------------
    ClientSession::~ClientSession()
    {
    
      Form1->Memo4->Lines->Add("Destruktor ClientSession");
    
      this->SessionClient1->Socket->Close();
      this->myserversocket->Close();
    
      delete this->SessionClient1;
    
    }
    //--------------------------------------------------------------
    
    //---------------------------------------------------------------------------
    //-------  CLIENT
    //---------------------------------------------------------------------------
    
    void __fastcall ClientSession::ClientSocket1Connect(TObject *Sender,
    	  TCustomWinSocket *Socket)
    {
    
       Form1->Memo4->Lines->Add(Time().TimeString() + " [ClientSession] Connected");
    
    }
    //---------------------------------------------------------------------------
    
    void __fastcall ClientSession::ClientSocket1Read(TObject *Sender,
          TCustomWinSocket *Socket)
    {
    
    	 ClientSession *asession = (ClientSession*) Socket->Data;
    	 std::vector<unsigned char> ReceiveBuffer(Socket->ReceiveLength(),0);
    
    	if(!ReceiveBuffer.empty())
    	{
    		int Received = Socket->ReceiveBuf( &ReceiveBuffer[0], ReceiveBuffer.size() );
    		if( Received > 0 )
    		{
    			asession->ClientPaketsammler.insert( asession->ClientPaketsammler.end(), ReceiveBuffer.begin(), ReceiveBuffer.begin() + Received );
    			ClientHandleReceivedPackets(Socket);
    		}
    	}
    
    }
    //---------------------------------------------------------------------------
    void __fastcall ClientSession::ClientHandleReceivedPackets(TCustomWinSocket *Socket)
    {
    
    	ClientSession *asession = (ClientSession*) Socket->Data;
    	unsigned int SequenceId;
    
    	while(asession->ClientPaketsammler.size() >= 8 )
    	{
    
    		 unsigned int TelegramLength = asession->ClientPaketsammler[4] | asession->ClientPaketsammler[5] << 8 | asession->ClientPaketsammler[6] << 16 | asession->ClientPaketsammler[7] << 24;
    
    		if( asession->ClientPaketsammler.size() < TelegramLength )
    		return;
    
    		SequenceId = asession->ClientPaketsammler[0] | asession->ClientPaketsammler[1] << 8 | asession->ClientPaketsammler[2] << 16 | asession->ClientPaketsammler[3] << 24;
    		SequenceId = SequenceId & 0x3fffffff;
    
    		std::vector<unsigned char> Paket(asession->ClientPaketsammler.begin(), asession->ClientPaketsammler.begin() + TelegramLength);
    
    		//Vom Master Server kommenden an den entsprechenden Client weiterleiten
    		asession->myserversocket->SendBuf(&Paket[0],Paket.size());
    
    		asession->ClientPaketsammler.erase( asession->ClientPaketsammler.begin(), asession->ClientPaketsammler.begin() + TelegramLength );
    
    	}
    
    }
    //------------------------------------------------------------------------------------------------------
    
    void __fastcall ClientSession::ClientSocket1Disconnect(TObject *Sender,
    	  TCustomWinSocket *Socket)
    {
    
    	 delete (ClientSession*) Socket->Data;
    	 Form1->Memo4->Lines->Add(Time().TimeString() +  " [ClientSession] Disconnected");
    
    }
    //---------------------------------------------------------------------------
    void __fastcall ClientSession::ClientSocket1Error(TObject *Sender,
    	  TCustomWinSocket *Socket, TErrorEvent ErrorEvent, int &ErrorCode)
    {
    
    	delete (ClientSession*) Socket->Data;
    	Form1->Memo4->Lines->Add(Time().TimeString() + " [ClientSession] Socket Error: " + String(ErrorCode)) ;
    	ErrorCode = 0;
    
    }
    //--------------------------------------------------------------------------
    

    ServerSession:

    //---------------------------------------------------------------------------
    //-----------   SERVER
    //---------------------------------------------------------------------------
    void __fastcall TForm1::Button14Click(TObject *Sender)
    {
    	if(Button14->Caption == "Start")
    	{
    	   Button14->Caption = "Stop";
    
    	   ServerSocket1 = new TServerSocket(Form1);
    	   ServerSocket1->ServerType = stNonBlocking;
    	   ServerSocket1->OnClientConnect = ServerSocket1Connect;
    	   ServerSocket1->OnClientRead = ServerSocket1ClientRead;
    	   ServerSocket1->OnClientDisconnect = ServerSocket1ClientDisconnect;
    	   ServerSocket1->OnClientError = ServerSocket1ClientError;
    	   ServerSocket1->Port = 14888;
    	   ServerSocket1->Active = true;
    	}
    	else
    	{
    
    	  //--- Alle verbundenen Clients trennen
    	  if(ServerSocket1->Socket->ActiveConnections > 0)
    	  {
    		 for(int i = 0; i < ServerSocket1->Socket->ActiveConnections; i++)
    		{
    		  ServerSocket1->Socket->Disconnect(i);
    		}
    	  }
    
    	   ServerSocket1->Active = false;
    	   delete ServerSocket1;
    	   ServerSocket1 = NULL;
    	   Button14->Caption = "Start";
    	}
    }
    //------------------------------------------------------------------------------
    
    //--- Konstruktor der Klasse ServerSession
    ServerSession::ServerSession(ClientSession *clientsession,TCustomWinSocket *ServerSocket)
       :myclientsession(clientsession),myserversocket(ServerSocket)
    {
    
       Form1->Memo4->Lines->Add("Konstruktor ServerSession");
    
    }
    //------------------------
    //--- Destruktor der Klasse ServerSession
    //------------------------
    ServerSession::~ServerSession()
    {
    
    	Form1->Memo4->Lines->Add("Destruktor ServerSession");
    	this->myclientsession->SessionClient1->Socket->Close();
    	this->myserversocket->Close();
    
    }
    //------------------------------------------------------------------------------
    void __fastcall TForm1::ServerSocket1Connect(TObject *Sender,
    	  TCustomWinSocket *Socket)
    {
    
    	   ClientSession *asession = new ClientSession(Socket);
    	   Socket->Data = new ServerSession(asession,Socket);
    	   asession->myserversession = (ServerSession*) Socket->Data;
    
    	   Form1->Memo4->Lines->Add(Time().TimeString() + " [YARCC Client] Connected");
    
    }
    
    //------------------------------------------------------------------------------
    void __fastcall TForm1::ServerSocket1ClientRead(TObject *Sender,
    	  TCustomWinSocket *Socket)
    {
    
    	ServerSession *asession = (ServerSession *)Socket->Data;
    
    	std::vector<unsigned char> ReceiveBuffer(Socket->ReceiveLength(), 0 );
    
    	if( !ReceiveBuffer.empty() )
    	{
    		int Received = Socket->ReceiveBuf( &ReceiveBuffer[0], ReceiveBuffer.size());
    		if(Received > 0)
    		{
    		  asession->ServerPaketsammler.insert( asession->ServerPaketsammler.end(), ReceiveBuffer.begin(),ReceiveBuffer.begin() + Received );
    		  asession->ServerHandleReceivedPackets(Socket);
    		}
    	}
    
    }
    //------------------------------------------------------------------------------
    void __fastcall ServerSession::ServerHandleReceivedPackets(TCustomWinSocket *Socket)
    {
    
    	ServerSession *asession = (ServerSession*)Socket->Data;
    
    	unsigned int SequenceId;
    	while(asession->ServerPaketsammler.size() >= 8 )
    	{
    
    		 unsigned int TelegramLength = asession->ServerPaketsammler[4] | asession->ServerPaketsammler[5] << 8 |
    		 asession->ServerPaketsammler[6] << 16 | asession->ServerPaketsammler[7] << 24;
    
    		if( asession->ServerPaketsammler.size() < TelegramLength )
    		return;
    
    		SequenceId = asession->ServerPaketsammler[0] | asession->ServerPaketsammler[1] << 8 | asession->ServerPaketsammler[2] << 16
    		| asession->ServerPaketsammler[3] << 24;
    		SequenceId = SequenceId & 0x3fffffff;
    
    		std::vector<unsigned char>Paket(asession->ServerPaketsammler.begin(), asession->ServerPaketsammler.begin() + TelegramLength );
    
    		//******** Packet vom Client kommend an Master Server weiterleiten
    		asession->myclientsession->SessionClient1->Socket->SendBuf(&Paket[0],Paket.size());
    
    		asession->ServerPaketsammler.erase( asession->ServerPaketsammler.begin(), asession->ServerPaketsammler.begin() + TelegramLength );
    	}
    
    }
    //------------------------------------------------------------------------------
    void __fastcall TForm1::ServerSocket1ClientDisconnect(TObject *Sender,
    	  TCustomWinSocket *Socket)
    {
    
    	  delete (ServerSession *)Socket->Data;
    	  Form1->Memo4->Lines->Add(Time().TimeString() + " [YARCC Client] Disconnected");
    
    }
    //------------------------------------------------------------------------------
    void __fastcall TForm1::ServerSocket1ClientError(TObject *Sender,
    	  TCustomWinSocket *Socket, TErrorEvent ErrorEvent, int &ErrorCode)
    {
    
    		delete (ServerSession *)Socket->Data;
    		Form1->Memo4->Lines->Add(Time().TimeString() + " [YARCC Client] Socket Error: " + String(ErrorCode)) ;
    
    		ErrorCode = 0;
    
    }
    //------------------------------------------------------------------------------
    


  • Kann die zuvor genannte Problematik dadurch entstehen das der Aufruf delete ASession auch die in der Klasse enthaltenen Objekte in Form von Pointern mit zerstört?
    Eigentlich sollten doch nur die Pointer zerstört werden und nicht die Objekte auf die der Pointer zeigt.



  • Guck dir mal die Adresse des TCustomWinSocket Objekts an, ist es immer das gleiche Objekt, das zerstört wird?

    Außerdem sieht dein Design seltsam aus:
    - warum besitzt ServerSession einen Zeiger auf ein ClientSession ?
    - warum sind beide friends voneinander?
    - warum verwaltest du den Speicher für ClientSession manuell?



  • Moin Doc,
    Der Grund das jede Klasse einen Pointer auf die andere besitzt ist, dass jeweils eine Instanz ClientSession zu einer Instanz ServerSession eine logische Einheit bildet um die Tunneling Funktion bereitzustellen (später kommt noch eine Berechtigungsfunktion bzw. Usermanagment mit rein um Pakete die nicht zur Berechtigungsgruppe gehören verworfen werden - jetzt nicht wichtig da die Klassen und Funktionen schon 2006 für LFS Dedilink von mir entwickelt wurden aber papplapapp).

    Sobald eine Klasseninstanz zerstört wird soll bekannt seine welche Instanz mit ihr ein Paar bildet um diese ebenfalls zu killen. Daher die gegenseitige Pointerzuweisung. Die friendbeziehungen erleichtern mir den Zugriff auf die Member der anderen Klasse



  • Aaargh, sich mal 2 Tage den Kopf frei machen und vom Projekt zu entfernen wirkt manchmal Wunder. Ist doch klar das die Destruktoren ärger machen. Wenn ich im OnSocketError und OnDisconnect Event ein delete einer Session Klasse aufrufe und im Destruktor der Klasse sich ein Socket->Disconnect Aufruf befindet, ruft sich bei einem Socket Error der Destruktor wie in einer Endlosschleife selbst auf bis das Programm abstürzt. Man bin ich blind...
    Jetzt muss ich zusehen wie ich das am besten löse

    Edit: Jetzt funktionierts! Habt ihr evtl. Optimierungsvorschläge für mich?

    //----------------------------------------
    //---Konstruktor der Klasse ClientSession
    //----------------------------------------
    ClientSession::ClientSession(TCustomWinSocket *serversocket)
     :myserversocket(serversocket)
    {
    
      Form1->Memo4->Lines->Add("Konstruktor ClientSession");
    
      SessionClient1 = new TClientSocket(NULL);
      SessionClient1->Socket->Data = this;
      SessionClient1->ClientType = ctNonBlocking;
      SessionClient1->Host = "90.123.45.5";
      SessionClient1->Port = 25505;
      SessionClient1->OnConnect = ClientSocket1Connect;
      SessionClient1->OnDisconnect = ClientSocket1Disconnect;
      SessionClient1->OnError = ClientSocket1Error;
      SessionClient1->OnRead = ClientSocket1Read;
      SessionClient1->Open();
    
    }
    //----------------------------------------
    //--- Destruktor der Klasse ClientSession
    //----------------------------------------
    ClientSession::~ClientSession()
    {
    
      Form1->Memo4->Lines->Add("Destruktor ClientSession");
    
      delete this->SessionClient1;
      this->SessionClient1 = NULL;
    
    }
    //--------------------------------------------------------------
    
    //---------------------------------------------------------------------------
    //-------  CLIENT
    //---------------------------------------------------------------------------
    
    void __fastcall ClientSession::ClientSocket1Connect(TObject *Sender,
    	  TCustomWinSocket *Socket)
    {
    
       Form1->Memo4->Lines->Add(Time().TimeString() + " [ClientSession] Connected");
    
    }
    //---------------------------------------------------------------------------
    
    void __fastcall ClientSession::ClientSocket1Read(TObject *Sender,
          TCustomWinSocket *Socket)
    {
    
    	 ClientSession *asession = (ClientSession*) Socket->Data;
    	 std::vector<unsigned char> ReceiveBuffer(Socket->ReceiveLength(),0);
    
    	if(!ReceiveBuffer.empty())
    	{
    		int Received = Socket->ReceiveBuf( &ReceiveBuffer[0], ReceiveBuffer.size() );
    		if( Received > 0 )
    		{
    			asession->ClientPaketsammler.insert( asession->ClientPaketsammler.end(), ReceiveBuffer.begin(), ReceiveBuffer.begin() + Received );
    			ClientHandleReceivedPackets(Socket);
    		}
    	}
    
    }
    //---------------------------------------------------------------------------
    void __fastcall ClientSession::ClientHandleReceivedPackets(TCustomWinSocket *Socket)
    {
    
    	ClientSession *asession = (ClientSession*) Socket->Data;
    	unsigned int SequenceId;
    
    	while(asession->ClientPaketsammler.size() >= 8 )
    	{
    
    		 unsigned int TelegramLength = asession->ClientPaketsammler[4] | asession->ClientPaketsammler[5] << 8 | asession->ClientPaketsammler[6] << 16 | asession->ClientPaketsammler[7] << 24;
    
    		if( asession->ClientPaketsammler.size() < TelegramLength )
    		return;
    
    		SequenceId = asession->ClientPaketsammler[0] | asession->ClientPaketsammler[1] << 8 | asession->ClientPaketsammler[2] << 16 | asession->ClientPaketsammler[3] << 24;
    		SequenceId = SequenceId & 0x3fffffff;
    
    		std::vector<unsigned char> Paket(asession->ClientPaketsammler.begin(), asession->ClientPaketsammler.begin() + TelegramLength);
    
    		//Vom Master Server kommenden an den entsprechenden Client weiterleiten
    		asession->myserversocket->SendBuf(&Paket[0],Paket.size());
    
    		asession->ClientPaketsammler.erase( asession->ClientPaketsammler.begin(), asession->ClientPaketsammler.begin() + TelegramLength );
    
    	}
    
    }
    //------------------------------------------------------------------------------------------------------
    
    void __fastcall ClientSession::ClientSocket1Disconnect(TObject *Sender,
    	  TCustomWinSocket *Socket)
    {
    	  if(this->SessionClient1->Socket->Data != NULL)
    	{
    	 ClientSession *asession = (ClientSession*) Socket->Data;
    	 asession->myserversession->myserversocket->Data = NULL;
    	 asession->myserversocket->Close();
    	 delete asession->myserversession;
    	 delete asession;
    
    	 asession->myserversession = NULL;
    	 asession = NULL;
    	}
    
    	 Form1->Memo4->Lines->Add(Time().TimeString() +  " [ClientSession] Disconnected");
    
    }
    //---------------------------------------------------------------------------
    void __fastcall ClientSession::ClientSocket1Error(TObject *Sender,
    	  TCustomWinSocket *Socket, TErrorEvent ErrorEvent, int &ErrorCode)
    {
    
    	ClientSession *asession = (ClientSession*) Socket->Data;
    	asession->SessionClient1->Socket->Close();
    
    	Form1->Memo4->Lines->Add(Time().TimeString() + " [ClientSession] Socket Error: " + String(ErrorCode)) ;
    	ErrorCode = 0;
    
    }
    //--------------------------------------------------------------------------
    
    //---------------------------------------------------------------------------
    //-----------   SERVER
    //---------------------------------------------------------------------------
    void __fastcall TForm1::Button14Click(TObject *Sender)
    {
    	if(Button14->Caption == "Start")
    	{
    	   Button14->Caption = "Stop";
    
    	   ServerSocket1 = new TServerSocket(Form1);
    	   ServerSocket1->ServerType = stNonBlocking;
    	   ServerSocket1->OnClientConnect = ServerSocket1Connect;
    	   ServerSocket1->OnClientRead = ServerSocket1ClientRead;
    	   ServerSocket1->OnClientDisconnect = ServerSocket1ClientDisconnect;
    	   ServerSocket1->OnClientError = ServerSocket1ClientError;
    	   ServerSocket1->Port = 14888;
    	   ServerSocket1->Active = true;
    	}
    	else
    	{
    
    	  //--- Alle verbundenen Clients trennen
    	  if(ServerSocket1->Socket->ActiveConnections > 0)
    	  {
    		 for(int i = 0; i < ServerSocket1->Socket->ActiveConnections; i++)
    		{
    		  ServerSocket1->Socket->Disconnect(i);
    		}
    	  }
    
    	   ServerSocket1->Active = false;
    	   delete ServerSocket1;
    	   ServerSocket1 = NULL;
    	   Button14->Caption = "Start";
    	}
    }
    //------------------------------------------------------------------------------
    
    //--- Konstruktor der Klasse ServerSession
    ServerSession::ServerSession(ClientSession *clientsession,TCustomWinSocket *ServerSocket)
       :myclientsession(clientsession),myserversocket(ServerSocket)
    {
    
       Form1->Memo4->Lines->Add("Konstruktor ServerSession");
    
    }
    //------------------------
    //--- Destruktor der Klasse ServerSession
    //------------------------
    ServerSession::~ServerSession()
    {
    
    	Form1->Memo4->Lines->Add("Destruktor ServerSession");
    
    }
    //----------------------------------------------------------------------------
    void __fastcall TForm1::ServerSocket1ClientRead(TObject *Sender,
    	  TCustomWinSocket *Socket)
    {
    
    	ServerSession *asession = (ServerSession *)Socket->Data;
    
    	std::vector<unsigned char> ReceiveBuffer(Socket->ReceiveLength(), 0 );
    
    	if( !ReceiveBuffer.empty() )
    	{
    		int Received = Socket->ReceiveBuf( &ReceiveBuffer[0], ReceiveBuffer.size());
    		if(Received > 0)
    		{
    		  asession->ServerPaketsammler.insert( asession->ServerPaketsammler.end(), ReceiveBuffer.begin(),ReceiveBuffer.begin() + Received );
    		  asession->ServerHandleReceivedPackets(Socket);
    		}
    	}
    
    }
    //---------------------------------------------------------------------------------------------------------
    void __fastcall ServerSession::ServerHandleReceivedPackets(TCustomWinSocket *Socket)
    {
    
    	ServerSession *asession = (ServerSession*)Socket->Data;
    
    	unsigned int SequenceId;
    	while(asession->ServerPaketsammler.size() >= 8 )
    	{
    
    		 unsigned int TelegramLength = asession->ServerPaketsammler[4] | asession->ServerPaketsammler[5] << 8 |
    		 asession->ServerPaketsammler[6] << 16 | asession->ServerPaketsammler[7] << 24;
    
    		if( asession->ServerPaketsammler.size() < TelegramLength )
    		return;
    
    		SequenceId = asession->ServerPaketsammler[0] | asession->ServerPaketsammler[1] << 8 | asession->ServerPaketsammler[2] << 16
    		| asession->ServerPaketsammler[3] << 24;
    		SequenceId = SequenceId & 0x3fffffff;
    
    		/*--- Verzögerungstest TEST!!!!
    		if(SequenceId == 1)
    		{
    			for(int i = 0; i < 10; i++)
    			{
    			  Sleep(10);
    			  Application->ProcessMessages();
    
    			}
    		}
    		*/
    
    		std::vector<unsigned char>Paket(asession->ServerPaketsammler.begin(), asession->ServerPaketsammler.begin() + TelegramLength );
    
    		//******** Packet vom Client kommend an Master Server weiterleiten
    		asession->myclientsession->SessionClient1->Socket->SendBuf(&Paket[0],Paket.size());
    
    		asession->ServerPaketsammler.erase( asession->ServerPaketsammler.begin(), asession->ServerPaketsammler.begin() + TelegramLength );
    	}
    
    }
    //----------------------------------------------------------------------------------------------------------
    void __fastcall TForm1::ServerSocket1Connect(TObject *Sender,
    	  TCustomWinSocket *Socket)
    {
    
    	   ClientSession *asession = new ClientSession(Socket);
    	   Socket->Data = new ServerSession(asession,Socket);
    	   asession->myserversession = (ServerSession*) Socket->Data;
    
    	   Form1->Memo4->Lines->Add(Time().TimeString() + " [YARCC Client] Connected");
    
    }
    
    //--------------------------------------------------------------------------------------------------------
    void __fastcall TForm1::ServerSocket1ClientDisconnect(TObject *Sender,
    	  TCustomWinSocket *Socket)
    {
    
    	  if((ServerSession*)Socket->Data != NULL)
    	 {
    	  ServerSession *asession = (ServerSession*)Socket->Data;
    	  asession->myclientsession->SessionClient1->Socket->Data = NULL;
    	  asession->myclientsession->SessionClient1->Socket->Close();
    
    	  delete asession->myclientsession;
    	  delete asession;
    
    	  asession->myclientsession = NULL;
    	  asession = NULL;
    	 }
    
    	  Form1->Memo4->Lines->Add(Time().TimeString() + " [YARCC Client] Disconnected");
    
    }
    //--------------------------------------------------------------------------------------------------------
    void __fastcall TForm1::ServerSocket1ClientError(TObject *Sender,
    	  TCustomWinSocket *Socket, TErrorEvent ErrorEvent, int &ErrorCode)
    {
    
    	  ServerSession *asession = (ServerSession*)Socket->Data;
    	  asession->myserversocket->Close();
    
    	  Form1->Memo4->Lines->Add(Time().TimeString() + " [YARCC Client] Socket Error: " + String(ErrorCode)) ;
    
    	  ErrorCode = 0;
    
    }
    //--------------------------------------------------------------------------------------------------------
    


  • Leider schlägt mein Code immernoch fehl wenn der Server zu dem ClientSession eine Verbindung aufbaut, die Verbindung trennt bzw: ein Socket Error eintritt. Alle anderen möglichen Szenarios funktionieren ohne Speicherlecks oder Fehlermeldungen.

    Ich habe nun den Lösungsweg über eine Klasseninstanz bestritten, da in der älteren Version beide Instanzen ein Paar bildeten, gleichzeitig Leben und Sterben. Also warum nicht das Vorhaben innerhalb einer Klasseninstanz realisieren.

    Der Fehler: Wird das OnDisconnect Event von myclientsocket ausgelöst, verursacht der darin enthaltene Code folgende Exception - Socket Error 10038, ein Vorgang bezog sich auf ein Objekt was kein Socket ist, bei Api "closesocket" aufgetreten. Danach kommt eine Exception Read of Adress 0xefefefef. Ich verfahre genauso wie bei einem Disconnect am Serversocket wo es keinerlei Auffälligkeiten gibt. Erkennt jemand von euch wo der Fehler liegt?

    class YarccSession
    {
    
    //friend class TForm1;
    
    public:
       YarccSession(TCustomWinSocket *);
       ~YarccSession();
    
       void __fastcall ClientSocket1Connect(TObject *Sender,
    	  TCustomWinSocket *Socket);
       void __fastcall ClientSocket1Read(TObject *Sender,
    	  TCustomWinSocket *Socket);
       void __fastcall ClientSocket1Disconnect(TObject *Sender,
    	  TCustomWinSocket *Socket);
       void __fastcall ClientSocket1Error(TObject *Sender,
    	  TCustomWinSocket *Socket, TErrorEvent ErrorEvent, int &ErrorCode);
    
       TClientSocket *myclientsocket;
       TCustomWinSocket *myserversocket;
    
    private:
       void __fastcall ClientHandleReceivedPackets(TCustomWinSocket *);
       void __fastcall ServerHandleReceivedPackets(TCustomWinSocket*);
       std::vector<unsigned char> ClientPaketsammler;
       std::vector<unsigned char> ServerPaketsammler;
    
    };
    
    //----------------------------------------
    YarccSession::YarccSession(TCustomWinSocket *serversocket)
     :myserversocket(serversocket)
    {
    
      Form1->Memo4->Lines->Add("Konstruktor YarccSession");
    
      myserversocket->Data = this;
      myclientsocket = new TClientSocket(NULL);
      myclientsocket->Socket->Data = this;
      myclientsocket->ClientType = ctNonBlocking;
      myclientsocket->Host = "90.197.152.229";
      myclientsocket->Port = 25505;
      myclientsocket->OnConnect = ClientSocket1Connect;
      myclientsocket->OnDisconnect = ClientSocket1Disconnect;
      myclientsocket->OnError = ClientSocket1Error;
      myclientsocket->OnRead = ClientSocket1Read;
      myclientsocket->Open();
    
    }
    //----------------------------------------
    //--- Destruktor der Klasse ClientSession
    //----------------------------------------
    YarccSession::~YarccSession()
    {
       Form1->Memo4->Lines->Add("Destruktor YarccSession");
    
       delete this->myclientsocket;
       this->myclientsocket = NULL;
    
    }
    //--------------------------------------------------------------
    

    Hier tritt der Fehler ein:

    void __fastcall YarccSession::ClientSocket1Disconnect(TObject *Sender,
    	  TCustomWinSocket *Socket)
    {
    	  if(Socket->Data != NULL)
    	{
    		YarccSession *asession = (YarccSession*)Socket->Data;
    		asession->myclientsocket->Socket->Data = NULL;
    		asession->myserversocket->Data = NULL;
    
    		if(asession->myserversocket->Connected)
    		asession->myserversocket->Close();
    
    		delete asession;
    		asession = NULL;
    	}
    
    	 Form1->Memo4->Lines->Add(Time().TimeString() +  " [ClientSession] Disconnected");
    
    }
    //---------------------------------------------------------------------------
    void __fastcall YarccSession::ClientSocket1Error(TObject *Sender,
    	  TCustomWinSocket *Socket, TErrorEvent ErrorEvent, int &ErrorCode)
    {
    
    	 YarccSession *asession = (YarccSession*) Socket->Data;
    
    	 if(asession->myclientsocket->Socket->Connected)
    	 asession->myclientsocket->Socket->Close();
    
    	 Form1->Memo4->Lines->Add(Time().TimeString() + " [ClientSession] Socket Error: " + String(ErrorCode)) ;
    	 ErrorCode = 0;
    
    }
    
    void __fastcall TForm1::ServerSocket1Connect(TObject *Sender,
    	  TCustomWinSocket *Socket)
    {
    
    	   new YarccSession(Socket);
    	   Form1->Memo4->Lines->Add(Time().TimeString() + " [YARCC Client] Connected");
    
    }
    
    //--------------------------------------------------------------------------------------------------------
    void __fastcall TForm1::ServerSocket1ClientDisconnect(TObject *Sender,
    	  TCustomWinSocket *Socket)
    {
    
    	  if(Socket->Data != NULL)
    	 {
    		 YarccSession *asession = (YarccSession*)Socket->Data;
    		 asession->myserversocket->Data = NULL;
    		 asession->myclientsocket->Socket->Data = NULL;
    
    		 if(asession->myclientsocket->Socket->Connected)
    		 asession->myclientsocket->Socket->Close();
    
    		 delete asession;
    		 asession = NULL;
    	 }
    
    	 Form1->Memo4->Lines->Add(Time().TimeString() + " [YARCC Client] Disconnected");
    
    }
    //--------------------------------------------------------------------------------------------------------
    void __fastcall TForm1::ServerSocket1ClientError(TObject *Sender,
    	  TCustomWinSocket *Socket, TErrorEvent ErrorEvent, int &ErrorCode)
    {
    
    	  YarccSession *asession = (YarccSession*)Socket->Data;
    
    	  if(asession->myserversocket->Connected)
    	  asession->myserversocket->Close();
    
    	  Form1->Memo4->Lines->Add(Time().TimeString() + " [YARCC Client] Socket Error: " + String(ErrorCode)) ;
    
    	  ErrorCode = 0;
    
    }
    //--------------------------------------------------------------------------------------------------------
    


  • Konnte heute endlich mal wieder etwas weitermachen. Ich habe nun herausgefunden was die beiden Exceptions verursacht. Folgende Zeile im Destruktor YarccSession:

    delete this->myclientsocket;
    

    Jetzt bin ich etwas irretiert. Das TClientSocket ist Member der Klasse. DocShoe hatte schon gefragt warum ich das Objekt manuell freigebe. Kommentiere ich das delete des ClientSockets aus, tauchen keine Exceptions mehr auf aber dafür ein deftiges Speicherleck. Also muss dies doch mit delete freigegeben werden weil anscheinend nach Zerstörung der Klasseninstanz noch Reste des Sockets im Speicher übrig bleiben. Hat jemand nen heissen Tip?



  • Kannst du dir den Stack Trace beim Auftreten der Exception angucken?



  • Danke Doc!!! Das Thema ist nun endgültig erledigt. Innerhalb von Events eines Klassenobjektes die Klasse freizugeben bzw. innerhalb eines Events das Sender Objekt freizugeben ohne das beide Szenarieren vollständig abgearbeitet waren, war gelinde gesagt sehr ungeschickt von mir. Wie war das mit dem Ast absägen worauf man sitzt???
    Ich habe nun alle erdenklichen Möglichkeiten von Socket Errors und Disconnects auf beiden Seiten durchgetestet und weder eine Exception oder ein Speicherleck treten auf. Habe es so umgeschrieben das das Serversocket die alleinige Kontrolle über new und delete der Klasseninstanzen hat. Codeguard ist nun genauso zufrieden wie ich 🙂

    YarccSession::YarccSession(TCustomWinSocket *serversocket)
     :myserversocket(serversocket)
    {
    
      Form1->Memo4->Lines->Add("Konstruktor YarccSession");
    
      this->myserversocket->Data = this;
      this->myclientsocket = new TClientSocket(NULL);
      this->myclientsocket->Socket->Data = this;
      this->myclientsocket->ClientType = ctNonBlocking;
      this->myclientsocket->Host = "90.192.150.231";
      this->myclientsocket->Port = 25505;
      this->myclientsocket->OnConnect = myclientsocket1Connect;
      this->myclientsocket->OnDisconnect = myclientsocket1Disconnect;
      this->myclientsocket->OnError = myclientsocket1Error;
      this->myclientsocket->OnRead = myclientsocket1Read;
      this->myclientsocket->Open();
    
    }
    //----------------------------------------
    //--- Destruktor der Klasse ClientSession
    //----------------------------------------
    YarccSession::~YarccSession()
    {
    
       Form1->Memo4->Lines->Add("Destruktor YarccSession");
       delete this->myclientsocket;
       this->myclientsocket = NULL;
    
    }
    //--------------------------------------------------------------
    
    //---------------------------------------------------------------------------
    //-------  CLIENT
    //---------------------------------------------------------------------------
    
    void __fastcall YarccSession::myclientsocket1Connect(TObject *Sender,
    	  TCustomWinSocket *Socket)
    {
       Form1->Memo4->Lines->Add(Time().TimeString() + " [ClientSession] Connected");
    }
    //---------------------------------------------------------------------------
    
    void __fastcall YarccSession::myclientsocket1Read(TObject *Sender,
          TCustomWinSocket *Socket)
    {
    
    	 YarccSession *asession = (YarccSession*) Socket->Data;
    	 std::vector<unsigned char> ReceiveBuffer(Socket->ReceiveLength(),0);
    
    	if(!ReceiveBuffer.empty())
    	{
    		int Received = Socket->ReceiveBuf( &ReceiveBuffer[0], ReceiveBuffer.size() );
    		if( Received > 0 )
    		{
    		    ReceiveBuffer.resize(Received);
    			asession->ClientPaketsammler.insert( asession->ClientPaketsammler.end(), ReceiveBuffer.begin(), ReceiveBuffer.begin() + Received );
    			ClientHandleReceivedPackets(Socket);
    		}
    	}
    
    }
    //---------------------------------------------------------------------------
    void __fastcall YarccSession::ClientHandleReceivedPackets(TCustomWinSocket *Socket)
    {
    
    	YarccSession *asession = (YarccSession*) Socket->Data;
    	unsigned int SequenceId;
    
    	while(asession->ClientPaketsammler.size() >= 8 )
    	{
    
    		unsigned int TelegramLength = asession->ClientPaketsammler[4] | asession->ClientPaketsammler[5] << 8 | asession->ClientPaketsammler[6] << 16 | asession->ClientPaketsammler[7] << 24;
    
    		if( asession->ClientPaketsammler.size() < TelegramLength )
    		return;
    
    		SequenceId = asession->ClientPaketsammler[0] | asession->ClientPaketsammler[1] << 8 | asession->ClientPaketsammler[2] << 16 | asession->ClientPaketsammler[3] << 24;
    		SequenceId = SequenceId & 0x3fffffff;
    
    		std::vector<unsigned char> Paket(asession->ClientPaketsammler.begin(), asession->ClientPaketsammler.begin() + TelegramLength);
    		Paket.resize(TelegramLength);
    		//Vom Master Server kommenden an den entsprechenden Client weiterleiten
    		asession->myserversocket->SendBuf(&Paket[0],Paket.size());
    
    		asession->ClientPaketsammler.erase( asession->ClientPaketsammler.begin(), asession->ClientPaketsammler.begin() + TelegramLength );
    	}
    
    }
    //------------------------------------------------------------------------------------------------------
    
    void __fastcall YarccSession::myclientsocket1Disconnect(TObject *Sender,
    	  TCustomWinSocket *Socket)
    {
    
    	  if(Socket->Data != NULL)
    	{
    		YarccSession *asession = (YarccSession*)Socket->Data;
    
    		if(asession->myserversocket->Connected)
    		asession->myserversocket->Close();
    	}
    
    	   Form1->Memo4->Lines->Add(Time().TimeString() +  " [ClientSession] Disconnected");
    
    }
    //---------------------------------------------------------------------------
    void __fastcall YarccSession::myclientsocket1Error(TObject *Sender,
    	  TCustomWinSocket *Socket, TErrorEvent ErrorEvent, int &ErrorCode)
    {
    
    	 if(Socket->Data != NULL)
    	{
    		YarccSession *asession = (YarccSession*)Socket->Data;
    
    		if(asession->myserversocket->Connected)
    		asession->myserversocket->Close();
    
    	}
    
    	 Form1->Memo4->Lines->Add(Time().TimeString() + " [ClientSession] Socket Error: " + String(ErrorCode)) ;
    	 ErrorCode = 0;
    
    }
    //--------------------------------------------------------------------------
    
    //---------------------------------------------------------------------------
    //-----------   SERVER
    //---------------------------------------------------------------------------
    void __fastcall TForm1::Button14Click(TObject *Sender)
    {
    	if(Button14->Caption == "Start")
    	{
    	   Button14->Caption = "Stop";
    
    	   ServerSocket1 = new TServerSocket(Form1);
    	   ServerSocket1->ServerType = stNonBlocking;
    	   ServerSocket1->OnClientConnect = ServerSocket1Connect;
    	   ServerSocket1->OnClientRead = ServerSocket1ClientRead;
    	   ServerSocket1->OnClientDisconnect = ServerSocket1ClientDisconnect;
    	   ServerSocket1->OnClientError = ServerSocket1ClientError;
    	   ServerSocket1->Port = 14888;
    	   ServerSocket1->Active = true;
    	}
    	else
    	{
    
    	  Button14->Caption = "Start";
    
    	  if(ServerSocket1->Socket->ActiveConnections > 0)
    	  {
    		 for(int i = 0; i < ServerSocket1->Socket->ActiveConnections; i++)
    		{
    		  ServerSocket1->Socket->Disconnect(i);
    		}
    	  }
    
    	   ServerSocket1->Active = false;
    	   delete ServerSocket1;
    	}
    }
    //------------------------------------------------------------------------------
    void __fastcall TForm1::ServerSocket1ClientRead(TObject *Sender,
    	  TCustomWinSocket *Socket)
    {
    
    	YarccSession *asession = (YarccSession *)Socket->Data;
    
    	std::vector<unsigned char> ReceiveBuffer(Socket->ReceiveLength(), 0 );
    
    	if( !ReceiveBuffer.empty() )
    	{
    		int Received = Socket->ReceiveBuf( &ReceiveBuffer[0], ReceiveBuffer.size());
    		if(Received > 0)
    		{
    		  ReceiveBuffer.resize(Received);
    		  asession->ServerPaketsammler.insert(asession->ServerPaketsammler.end(), ReceiveBuffer.begin(),ReceiveBuffer.begin() + Received);
    		  asession->ServerHandleReceivedPackets(Socket);
    		}
    	}
    
    }
    //---------------------------------------------------------------------------------------------------------
    void __fastcall YarccSession::ServerHandleReceivedPackets(TCustomWinSocket *Socket)
    {
    
    	YarccSession *asession = (YarccSession*)Socket->Data;
    
    	unsigned int SequenceId;
    	while(asession->ServerPaketsammler.size() >= 8 )
    	{
    
    		 unsigned int TelegramLength = asession->ServerPaketsammler[4] | asession->ServerPaketsammler[5] << 8 |
    		 asession->ServerPaketsammler[6] << 16 | asession->ServerPaketsammler[7] << 24;
    
    		 if( asession->ServerPaketsammler.size() < TelegramLength )
    		 return;
    
    		 SequenceId = asession->ServerPaketsammler[0] | asession->ServerPaketsammler[1] << 8 | asession->ServerPaketsammler[2] << 16
    		 | asession->ServerPaketsammler[3] << 24;
    		 SequenceId = SequenceId & 0x3fffffff;
    
    		std::vector<unsigned char>Paket(asession->ServerPaketsammler.begin(), asession->ServerPaketsammler.begin() + TelegramLength );
    		Paket.resize(TelegramLength);
    		//******** Packet vom Client kommend an Master Server weiterleiten
    		asession->myclientsocket->Socket->SendBuf(&Paket[0],Paket.size());
    		asession->ServerPaketsammler.erase( asession->ServerPaketsammler.begin(), asession->ServerPaketsammler.begin() + TelegramLength );
    
    	}
    
    }
    //----------------------------------------------------------------------------------------------------------
    void __fastcall TForm1::ServerSocket1Connect(TObject *Sender,
    	  TCustomWinSocket *Socket)
    {
    
    	   new YarccSession(Socket);
    	   Form1->Memo4->Lines->Add(Time().TimeString() + " [YARCC Client] Connected");
    
    }
    
    //--------------------------------------------------------------------------------------------------------
    void __fastcall TForm1::ServerSocket1ClientDisconnect(TObject *Sender,
    	  TCustomWinSocket *Socket)
    {
    
    	  if(Socket->Data != NULL)
    	 {
    
    		 YarccSession *asession = (YarccSession*)Socket->Data;
    		 if(asession->myclientsocket->Socket->Connected)
    		{
    		 asession->myclientsocket->Socket->Data = NULL;
    		 asession->myclientsocket->Socket->Close();
    		}
    
    		 delete asession;
    		 asession = NULL;
    	 }
    
    	 Form1->Memo4->Lines->Add(Time().TimeString() + " [YARCC Client] Disconnected");
    
    }
    //--------------------------------------------------------------------------------------------------------
    void __fastcall TForm1::ServerSocket1ClientError(TObject *Sender,
    	  TCustomWinSocket *Socket, TErrorEvent ErrorEvent, int &ErrorCode)
    {
    
    	  YarccSession *asession = (YarccSession*)Socket->Data;
    
    	  if(asession->myserversocket->Connected)
    	  asession->myserversocket->Close();
    
    	  Form1->Memo4->Lines->Add(Time().TimeString() + " [YARCC Client] Socket Error: " + String(ErrorCode)) ;
    
    	  ErrorCode = 0;
    
    }
    //--------------------------------------------------------------------------------------------------------
    

Anmelden zum Antworten