2013-01-31 10 views
9

Ich beginne ein neues Projekt und habe gleichzeitig die Poco Library entdeckt, was ich absolut erstaunlich finde. Allerdings bin ich ein bisschen verloren, als Beispiele sind nicht viele.Poco :: Net Server & Client TCP Verbindung Event Handler

Ich habe einen ServerApplication-> TCPServer-> ServerSocket + TCPServerConnectionFactory-> TCPServerconnection Ansatz wie in den Beispielen angegeben. Ich erben wie angewiesen von den PocoNet-Klassen. Im Moment kann ich meinen Server als Dienst ausführen, & eingehende Verbindungen empfangen.

Ich möchte einen Event-Handling-Ansatz zu folgen: auf einer pro Verbindung (oder pro Client) Basis behandeln Ereignisse wie Daten zum Lesen auf dem Client-Socket, aufgetreten Fehler auf dem Client-Socket (getrennt oder Timeout), senden Sie Daten ohne Fehler auf Client-Socket.

Wie gehe ich vor? Ist Poco/Foundation/Events was ich suche, oder ist in Poco :: Net ein Mechanismus implementiert?

Ich habe die Poco :: Net :: NetExpections gesehen, aber sie scheinen nicht in meiner TCPServerConnection abgeleiteten Klasse geworfen werden, wenn eine Netcat-Verbindung schließt.

Antwort

9

Was ich am Ende mit ist ein anderer Ansatz als TCPServer ein anderes Tier überhaupt ist. Nach dem Beispiel gepostet here endete ich mit einer Klasse erben von ServerApplication, und eine Klasse, die im Wesentlichen wird die Verbindung Handler von einem SocketReactor.

Deamonizer Header:

class Daemon : public ServerApplication 
{ 
    public: 
    Daemon(); 
    /// @Brief The main loop of the daemon, everything must take place here 
    int main(); 
}; 

Deamonizer Umsetzung:

int Daemon::main() 
{ 
    // Server Socket 
    ServerSocket svs(2222); 
    // Reactor-Notifier 
    SocketReactor reactor; 
    Poco::Timespan timeout(2000000); // 2Sec 
    reactor.setTimeout(timeout); 
    // Server-Acceptor 
    SocketAcceptor<ConnectionHandler> acceptor(svs, reactor); 
    // Threaded Reactor 
    Thread thread; 
    thread.start(reactor); 
    // Wait for CTRL+C 
    waitForTerminationRequest(); 
    // Stop Reactor 
    reactor.stop(); 
    thread.join(); 
    return Application::EXIT_OK; 
} 

Die Handler-Klasse kann alles sein, solange es eine konforme Constructor hat (siehe Poco :: Net Dokumentation für diese). In meinem Fall der Header wie folgt aussieht:

class ConnectionHandler 
{ 
    public: 

    /** 
    * @Brief Constructor of the Connection Handler 
    * @Note Each object is unique to an accepted connection 
    * @Param SteamSocket is the socket accepting the connections 
    * @See SocketAcceptor http://pocoproject.org/docs/Poco.Net.SocketAcceptor.html 
    * @Param SocketReactor is the reacting engine (threaded) which creates notifications about the socket 
    */ 
    ConnectionHandler(StreamSocket &, SocketReactor &); 

    /** 
    * @Brief Destructor 
    */ 
    ~ConnectionHandler(); 

    /** 
    * @Brief Event Handler when Socket becomes Readable, i.e: there is data waiting to be read 
    */ 
    void onSocketReadable(const AutoPtr<ReadableNotification>& pNf); 

    /** 
    * @Brief Event Handler when Socket was written, i.e: confirmation of data sent away (not received by client) 
    */ 
    void onSocketWritable(const AutoPtr<WritableNotification>& pNf); 

    /** 
    * @Brief Event Handler when Socket was shutdown on the remote/peer side 
    */ 
    void onSocketShutdown(const AutoPtr<ShutdownNotification>& pNf); 

    /** 
    * @Brief Event Handler when Socket throws an error 
    */ 
    void onSocketError(const AutoPtr<ErrorNotification>& pNf); 

    /** 
    * @Brief Event Handler when Socket times-out 
    */ 
    void onSocketTimeout(const AutoPtr<TimeoutNotification>& pNf); 

    private: 

    /** 
    * @Brief Read bytes from the socket, depending on available bytes on socket 
    */ 
    void readBytes(); 

    /** 
    * @Brief Send message to the socket 
    * @Param std::string is the message (null terminated) 
    */ 
    void sendMessage(std::string); 

    /// Stream Socket 
    StreamSocket _socket; 

    /// Socket Reactor-Notifier 
    SocketReactor& _reactor; 

    /// Received Data Buffer 
    std::vector<char *> in_buffer; 
}; 

Wie Sie den Handler an Ihnen implementieren ist, vorausgesetzt, das einzige, was Sie tun müssen, ist die Klassenmethoden registrieren, die Ereignisse behandeln wie so:

_reactor.addEventHandler(_socket,NObserver<ConnectionHandler, ReadableNotification>(*this, &ConnectionHandler::onSocketReadable)); 
    _reactor.addEventHandler(_socket,NObserver<ConnectionHandler, ShutdownNotification>(*this, &ConnectionHandler::onSocketShutdown)); 
    _reactor.addEventHandler(_socket,NObserver<ConnectionHandler, ErrorNotification>(*this, &ConnectionHandler::onSocketError)); 
    _reactor.addEventHandler(_socket,NObserver<ConnectionHandler, TimeoutNotification>(*this, &ConnectionHandler::onSocketTimeout)); 

Alles in allem zwei Klassen, ein paar Zeilen Code, einfach und sauber. Ich fange an Poco Bibliothek zu lieben! :)

+0

Schöne Reaktor :) Danke Alex –

8

Versuchen mit diesem:

#include <iostream> 
#include "Poco/Net/TCPServer.h" 
#include "Poco/Net/TCPServerParams.h" 
#include "Poco/Net/TCPServerConnectionFactory.h" 
#include "Poco/Net/TCPServerConnection.h" 
#include "Poco/Net/Socket.h" 
using namespace std; 

class newConnection: public Poco::Net::TCPServerConnection { 
public: 
    newConnection(const Poco::Net::StreamSocket& s) : 
     Poco::Net::TCPServerConnection(s) { 
    } 

    void run() { 
     cout << "New connection from: " << socket().peerAddress().host().toString() << endl << flush; 
     bool isOpen = true; 
     Poco::Timespan timeOut(10,0); 
     unsigned char incommingBuffer[1000]; 
     while(isOpen){ 
      if (socket().poll(timeOut,Poco::Net::Socket::SELECT_READ) == false){ 
       cout << "TIMEOUT!" << endl << flush; 
      } 
      else{ 
       cout << "RX EVENT!!! ---> " << flush; 
       int nBytes = -1; 

       try { 
        nBytes = socket().receiveBytes(incommingBuffer, sizeof(incommingBuffer)); 
       } 
       catch (Poco::Exception& exc) { 
        //Handle your network errors. 
        cerr << "Network error: " << exc.displayText() << endl; 
        isOpen = false; 
       } 


       if (nBytes==0){ 
        cout << "Client closes connection!" << endl << flush; 
        isOpen = false; 
       } 
       else{ 
        cout << "Receiving nBytes: " << nBytes << endl << flush; 
       } 
      } 
     } 
     cout << "Connection finished!" << endl << flush; 
    } 
}; 

int main(int argc, char** argv) { 

    //Create a server socket to listen. 
    Poco::Net::ServerSocket svs(1234); 

    //Configure some server params. 
    Poco::Net::TCPServerParams* pParams = new Poco::Net::TCPServerParams(); 
    pParams->setMaxThreads(4); 
    pParams->setMaxQueued(4); 
    pParams->setThreadIdleTime(100); 

    //Create your server 
    Poco::Net::TCPServer myServer(new Poco::Net::TCPServerConnectionFactoryImpl<newConnection>(), svs, pParams); 
    myServer.start(); 

    while(1); 

    return 0; 
} 
+0

Vielen Dank für die Antwort Cesar, aber das beantwortet die Frage nicht. Ihr Beispiel akzeptiert nur Verbindungen, während ich nach einem ausgewählten oder (e) Poll oder Event-Handler für die angenommenen Verbindungen für eingehende Daten, auftretende Fehler usw. frage. –

+0

Beispiel mit eingehenden Verbindungen, Timeouts, Netzwerkfehlern usw. .. –

+0

Nochmals vielen Dank :) –