Hey, zuerst einmal musst du, wie oben schon genannt, die Programmiersprache die Dir gefällt oder dazu geeignet ist aussuchen.
Du musst Fähigkeiten erfüllen wie Erfahrungen in
- Multi-Threading
- Binary reading & writing
- Packet Managing
- Filesystem Managing
- Logging
- (Als NLP) CPU Architektur
- wissen von Dynamic & Static IP Handling
- (Als NLP) Memory al-/delocation
Wenn du noch ein Anfänger, oder kein Freund von eigenen Bibliotheken schreiben bist,
dann solltest du zum .NET Framework 4.5/4.6 greifen. Unterdem .NET Framework agieren folgende brauchbare Sprachen:
- C#
- Visual Basic
- C++/CLI
- Oxygene
Damit bist du zum Beispiel bei einem "commercial used" Server mit automatisierten Updates einen Schritt weiter als einem Native-L-Programmer, da du Zugriff auf Bibliotheken hast die dir das Auslesen einer XML per HTTP ermöglichen, dir erlauben mehrere Datentypen zu konvertieren ohne großen Aufwand.
Falls du aber schon Fortgeschritten und ein Freund von eigenen Bibliotheken schreiben bist, stehen dir
- C
- C++
- Ada (A#)
- Rust
- Perl
- Erlang
und viele weitere zur Verfügung! Nehmen wir an, du hast dich für C & C++ entschieden. C für das "Directory-Handling" & C++ für den eigentlich Teil.
Was du nun jedoch beachten solltest ist, dass dir keine Bibliothek zur Verfügung steht die dir direkt das Auslesen einer XML per HTTP erlaubt. Versuchen wir anhand eines Beispiels zu erleutern wie kompliziert (aber auch Spaßig) es ist mit native code zu arbeiten. Wir wollen einen kleinen simplen, nicht so fortgeschrittenen Updater schreiben. Was zu beachten ist HTTP & XML reading;
- fstream, ifstream & ofstream sind schließlich lokal
Erstellen wir erstmals eine Header-Datei namens ExternC.h:
/**
###########################################################
##### @Author: RegeretSam #####
##### Date: 1 November 2015 #####
##### File-Type: C/C++ Header File #####
##### Purpose: Logging Handling #####
###########################################################
**/
#ifndef EXTERNC_H
#define EXTERNC_H
extern "C"
{
#include <stdio.h>
#include <stdlib.h>
#include <direct.h>
typedef enum
{
HttpError,
DirError,
Output
} FileTypes;
FILE *pFileTXT;
const char * logFile;
void CreateVersionFileWithContent(const char * String, const char * destination)
{
pFileTXT = fopen(destination, "w+");
if (pFileTXT != NULL)
{
fputs(String, pFileTXT);
fclose(pFileTXT);
}
}
void Log(const char * String, FileTypes type)
{
switch (type)
{
case HttpError:
logFile = "Logs/HttpError.txt";
break;
case DirError:
logFile = "Logs/ExternC_Error.txt";
break;
case Output:
logFile = "Logs/Output.txt";
break;
}
pFileTXT = fopen(logFile, "ab+");
if (pFileTXT != NULL)
{
fprintf(pFileTXT, String);
fclose(pFileTXT);
}
}
void CreateFolder(const char *path)
{
if (_mkdir(path) != 0)
Log("void CreateFolder(const char *path): Successfull found/created directory!\r\n\r\n", Output);
else
Log("void CreateFolder(const char *path): Can\'t create directory!\r\n\r\n", DirError);
}
}
#endif /* EXTERNC_H */
Alles anzeigen
Perfekt! Unser kleines C-Skript ist bereit und kann nun C++ Unterstützen.
Nun erstellen wir eine Header-Datei namens PackageManager.h in der wir per 'Namespace' strukturiert vorgehen:
/**
###########################################################
##### @Author: RegeretSam #####
##### Date: 31 October 2015 #####
##### File-Type: C/C++ Header File #####
##### Purpose: Package Manager #####
###########################################################
**/
#ifndef PACKAGEMANAGER_H
#define PACKAGEMANAGER_H
namespace PackageManager
{
int FileExists(std::string destination);
void CreateFolders();
std::string GetCurrentVersion();
std::string GetPatchOnlyVersion(std::string destination);
void GetPatchStamp(std::string destination, int code);
void DownloadFile(std::string destination);
void Update(std::string destination);
}
#endif /* PACKAGEMANAGER_H */
Alles anzeigen
& we're done. Nice! Bevor wir mit der C++-Datei PackageManager.cpp anfangen, lädst du dir die Chilkat- & rapidxml-Bibliothek herunter. Binde diese in dein Projekt mitein, oder verlinke mit -I (gcc/g++);
VORSICHT: Chilkat & rapidxml werden in diesem Beispiel nur verwendet, um die Antwort hier, die eh nicht schon groß genug ist, nicht zu vergrößern!
Okay, you're done? Nice; Jetzt erstellen wir die C++-Datei PackageManager.cpp:
/**
###########################################################
##### @Author: RegeretSam #####
##### Date: 1 November 2015 #####
##### File-Type: C/C++ Header File #####
##### Purpose: Package Manager #####
###########################################################
**/
#include <CkHttp.h>
#include <iostream>
#include <string>
#include <vector>
#include <fstream>
#include <rapidxml.hpp>
#include "ExternC.h"
#include "PackageManager.h"
#include <set>
using namespace rapidxml;
std::string PackageEnd;
std::string PackageVersion;
int PackageManager::FileExists(std::string destination)
{
std::ifstream in(destination.c_str());
if (in.is_open())
{
in.close();
return 1;
}
else
{
in.close();
return 0;
}
}
void PackageManager::CreateFolders()
{
CreateFolder("C:\\ProgramData\\Server\\");
CreateFolder("C:\\ProgramData\\Server\\Data\\");
CreateFolder("C:\\ProgramData\\Server\\Patch\\");
CreateFolder("C:\\ProgramData\\Server\\Saved\\");
}
std::string PackageManager::GetCurrentVersion()
{
std::ifstream in("C:\\ProgramData\\Server\\Saved\\version.xml");
Log("Successfull opened the version file with CurrentVersion(std::string destination)!\r\n\r\n", Output);
xml_document<> doc;
std::vector<char> buffer((std::istreambuf_iterator<char>(in)), std::istreambuf_iterator<char>());
buffer.push_back('\0');
doc.parse<0>(&buffer[0]);
xml_node<>* nodeVersion = doc.first_node();
std::string retVal(nodeVersion->value());
in.close();
Log("Successfull closed the version file with CurrentVersion(std::string destination)!\r\n\r\n", Output);
return retVal;
}
std::string PackageManager::GetPatchOnlyVersion(std::string destination)
{
if (FileExists("C:\\ProgramData\\Server\\Data\\update.xml") != 1)
{
CkHttp http;
bool success;
success = http.UnlockComponent("HTTP-DOWNLOAD-FILE-XML");
if (success != true)
{
Log(http.lastErrorText(), HttpError);
Log("\n", HttpError);
}
success = http.Download("http://X.XXX.XXX.XXX/api/update.xml", destination.c_str());
if (success != true)
{
Log(http.lastErrorText(), HttpError);
Log("\n", HttpError);
}
Log("void GetPatchOnlyVersion(std::string destination) downloaded successfull the first file!\r\n\r\n", Output);
}
std::string line;
std::ifstream in(destination.c_str());
if (in.is_open())
Log("void GetPatchOnlyVersion(std::string destination) opened successfull the first file!\r\n\r\n", Output);
xml_document<> doc;
std::vector<char> buffer((std::istreambuf_iterator<char>(in)), std::istreambuf_iterator<char>());
buffer.push_back('\0');
doc.parse<0>(&buffer[0]);
xml_node<>* nodePackageVersion = doc.first_node()->first_node();
PackageVersion = nodePackageVersion->value();
in.close();
remove(destination.c_str());
Log("void GetPatchOnlyVersion(std::string destination) closed successfull the first file!\r\n\r\n", Output);
Log("void GetPatchOnlyVersion(std::string destination) deleted successfull the downloaded file!\r\n\r\n", Output);
return PackageVersion;
}
void PackageManager::GetPatchStamp(std::string destination, int code)
{
CkHttp http;
bool success;
success = http.UnlockComponent("HTTP-DOWNLOAD-FILE-XML");
if (success != true)
{
Log(http.lastErrorText(), HttpError);
Log("\n", HttpError);
return;
}
success = http.Download("http://X.XXX.XXX.XXX/api/update.xml", destination.c_str());
if (success != true)
{
Log(http.lastErrorText(), HttpError);
Log("\n", HttpError);
return;
}
Log("void GetVersion(std::string destination) downloaded successfull the first file!\r\n\r\n", Output);
std::string line;
std::ifstream in(destination.c_str());
if (in.is_open())
Log("void GetVersion(std::string destination) opened successfull the first file!\r\n\r\n", Output);
xml_document<> doc;
std::vector<char> buffer((std::istreambuf_iterator<char>(in)), std::istreambuf_iterator<char>());
buffer.push_back('\0');
doc.parse<0>(&buffer[0]);
xml_node<>* nodePackageEnd = doc.first_node()->last_node();
xml_node<>* nodePackageVersion = doc.first_node()->first_node();
PackageEnd = nodePackageEnd->value();
PackageVersion = nodePackageVersion->value();
in.close();
remove(destination.c_str());
Log("void GetVersion(std::string destination) closed successfull the first file!\r\n\r\n", Output);
Log("void GetVersion(std::string destination) deleted successfull the downloaded file!\r\n\r\n", Output);
std::string VStamp = "<?xml version=\"1.0\" encoding=\"UTF - 8\"?><version>" + PackageVersion + "</version>";
CreateVersionFileWithContent(VStamp.c_str(), "C:\\ProgramData\\MSTRSRV\\Saved\\version.xml");
Log("Successfull read the data of the file! void GetVersion(std::string destination) was successfull!\r\n\r\n", Output);
Log("Downloading file on starting void DownloadFile(std::string destination)...\r\n\r\n", Output);
DownloadFile("C:\\ProgramData\\Server\\Patch\\patch.package");
}
void PackageManager::DownloadFile(std::string destination)
{
CkHttp http;
bool success;
success = http.UnlockComponent("HTTP-DOWNLOAD-FILE-UPDATE");
if (success != true)
{
Log(http.lastErrorText(), HttpError);
Log("\n", HttpError);
return;
}
std::string File = "patch" + PackageEnd;
std::string FullUrl = "http://X.XXX.XXX.XXX/api/updates/container/" + File;
success = http.Download(FullUrl.c_str(), destination.c_str());
if (success != true)
{
Log(http.lastErrorText(), HttpError);
Log("\n", HttpError);
return;
}
Log("void DownloadFile(std::string destination) was successfull!\r\n\r\n", Output);
Update("C:\\ProgramData\\Server\\Patch\\patch.package");
}
void PackageManager::Update(std::string destination)
{
std::streamoff size;
std::ifstream infile(destination.c_str(), std::ios::binary);
if (infile.is_open())
{
Log("void Update(std::string destination) opened successfull the patch file!\r\n\r\n", Output);
infile.seekg(0, std::ifstream::end);
size = infile.tellg();
infile.seekg(0);
std::set<std::string> dict;
std::string buffer;
while (std::getline(infile, buffer, '\0'))
dict.insert(buffer);
unsigned char * rawData = new unsigned char[buffer.length() + 1];
std::strcpy((char *)rawData, buffer.c_str());
std::ofstream MstrsrvFile("Server.exe", std::ios::binary);
if (MstrsrvFile.is_open())
{
Log("Successfull opened Masterserver.exe!\r\n\r\n", Output);
MstrsrvFile.write(reinterpret_cast<const char*>(rawData), size);
Log("Successfull wrote patch to Masterserver.exe\r\n\r\n", Output);
}
else
{
Log("void Update(std::string destination) can\'t open Masterserver.exe\r\n\r\n", DirError);
}
delete[] rawData;
MstrsrvFile.close();
infile.close();
}
else
{
Log("Error on void Update(std::string destination) - Failed to open patch file!\r\n\r\n", DirError);
}
}
Alles anzeigen
Die update.xml wird temporär heruntergeladen & nach dem Auslesen sofort wieder gelöscht! Daten die gespeichert werden müssen, werden im Ordner "Saved" verschrieben.
Nachdem die C++-Datei (Einstiegsmethode) main.cpp:
#include <iostream>
#include "PackageManager.h"
int main(void)
{
std::cout << "Updating..." << std::endl;
PackageManager::CreateFolders();
if (PackageManager::FileExists("Server.exe") != 0)
{
if (PackageManager::FileExists("C:\\ProgramData\\Server\\Saved\\version.xml") != 0)
{
if (PackageManager::GetCurrentVersion() == PackageManager::GetPatchOnlyVersion("C:\\ProgramData\\Server\\Data\\update.xml"))
{
std::cout << "You already have the updated version!" << std::endl;
}
else
{
PackageManager::GetPatchStamp("C:\\ProgramData\\Server\\Data\\update.xml", 0);
}
}
else
{
PackageManager::GetPatchStamp("C:\\ProgramData\\Server\\Data\\update.xml", 1);
}
}
else
{
//Log("Updater can\'t find Server.exe! Make sure the file is in the directory.", DirError);
std::cout << "Server.exe is not in directory!" << std::endl;
}
std::cout << "Update done!" << std::endl;
std::cin.get();
return 0;
}
Alles anzeigen
angefertigt wurde, kreieren wir nun die update.xml im Verzeichneis wie im Code oben angegeben:
<?xml version="1.0" encoding="UTF-8"?>
<update>
<version>0.1.0</version>
<type>patch></patch>
<root>container/</root>
<methodTags>Sockets;Stability;C;DLL;EXTERNAL</methodTags>
<PackageData>_11032015.package</PackageData>
</update>
und eine patch_11032015.package im Verzeichnis wie im Code oben angegeben:
/* Erstelle ein Hallo Welt Programm, öffne die Ausgabe-Datei mit dem HxD-Editor und exportiere sie. Füge die Ausgabe in diese Datei (patch_******.package) ein. */
Nachdem wir das nun alles haben, kompiliere das Projekt/die Skript-Dateien per Visual Studio/GCC/G++.
Erstelle mit Notepad++ eine leere Datei namens Server.exe und speichere sie beim Updater ab. Du kannst auch eine bestehende App verwenden, du musst sie eben nur in Server.exe umbennen! Führe den Updater aus & falls alles geklappt hat (was es auch sollte) kannst du Server.exe starten und schauen ob deine neue gewollte Ausgabe aus dem Patch übernommen wurde.
MfG,
RegeretSam
PS:
*Falls du einfachere und simplere Codes haben möchtest, adde mich in Skype: masteret.sam