| 41 | class TCPEchoClient : public TCPClient { |
| 42 | public: |
| 43 | TCPEchoClient(const SocketManager& manager,bool parallel) : testDisconnection(false),TCPClient(manager),_mutex(!parallel),parallel(parallel) { |
| 44 | |
| 45 | onData = [this](PoolBuffer& pBuffer)->UInt32 { |
| 46 | lock_guard<Mutex> lock(_mutex); |
| 47 | if (pBuffer->size() < _datas.front().size()) |
| 48 | return 0; // wait more data |
| 49 | UInt32 consumed(_datas.front().size()); |
| 50 | CHECK(memcmp(_datas.front().data(), pBuffer->data(), consumed) == 0); |
| 51 | _datas.pop_front(); |
| 52 | if (this->parallel) |
| 53 | _signal.set(); |
| 54 | return consumed; |
| 55 | }; |
| 56 | |
| 57 | onError = [this](const Exception& ex) { |
| 58 | if (!testDisconnection) |
| 59 | FATAL_ERROR("TCPEchoClient, ", ex.error()) |
| 60 | }; |
| 61 | |
| 62 | onDisconnection = [this](TCPClient& client,const SocketAddress& peerAddress){ |
| 63 | CHECK(!connected()) |
| 64 | _signal.set(); |
| 65 | }; |
| 66 | |
| 67 | OnError::subscribe(onError); |
| 68 | OnData::subscribe(onData); |
| 69 | OnDisconnection::subscribe(onDisconnection); |
| 70 | } |
| 71 | |
| 72 | ~TCPEchoClient() { |
| 73 | OnError::unsubscribe(onError); |
| 74 | OnData::unsubscribe(onData); |
| 75 | OnDisconnection::unsubscribe(onDisconnection); |
| 76 | } |
| 77 | |
| 78 | |
| 79 | const bool parallel; |
| 80 | bool testDisconnection; |
| 81 | |
| 82 | |
| 83 | bool join() { |
| 84 | if (!parallel) { |
| 85 | if (testDisconnection) |
| 86 | return !connected(); |
| 87 | lock_guard<Mutex> lock(_mutex); |
| 88 | return _datas.empty(); |
| 89 | } |
| 90 | while(_signal.wait(20000)) { |
| 91 | lock_guard<Mutex> lock(_mutex); |
| 92 | if (testDisconnection) |
| 93 | return !connected(); |
| 94 | if (_datas.empty()) |
| 95 | return true; |
| 96 | } |
| 97 | return false; |
| 98 | } |
| 99 | |
| 100 | bool echo(Exception& ex,const UInt8* data,UInt32 size) { |