WSARecv()
you'll realise that is harder than it sounds as WSARecv()
does not provide this functionality. The basic structure of this server is very similar to the Basic Echo Server example and you should go and read about that first and have a good understanding of how everything fits together. This document will only cover the differences between the Basic Echo Server example and this example. ServerMain.cpp
is identical to the Basic Echo Server, but our CSocketServer class contains instances of JetByteTools::Socket::CReadTimeoutStreamSocketConnectionFilter and JetByteTools::Win32::CThreadedCallbackTimerQueue as member variables and inherits from JetByteTools::Socket::CReadTimeoutStreamSocketConnectionFilter::TimerCallback in addition to the base classes used in previous examples. During construction we wire up the connection filter and the timer queue and register the filter with the server base class.
CSocketServer::CSocketServer( const string &welcomeMessage, const IFullAddress &address, const ListenBacklog listenBacklog, IIOPool &pool, IAllocateStreamSockets &socketAllocator, IAllocateBuffers &bufferAllocator, ILimitConnections &connectionLimiter) : CStreamSocketServerEx(address, listenBacklog, *this, pool, socketAllocator, bufferAllocator, NoZeroByteRead, connectionLimiter), m_timeoutFilter(*this, socketAllocator, m_timerQueue), m_welcomeMessage(welcomeMessage) { }
void CSocketServer::OnConnectionEstablished( IStreamSocket &socket, const IAddress & /*address*/) { Output(_T("OnConnectionEstablished")); socket.Write(m_welcomeMessage.c_str(), GetStringLengthAsDWORD(m_welcomeMessage)); m_timeoutFilter.SetReadTimeout(socket, 1000, *this, 1); socket.TryRead(); }
SetReadTimeout()
on the connection filter and this sets a reoccurring timer on the connection. The timer is set after every read completes on the connection and when the timer goes off (i.e. when a read does not complete within the given timeout) the OnTimer()
method of the timer callback is called. and the user data (in this case the constant value 1
) is passed to the callback. Our implementation of OnTimer()
looks like this. void CSocketServer::OnTimer( IStreamSocket &socket, TimerCallback::UserData userData) { if (userData < 5) { const string message = "Read timeout! " + ToStringA(userData) + "\r\n"; socket.Write(message.c_str(), GetStringLengthAsDWORD(message)); const Milliseconds timeout = static_cast<Milliseconds>(userData); m_timeoutFilter.SetSingleReadTimeout(socket, 1000 * timeout, *this, timeout + 1); } else { const string message = "Too many timeouts!\r\n"; socket.Write(message.c_str(), GetStringLengthAsDWORD(message)); socket.Shutdown(ShutdownSend); } }
SetSingleReadTimeout()
which means that the timer is not reset automatically when a read completes. This means that if you send data after the timer has gone off once or twice then the timer is reset back to a one second timer as the reoccurring timer is used.