Fixed design problem: Thread objects can now be created in any context.
Sender thread output queue is now limited. Server thread now terminates correctly. Now cloning packets when sending them to multiple recipients. Fixed one thread issue - GameStart still needs to be made thread safe.
This commit is contained in:
@@ -44,10 +44,14 @@ private:
|
||||
ServerRecvThread::ServerRecvThread()
|
||||
{
|
||||
m_senderCallback.reset(new ServerSenderCallback(*this));
|
||||
m_sender.reset(new SenderThread(GetSenderCallback()));
|
||||
m_receiver.reset(new ReceiverHelper);
|
||||
}
|
||||
|
||||
ServerRecvThread::~ServerRecvThread()
|
||||
{
|
||||
CleanupConnectQueue();
|
||||
CleanupSessionMap();
|
||||
}
|
||||
|
||||
void
|
||||
@@ -58,16 +62,18 @@ ServerRecvThread::StartGame()
|
||||
}
|
||||
|
||||
void
|
||||
ServerRecvThread::SendToAllClients(boost::shared_ptr<NetPacket> packet)
|
||||
ServerRecvThread::SendToAllPlayers(boost::shared_ptr<NetPacket> packet)
|
||||
{
|
||||
// TODO: possible race condition if used in multithreading
|
||||
SocketSessionMap::iterator i = m_sessions.begin();
|
||||
SocketSessionMap::iterator end = m_sessions.end();
|
||||
// This function needs to be thread safe.
|
||||
boost::mutex::scoped_lock lock(m_sessionMapMutex);
|
||||
|
||||
SocketSessionMap::iterator i = m_sessionMap.begin();
|
||||
SocketSessionMap::iterator end = m_sessionMap.end();
|
||||
|
||||
while (i != end)
|
||||
{
|
||||
// TODO: desparately need clone here, this is very dangerous.
|
||||
GetSender().Send(packet, i->first);
|
||||
// Send each client a copy of the packet.
|
||||
GetSender().Send(boost::shared_ptr<NetPacket>(packet->Clone()), i->first);
|
||||
++i;
|
||||
}
|
||||
}
|
||||
@@ -83,9 +89,6 @@ void
|
||||
ServerRecvThread::Main()
|
||||
{
|
||||
SetState(SERVER_INITIAL_STATE::Instance());
|
||||
|
||||
m_sender.reset(new SenderThread(GetSenderCallback()));
|
||||
m_receiver.reset(new ReceiverHelper);
|
||||
GetSender().Run();
|
||||
|
||||
try
|
||||
@@ -114,7 +117,8 @@ ServerRecvThread::Main()
|
||||
GetSender().SignalTermination();
|
||||
GetSender().Join(SENDER_THREAD_TERMINATE_TIMEOUT);
|
||||
|
||||
// TODO: clear connection queue
|
||||
CleanupConnectQueue();
|
||||
CleanupSessionMap();
|
||||
}
|
||||
|
||||
SOCKET
|
||||
@@ -122,31 +126,32 @@ ServerRecvThread::Select()
|
||||
{
|
||||
SOCKET retSock = INVALID_SOCKET;
|
||||
|
||||
if (m_sessions.empty())
|
||||
SOCKET maxSock = INVALID_SOCKET;
|
||||
fd_set rdset;
|
||||
FD_ZERO(&rdset);
|
||||
|
||||
{
|
||||
boost::mutex::scoped_lock lock(m_sessionMapMutex);
|
||||
SocketSessionMap::iterator i = m_sessionMap.begin();
|
||||
SocketSessionMap::iterator end = m_sessionMap.end();
|
||||
|
||||
while (i != end)
|
||||
{
|
||||
SOCKET tmpSock = i->first;
|
||||
FD_SET(tmpSock, &rdset);
|
||||
if (tmpSock > maxSock)
|
||||
maxSock = tmpSock;
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
if (maxSock == INVALID_SOCKET)
|
||||
{
|
||||
Msleep(RECV_TIMEOUT_MSEC); // just sleep if there is no session
|
||||
}
|
||||
else
|
||||
{
|
||||
// wait for data
|
||||
SOCKET maxSock = 0;
|
||||
fd_set rdset;
|
||||
FD_ZERO(&rdset);
|
||||
|
||||
{
|
||||
SocketSessionMap::iterator i = m_sessions.begin();
|
||||
SocketSessionMap::iterator end = m_sessions.end();
|
||||
|
||||
while (i != end)
|
||||
{
|
||||
SOCKET tmpSock = i->first;
|
||||
FD_SET(tmpSock, &rdset);
|
||||
if (tmpSock > maxSock)
|
||||
maxSock = tmpSock;
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
struct timeval timeout;
|
||||
timeout.tv_sec = 0;
|
||||
timeout.tv_usec = RECV_TIMEOUT_MSEC * 1000;
|
||||
@@ -158,8 +163,9 @@ ServerRecvThread::Select()
|
||||
if (selectResult > 0) // one (or more) of the sockets is readable
|
||||
{
|
||||
// Check which socket is readable, return the first.
|
||||
SocketSessionMap::iterator i = m_sessions.begin();
|
||||
SocketSessionMap::iterator end = m_sessions.end();
|
||||
boost::mutex::scoped_lock lock(m_sessionMapMutex);
|
||||
SocketSessionMap::iterator i = m_sessionMap.begin();
|
||||
SocketSessionMap::iterator end = m_sessionMap.end();
|
||||
|
||||
while (i != end)
|
||||
{
|
||||
@@ -176,6 +182,34 @@ ServerRecvThread::Select()
|
||||
return retSock;
|
||||
}
|
||||
|
||||
void
|
||||
ServerRecvThread::CleanupConnectQueue()
|
||||
{
|
||||
boost::mutex::scoped_lock lock(m_connectQueueMutex);
|
||||
|
||||
// Sockets will be closed automatically.
|
||||
m_connectQueue.clear();
|
||||
}
|
||||
|
||||
void
|
||||
ServerRecvThread::CleanupSessionMap()
|
||||
{
|
||||
boost::mutex::scoped_lock lock(m_sessionMapMutex);
|
||||
|
||||
// We need to manually close all sockets for the sessions.
|
||||
// This is "not great", but there are some issues when
|
||||
// automatically closing them.
|
||||
SocketSessionMap::iterator i = m_sessionMap.begin();
|
||||
SocketSessionMap::iterator end = m_sessionMap.end();
|
||||
|
||||
while (i != end)
|
||||
{
|
||||
CLOSESOCKET(i->first);
|
||||
++i;
|
||||
}
|
||||
m_sessionMap.clear();
|
||||
}
|
||||
|
||||
ServerRecvState &
|
||||
ServerRecvThread::GetState()
|
||||
{
|
||||
@@ -193,9 +227,10 @@ boost::shared_ptr<SessionData>
|
||||
ServerRecvThread::GetSession(SOCKET sock)
|
||||
{
|
||||
boost::shared_ptr<SessionData> tmpSession;
|
||||
|
||||
SocketSessionMap::iterator pos = m_sessions.find(sock);
|
||||
if (pos != m_sessions.end())
|
||||
boost::mutex::scoped_lock lock(m_sessionMapMutex);
|
||||
|
||||
SocketSessionMap::iterator pos = m_sessionMap.find(sock);
|
||||
if (pos != m_sessionMap.end())
|
||||
{
|
||||
tmpSession = pos->second;
|
||||
}
|
||||
@@ -205,15 +240,17 @@ ServerRecvThread::GetSession(SOCKET sock)
|
||||
void
|
||||
ServerRecvThread::AddSession(boost::shared_ptr<ConnectData> connData, boost::shared_ptr<SessionData> sessionData)
|
||||
{
|
||||
SocketSessionMap::iterator pos = m_sessions.lower_bound(connData->GetSocket());
|
||||
boost::mutex::scoped_lock lock(m_sessionMapMutex);
|
||||
|
||||
SocketSessionMap::iterator pos = m_sessionMap.lower_bound(connData->GetSocket());
|
||||
|
||||
// If pos points to a pair whose key is equivalent to the socket, this handle
|
||||
// already exists within the list.
|
||||
if (pos != m_sessions.end() && connData->GetSocket() == pos->first)
|
||||
if (pos != m_sessionMap.end() && connData->GetSocket() == pos->first)
|
||||
{
|
||||
throw ServerException(ERR_SOCK_CONN_EXISTS, 0);
|
||||
}
|
||||
m_sessions.insert(pos, SocketSessionMap::value_type(connData->ReleaseSocket(), sessionData));
|
||||
m_sessionMap.insert(pos, SocketSessionMap::value_type(connData->ReleaseSocket(), sessionData));
|
||||
}
|
||||
|
||||
SenderThread &
|
||||
|
||||
Reference in New Issue
Block a user