Removed Multithreading, simplifying the server

Networking and multithreading working at the same time is really fucking
hard. It's better to just have the one thread, and not worry about speed
at this stage.
This commit is contained in:
Kayne Ruse
2013-12-01 15:21:00 +11:00
parent 6ccc874583
commit 1e0ed350fc
5 changed files with 23 additions and 257 deletions
+19 -54
View File
@@ -36,30 +36,6 @@ using namespace std;
int ClientInformation::counter = 0;
//-------------------------
//Define the network thread
//-------------------------
/* This thread sucks in the packets sent to the server, and pushes them onto the queue.
* This function is declared as a friend of ServerApplication, because I'm lazy
*/
int networkQueueThread(void* ptr) {
ServerApplication* app = reinterpret_cast<ServerApplication*>(ptr);
NetworkPacket packet;
while(app->running) {
//suck in the waiting packets
while(app->networkUtil.Receive()) {
memcpy(&packet, app->networkUtil.GetInData(), sizeof(NetworkPacket));
//this is important: keep track of the source address
packet.meta.srcAddress = app->networkUtil.GetInPacket()->address;
app->networkQueue.PushBack(packet);
}
SDL_Delay(10);
}
return 0;
}
//-------------------------
//Define the ServerApplication
//-------------------------
@@ -75,12 +51,6 @@ ServerApplication::~ServerApplication() {
void ServerApplication::Init(int argc, char** argv) {
//TODO: proper command line option parsing
//Check prerequisites
if (!sqlite3_threadsafe()) {
throw(runtime_error("Cannot run without thread safety"));
}
cout << "Thread safety confirmed" << endl;
//load config
config.Load("rsc\\config.cfg");
@@ -94,7 +64,7 @@ void ServerApplication::Init(int argc, char** argv) {
if (SDLNet_Init()) {
throw(runtime_error("Failed to init SDL_net"));
}
networkUtil.Open(config.Int("server.port"), sizeof(NetworkPacket));
network.Open(config.Int("server.port"), sizeof(NetworkPacket));
cout << "initialized SDL_net" << endl;
//Init SQL
@@ -116,26 +86,25 @@ void ServerApplication::Init(int argc, char** argv) {
getline(is, script, '\0');
is.close();
sqlite3_exec(database, script.c_str(), nullptr, nullptr, nullptr);
//setup the threads
networkQueueThread = SDL_CreateThread(&::networkQueueThread, this);
if (!networkQueueThread) {
throw(runtime_error("Failed to create the networkQueueThread"));
}
cout << "initialized networkQueueThread" << endl;
}
void ServerApplication::Loop() {
//debugging
NetworkPacket packet;
while(running) {
while(networkQueue.Size() > 0) {
try {
HandlePacket(networkQueue.PopFront());
//suck in the waiting packets & process them
try {
while(network.Receive()) {
memcpy(&packet, network.GetInData(), sizeof(NetworkPacket));
packet.meta.srcAddress = network.GetInPacket()->address;
HandlePacket(packet);
}
catch(exception& e) {
cerr << "Network Error: " << e.what() << endl;
}
};
}
catch(exception& e) {
cerr << "Network Error: " << e.what() << endl;
}
//give the computer a break
SDL_Delay(10);
@@ -143,12 +112,8 @@ void ServerApplication::Loop() {
}
void ServerApplication::Quit() {
//catch all signal
running = false;
//members
SDL_WaitThread(networkQueueThread, nullptr);
networkUtil.Close();
network.Close();
//APIs
sqlite3_close_v2(database);
@@ -162,7 +127,7 @@ void ServerApplication::HandlePacket(NetworkPacket packet) {
//send back the server's name
packet.meta.type = NetworkPacket::Type::BROADCAST_RESPONSE;
snprintf(packet.serverInfo.name, PACKET_STRING_SIZE, "%s", config["server.name"].c_str());
networkUtil.Send(&packet.meta.srcAddress, &packet, sizeof(NetworkPacket));
network.Send(&packet.meta.srcAddress, &packet, sizeof(NetworkPacket));
break;
case NetworkPacket::Type::JOIN_REQUEST: {
//TODO: prevent duplicate logins from the same address?
@@ -178,14 +143,14 @@ void ServerApplication::HandlePacket(NetworkPacket packet) {
//send the client their info
packet.meta.type = NetworkPacket::Type::JOIN_RESPONSE;
packet.clientInfo.index = newClient.index;
networkUtil.Send(&newClient.address, &packet, sizeof(NetworkPacket));
network.Send(&newClient.address, &packet, sizeof(NetworkPacket));
cout << "connect, total: " << clientInfo.size() << endl;
}
break;
case NetworkPacket::Type::DISCONNECT:
//disconnect the specified client
networkUtil.Send(&clientInfo[packet.clientInfo.index].address, &packet, sizeof(NetworkPacket));
network.Send(&clientInfo[packet.clientInfo.index].address, &packet, sizeof(NetworkPacket));
clientInfo.erase(packet.clientInfo.index);
cout << "disconnect, total: " << clientInfo.size() << endl;
@@ -200,7 +165,7 @@ void ServerApplication::HandlePacket(NetworkPacket packet) {
//disconnect all clients
packet.meta.type = NetworkPacket::Type::DISCONNECT;
for (auto& it : clientInfo) {
networkUtil.Send(&it.second.address, &packet, sizeof(NetworkPacket));
network.Send(&it.second.address, &packet, sizeof(NetworkPacket));
}
cout << "shutting down" << endl;
+4 -8
View File
@@ -24,19 +24,18 @@
//networking
#include "network_packet.hpp"
#include "thread_safe_queue.hpp"
#include "udp_network_utility.hpp"
//APIs
#include "sqlite3/sqlite3.h"
#include "SDL/SDL.h"
#include "SDL/SDL_thread.h"
//misc
#include "config_utility.hpp"
#include "world_room.hpp"
//STL
#include <map>
#include <queue>
//hold the client info
struct ClientInformation {
@@ -56,14 +55,12 @@ public:
void Loop();
void Quit();
friend int networkQueueThread(void*);
private:
void HandlePacket(NetworkPacket);
//networking
UDPNetworkUtility networkUtil;
ThreadSafeQueue<NetworkPacket> networkQueue;
SDL_Thread* networkQueueThread = nullptr;
UDPNetworkUtility network;
std::queue<NetworkPacket> networkQueue;
//database
sqlite3* database = nullptr;
@@ -71,7 +68,6 @@ private:
//misc
bool running = true;
ConfigUtility config;
WorldRoom worldRoom;
std::map<int, ClientInformation> clientInfo;
};
-68
View File
@@ -1,68 +0,0 @@
#ifndef THREADSAFEQUEUE_HPP_
#define THREADSAFEQUEUE_HPP_
#include "SDL/SDL_thread.h"
#include <deque>
#include <stdexcept>
/* This container is a thread safe reimplementation of std::queue.
*/
template<typename T, class Container = std::deque<T>>
class ThreadSafeQueue {
public:
ThreadSafeQueue() {
lock = SDL_CreateSemaphore(1);
if (!lock) {
throw(std::runtime_error("Failed to create ThreadSafeQueue::lock"));
}
}
~ThreadSafeQueue() {
SDL_DestroySemaphore(lock);
}
T PushBack(T t) {
SDL_SemWait(lock);
container.push_back(t);
SDL_SemPost(lock);
return t;
}
T PeekFront() {
T t;
SDL_SemWait(lock);
if (container.size() > 0) {
t = container[0];
}
SDL_SemPost(lock);
return t;
}
T PopFront() {
T t;
SDL_SemWait(lock);
if (container.size() > 0) {
t = container[0];
container.pop_front();
}
SDL_SemPost(lock);
return t;
}
int Size() {
//can't be sure if std::deque::size() is thread safe
int ret;
SDL_SemWait(lock);
ret = container.size();
SDL_SemPost(lock);
return ret;
}
private:
Container container;
SDL_sem* lock;
};
#endif
-83
View File
@@ -1,83 +0,0 @@
/* Copyright: (c) Kayne Ruse 2013
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
*/
#include "world_room.hpp"
#include <iostream>
#include <stdexcept>
using namespace std;
//-------------------------
//Define the WorldRoom's thread
//-------------------------
int worldRoomThread(void* ptr) {
WorldRoom* room = reinterpret_cast<WorldRoom*>(ptr);
try {
room->Init();
room->Loop();
room->Quit();
}
catch(std::exception& e) {
cerr << "Fatal Room Error: " << e.what() << endl;
return 1;
}
return 0;
}
//-------------------------
//Define the WorldRoom's methods
//-------------------------
WorldRoom::WorldRoom() {
//
}
WorldRoom::~WorldRoom() {
//
}
void WorldRoom::Init() {
//
}
void WorldRoom::Loop() {
//
}
void WorldRoom::Quit() {
//
}
void WorldRoom::HandlePacket(NetworkPacket packet) {
switch(packet.meta.type) {
// case NetworkPacket::Type::SYNCHRONIZE:
// //
// break;
//handle errors
default:
throw(runtime_error("Unknown NetworkPacket::Type encountered"));
break;
}
}
-44
View File
@@ -1,44 +0,0 @@
/* Copyright: (c) Kayne Ruse 2013
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
*/
#ifndef WORLDROOM_HPP_
#define WORLDROOM_HPP_
#include "network_packet.hpp"
#include "thread_safe_queue.hpp"
class WorldRoom {
public:
WorldRoom();
~WorldRoom();
void Init();
void Loop();
void Quit();
ThreadSafeQueue<NetworkPacket>* GetNetworkQueue() { return &networkQueue; }
private:
void HandlePacket(NetworkPacket);
ThreadSafeQueue<NetworkPacket> networkQueue;
};
#endif