Klassendesign.
-
Hey,
ich bin mit der Software, die ich entwickle meistens nicht zufrieden. Es ist nicht so, dass sie nicht funktioniert - mir gefällt das Klassendesign einfach nicht.
Momentan entwickle ich eine Server-Applikation und mich würde interessieren, ob mein Klassendesign tatsächlich so schlecht ist, wie ich es empfinde.
Nachfolgend beschreibe ich kurz meine Klassen:
WinsockInitializer
Diese Klasse dient zur Initialisierung (Konstruktor) und späteren Freigabe (Destruktor) von Winsock.SocketAddr
Diese Klasse hält eine sockaddr_in und stellt Funktionen zum Setzen der Eigenschaften bereit.Socket
Diese Klasse stellt ein SOCKET dar, und stell Funktionen zum Lesen und Schreiben auf diesem bereit. Außerdem implementiert er die Funktionen connect, bind, etc.Client
Diese Klasse soll später den tatsächlichen Client darstellen. Da es sich um ein Zeilenbasiertes Protokoll handelt, stellt diese Klasse noch die Funktion readLine und writeLine bereit.Listener
Diese Klasse dient zur Annahme von Clients. Sie stellt Funktionen bereit, um in den Listen-Mode zu wechseln und ein Socket anzunehmen.Exception
Es handelt sich um die Oberklasse für alle Exception-Klassen.Die Hierachie sieht so aus:
Exception - ExceptionSocket - ExceptionSocketIO - ExceptionSocketTimeout
Ein simpler Server kann mit den Klassen dann so realisiert werden:
int main() { try { WinsockInitializer init; // Winsock initialisieren Listener listener(2400); listener.startListening(); // Server starten Client client; listener.acceptSocket(client.socket()); // Auf Client warten client.setTimeout(CLIENT_NO_TIMEOUT); // Kein Timeout while (true) { try { std::string x; client.readLine(x); // Zeile lesen std::cout << "'" << x << "'" << std::endl; if (x == "quit") { client.socket().closeSocket(); break; } } catch (ExceptionSocket& e) { e.getSocket().closeSocket(); break; } } } catch (Exception& e) // Allgemeiner Fehler, Socket konnte nicht erstellt werden o. ä. { e.showException(); } }
Was denkt ihr?
-
Ich würde mich bezüglich des Acceptors ein bischen an boost asio orientieren, da wurde es imo etwas besser gelöst:
Beispiel: http://www.boost.org/doc/libs/1_38_0/doc/html/boost_asio/example/echo/blocking_tcp_echo_server.cpp
-
Icematix schrieb:
Ich würde mich bezüglich des Acceptors ein bischen an boost asio orientieren, da wurde es imo etwas besser gelöst:
Beispiel: http://www.boost.org/doc/libs/1_38_0/doc/html/boost_asio/example/echo/blocking_tcp_echo_server.cpp
Ja, mus sich mir nochmal Gedanken drüber machen. Im großen und ganzen finde ich asio aber recht hässlich
-
Macht kein Sinn:
listener.acceptSocket(client.socket()); // Auf Client warten
-
Zeus schrieb:
Macht kein Sinn:
listener.acceptSocket(client.socket()); // Auf Client warten
Ich muss zugeben, es ist auch der Teil an meinem Code, der mich am meisten stört. Der Code ist trotzdem voll funktionsfähig - was macht also keinen Sinn?
Listener
void Listener::acceptSocket(Socket& sock) { mySocket.acceptSocket(sock.rowSocket()); }
Socket
void Socket::acceptSocket(size_t& socket) { socket = accept(mySocket, (sockaddr *) &myAddr.rowAddr(), &myAddr.length()); }
-
Nun, du übergibst deinen Server manuell den Socketobjekt, in dein eigenen Problem stellt das kein Problem, allerdings was passiert, wenn du das Clientprogramm auf einen anderen Rechner laufen lässt? Dann kannst du nicht einfach eine Objekt übergeben. Daher wird das in den Frameworks so gelösst, dass für das Accept ein Clientsocket zur Verfügung gestellt wird.
-
Zeus schrieb:
Nun, du übergibst deinen Server manuell den Socketobjekt, in dein eigenen Problem stellt das kein Problem, allerdings was passiert, wenn du das Clientprogramm auf einen anderen Rechner laufen lässt? Dann kannst du nicht einfach eine Objekt übergeben. Daher wird das in den Frameworks so gelösst, dass für das Accept ein Clientsocket zur Verfügung gestellt wird.
Das verstehe ich nicht. Sehe da keine Probleme.
-
Versuch zwei Programme zu schreiben, ein Client und ein Server und lass den Client auf dem Server verbinden, von den Codestücken die ich gesehen haben, solltest du daran scheitern mit diesem Design.
-
Zeus schrieb:
Versuch zwei Programme zu schreiben, ein Client und ein Server und lass den Client auf dem Server verbinden, von den Codestücken die ich gesehen haben, solltest du daran scheitern mit diesem Design.
Ja, die Klasse Client ist nur für den Server gedacht. Es wäre notwendig, eine neue Klasse für die Client-Applikation zu schreiben. Aber das wäre kein Problem. Die Klasse Socket stellt alle benötigten Funktionen zur Verfügung.
-
Listener
Diese Klasse dient zur Annahme von Clients. Sie stellt Funktionen bereit, um in den Listen-Mode zu wechseln und ein Socket anzunehmen.Wie soll dein Listener den Socket eines anderen Client annehmen?
void Listener::acceptSocket(Socket& sock) { mySocket.acceptSocket(sock.rowSocket()); }
-
Zeus schrieb:
Listener
Diese Klasse dient zur Annahme von Clients. Sie stellt Funktionen bereit, um in den Listen-Mode zu wechseln und ein Socket anzunehmen.Wie soll dein Listener den Socket eines anderen Client annehmen?
void Listener::acceptSocket(Socket& sock) { mySocket.acceptSocket(sock.rowSocket()); }
Ich will mir noch einen ClientManager basteln, der mehrere Clients verwalten und annehmen kann.