2013-01-31 10 views
9

Rozpoczynam nowy projekt i jednocześnie odkryłem bibliotekę Poco, która jest absolutnie niesamowita. Jednak jestem trochę zagubiony, ponieważ przykłady nie są obfite.Poco :: Net Server & Client Połączenie TCP Event Handler

Mam podejście ServerApplication-> TCPServer-> ServerSocket + TCPServerConnectionFactory-> TCPServerconnection zgodnie z przykładem. Dziedziczę po zajęciach PocoNet zgodnie z instrukcją. Teraz mogę uruchomić mój serwer jako usługę, & odbierać połączenia przychodzące.

Chcę podejść do obsługi zdarzeń w następujący sposób: na podstawie pojedynczego połączenia (lub na kliencie) obsługiwać zdarzenia, takie jak dane dostępne do odczytu w gnieździe klienta, błąd w gniazdach klienta (rozłączony lub timeout), wyślij dane bez błędu na gnieździe klienta.

Jak mam to wykonać? Czy Poco/Foundation/Events to, czego szukam, czy jest jakiś mechanizm zaimplementowany w Poco :: Net?

Widziałem Poco :: Net :: NetExpections, ale nie wydają się być wyrzucane w mojej klasie pochodnej TCPServerConnection, gdy połączenie Netcat zamyka.

Odpowiedz

9

Co skończyło się przy użyciu jest inne podejście jak tcpserver jest inna bestia w ogóle. Po opublikowaniu przykładu here otrzymałem klasę dziedziczącą po ServerApplication i klasę, która staje się w istocie połączeniem handler przez SocketReactor.

Deamonizer nagłówek:

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

realizacja Deamonizer:

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; 
} 

Klasa obsługi może być wszystko, o ile ma on zgodny Konstruktor (patrz dokumentacja Poco :: netto na ten temat). W moim przypadku nagłówek wygląda tak:

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; 
}; 

Jak zaimplementować obsługi jest do Ciebie, pod warunkiem, jedyną rzeczą, którą musisz zrobić, to zarejestrować metody klasy, która obsługiwać zdarzenia tak:

_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)); 

Podsumowując, dwie klasy, kilka linii kodu, proste i czyste. Absolutnie zaczynamy kochać bibliotekę Poco! :)

+0

Przyjemny reaktor :) Dzięki Alex –

8

Spróbuj z tym:

#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

Dziękuję za odpowiedź Cesar, ale to nie odpowiada na pytanie. Twój przykład po prostu akceptuje połączenia, natomiast to, o co pytam, to ankieta wyboru lub (e) lub obsługa zdarzeń w akceptowanych połączeniach dla danych przychodzących, występujących błędów itp. –

+0

Przykład uzupełniony o połączenia przychodzące, limity czasu, błędy sieciowe itp. .. –

+0

Jeszcze raz, dziękuję bardzo :) –

Powiązane problemy