2013-01-31 96 views
9

我開始一個新項目,同時剛剛發現了Poco Library,我發現它非常棒。不過,我有點迷路,因爲例子並不多。Poco :: Net服務器和客戶端TCP連接事件處理程序

我有一個ServerApplication-> TCPServer-> ServerSocket + TCPServerConnectionFactory-> TCPServerconnection方法,如示例所示。我按照指示繼承PocoNet課程。現在我可以運行我的服務器作爲服務,&接收傳入的連接。

我想對以下事件進行事件處理:在每個連接(或每個客戶端)的基礎上處理事件,例如可在客戶端套接字上讀取的數據,在客戶端套接字上發生錯誤(斷開連接或超時),在客戶端套接字上發送沒有錯誤的數據。

我該如何去做呢? 是Poco/Foundation/Events我在找什麼,或者有一些機制在Poco :: Net中實現?

我已經看到了Poco :: Net :: NetExpections,但是當netcat連接關閉時,它們似乎不會出現在我的TCPServerConnection派生類中。

回答

9

我最終什麼事是一種使用不同的方法,因爲TCPSERVER是一個不同的野獸一起。在發佈here的示例之後,我結束了一個繼承自ServerApplication的類以及一個實質上連接處理程序SocketReactor構成的類。

Deamonizer頭:

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

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

處理程序類可以是任何東西,只要它具有符合構造函數(請參閱本波科:: NET文檔)。 在我的情況,頭看起來是這樣的:

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

你如何實現處理是你的,前提是你需要做的是註冊類方法,它處理事件,像這樣的唯一的事情:

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

總而言之,兩個類,幾行代碼,簡單而乾淨。絕對開始愛Poco圖書館! :)

+0

尼斯反應堆:)謝謝亞歷克斯 –

8

試試這個:

#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

謝謝你的答覆塞薩爾,但這並沒有回答這個問題。你的例子只是接受連接,而我所要求的是一個select或(e)輪詢或事件處理程序在接受連接傳入數據,發生的錯誤,等等。 –

+0

完整的例子包括連接,超時,網絡錯誤等。 .. –

+0

再次,非常感謝:) –