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:
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user