Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Server Client managment  (Read 3356 times)

0 Members and 1 Guest are viewing this topic.

Blackspell

  • Newbie
  • *
  • Posts: 4
    • View Profile
Server Client managment
« on: September 15, 2010, 07:10:14 pm »
I have wrote a Server-Client application which sends a vector to the server. The server collcet the vecors from all Clients and send them to all. But this works verly slow (~5fps, and im only sending 1 vector).
I searched a bit in the forum and collected some ideas and now i have some questions:

-Should i use TCP or UDP? UDP is faster but how can i chech if all the data i sended arrived (if this is necessary, look to the next question)

-What should i send? If i send the nex Position every frame it isnt important that every packet arrives because the new one will correct it all. But if i only send weather a key is pressed or not the clients could become asyncron if they miss a few packets. And how can i correct mistakes?

-Should I use non blocking calls or a Selector?

PS: Im not a native speaker so there may be some mistakes in in what i have wrote :oops:

Finn

  • Jr. Member
  • **
  • Posts: 90
    • View Profile
Server Client managment
« Reply #1 on: September 15, 2010, 07:42:02 pm »
Normally you just tell the server that you want to move. Then the server checks if you may move and if so he sends the new position to the clients

Mindiell

  • Hero Member
  • *****
  • Posts: 1261
    • ICQ Messenger - 41484135
    • View Profile
Server Client managment
« Reply #2 on: September 16, 2010, 09:16:29 am »
I really think you should use non-blocking sockets.

But if we could see the source code, it will be easier for us ;)
Mindiell
----

Blackspell

  • Newbie
  • *
  • Posts: 4
    • View Profile
Server Client managment
« Reply #3 on: September 18, 2010, 01:03:38 pm »
My Code (There are some German Comments in it but I think you will understand it):

Client:
Code: [Select]

//Moving Cubes 2 Client
//Includes
#include "stdafx.h"
#include <SFML/Network.hpp>
#include <SFML/System.hpp>
#include <iomanip>
#include <iostream>
#include <irrlicht.h>
#include <IrrIni.h>

//Libaries
#pragma comment(lib, "Irrlicht.lib")
#pragma comment(lib, "IrrIni.lib")

//Namcespaces
using namespace irr;
using namespace core;
using namespace scene;
using namespace video;
using namespace gui;
using namespace io;

//Classes
#include "cCube.h"

//Variables
int iClientNumber;
char name[256];
char input[256];
bool binput = false;
bool bThreadRunning = false;

//Functions
void Input(void* UserData)
{
std::cin.getline(input,256);
binput = true;
bThreadRunning = false;
}
;



int main()
{
printf("--------------------Chat--------------------\n\n");
printf("Please enter your Nickname...\n");
std::cin.getline(name,256);
sf::SocketTCP Socket;
printf("\nPlease enter the ip of the Server.\n");
sf::IPAddress ip;
std::cin >> ip;
std::cin.sync();
printf("Connecting to Server...\n");
if(Socket.Connect(12345, ip) != sf::Socket::Done)
{
//Error
printf("Error during connecting!\nProgramm will close in 2 seconds!\n");
Sleep(2000);
Socket.Close();
return 0;
}
printf("Connected to the Server!\n\nChat started!\n\n");

Socket.SetBlocking(false);

sf::Thread Thread(&Input);

sf::Packet Packet;

sf::SelectorTCP Selector;
Selector.Add(Socket);

while(true)
{
if(bThreadRunning == false)
{
bThreadRunning = true;
Thread.Launch();
}

int iSocketReady = Selector.Wait(0.1f);

if(iSocketReady == 1) //Data can be recieved
{
if(Socket.Receive(Packet) == sf::Socket::Done)
{
//Recive Data
bool bGameStarted;
char message[256];

Packet >> bGameStarted;
if(bGameStarted == true)
{
goto Game;
}
Packet >> message;  //der Boolwert ist ja schon raus!!!
printf("%s\n",message);
}
else
{
//Eorror during Reciving
//printf("Error during receiving the message...\nThe Server is probably down...\nExit with Enter...\n");
//return 0;
}
}
if(binput == true)
{
binput = false;

char message[256] = "";
strcat(message,name);
strcat(message," : ");
strcat(message,input);

sf::Packet Packet;
Packet << message; //Messsage ins Packet schreiben
if(Socket.Send(Packet) == sf::Socket::Done)
{
//Data Sended
}
}
}

Game:;
//Create Cubes
cCube Cube[4];

//Read used Clients and Client number
Packet >> Cube[0].bUsed >> Cube[1].bUsed >> Cube[2].bUsed >> Cube[3].bUsed >> iClientNumber;

//Socket auf non-blocking stellen
Socket.SetBlocking(false);

//Device erstellen
IrrlichtDevice* device = createDevice(EDT_DIRECT3D9, dimension2d<s32>(640, 480), 32, false, false, false, 0);
if(device == 0)
{
printf("\nError while creating Device! Programm will close in 2 seconds!\n");
Sleep(2000);
return 1;
}

//Pointer erstellen
IVideoDriver* driver = device->getVideoDriver();
ISceneManager* smgr = device->getSceneManager();
IGUIEnvironment* gui = device->getGUIEnvironment();

//Cubes einstellen
for(int i = 0;i < 4; ++i)
{
if(Cube[i].bUsed == true)
{
Cube[i].Startup();
Cube[i].Mesh = smgr->getMesh("Cube.3ds");
Cube[i].Node = smgr->addOctTreeSceneNode(Cube[i].Mesh->getMesh(0));
if(iClientNumber == i)//Wenn man selbst Client i ist
{
Cube[i].Camera = smgr->addCameraSceneNode();
Cube[i].Camera->setPosition(vector3df(0,8,6));
Cube[i].Camera->setTarget(Cube[i].Node->getPosition() + vector3df(0,4,0));
}
}
}

sf::Clock Clock;

while(device->run())//Hauptschleife
{
//Timer
float fElapsedTime = Clock.GetElapsedTime();
Clock.Reset();

//starte Scene
driver->beginScene(true, true, SColor(255,100,100,140));

//Daten empfangen
if(Socket.Receive(Packet) == sf::Socket::Done)
{
int iCube;
int iKeycode;
Packet >> iCube >> iKeycode;

if(iKeycode >= 16)
{
Cube[iCube].bForward = !Cube[iCube].bForward;
iKeycode = iKeycode - 16;
}
if(iKeycode >= 8)
{
Cube[iCube].bBackward = !Cube[iCube].bBackward;
iKeycode = iKeycode - 8;
}
if(iKeycode >= 4)
{
Cube[iCube].bLeft = !Cube[iCube].bLeft;
iKeycode = iKeycode - 4;
}
if(iKeycode >= 2)
{
Cube[iCube].bRight = !Cube[iCube].bRight;
iKeycode = iKeycode - 2;
}
//printf("Recived Data fromClient %i!\n", iCube);
}

//Eigenen Keycode akualisieren
if(device->isWindowFocused() == true)
{
if(Cube[iClientNumber].UpdateKeyStates() == true) //Wenn sich was geändert hat
{
//Daten senden
Packet.Clear();
Packet << iClientNumber << Cube[iClientNumber].iKeycode;
Socket.Send(Packet);
}
}


//Cubes Bewegen
for(int i = 0;i < 4; ++i)
{
if(Cube[i].bUsed == true)
{
Cube[i].Move(fElapsedTime);
}
}

//printf("frame completed!\n");

//Rendern
smgr->drawAll();
gui->drawAll();
driver->endScene();
}
device->drop();
return 0;  
}


The Class cCube.h:
Code: [Select]

#include <windows.h>
#include <IrrIni.h>
class cCube
{
//Private Area
private:
//Variables
float       fSpeed;
float       fRotSpeed;
char        kForward;
char        kBackward;
char        kLeft;
char        kRight;

//Methods
//...

//Puplic Area
public:
//Variables
scene::ICameraSceneNode* Camera;
scene::IAnimatedMesh* Mesh;
scene::ISceneNode* Node;

bool bUsed;

bool        bForward;
bool        bBackward;
bool        bLeft;
bool        bRight;

int iKeycode;




//Methods
bool UpdateKeyStates()
{
bool bChanged = false;
iKeycode = 0;
if(GetAsyncKeyState(kForward) & 0x8000)
{
if(bForward == false)
{
bChanged = true;
iKeycode = iKeycode + 16;
}
bForward = true;
}
else
{
if(bForward == true)
{
bChanged = true;
iKeycode = iKeycode + 16;
}
bForward = false;
}
if(GetAsyncKeyState(kBackward) & 0x8000)
{
if(bBackward == false)
{
bChanged = true;
iKeycode = iKeycode + 8;
}
bBackward = true;
}
else
{
if(bBackward == true)
{
bChanged = true;
iKeycode = iKeycode + 8;
}
bBackward = false;
}
if(GetAsyncKeyState(kLeft) & 0x8000)
{
if(bLeft == false)
{
bChanged = true;
iKeycode = iKeycode + 4;
}
bLeft = true;
}
else
{
if(bLeft == true)
{
bChanged = true;
iKeycode = iKeycode + 4;
}
bLeft = false;
}
if(GetAsyncKeyState(kRight) & 0x8000)
{
if(bRight == false)
{
bChanged = true;
iKeycode = iKeycode + 2;
}
bRight = true;
}
else
{
if(bRight == true)
{
bChanged = true;
iKeycode = iKeycode + 2;
}
bRight = false;
}  
return bChanged;
}
void Move(float fElapsedTime)
{
vector3df vMovement;
vector3df vNewPos = Node->getPosition();
matrix4 mTransformation;

if(bForward == true)
{
mTransformation = Node->getAbsoluteTransformation();
vMovement = vector3df(0,0,-fSpeed);
mTransformation.rotateVect(vMovement);
vNewPos = vNewPos + vMovement * fElapsedTime;
}
if(bBackward == true)
{
mTransformation = Node->getAbsoluteTransformation();
vMovement = vector3df(0,0,fSpeed);
mTransformation.rotateVect(vMovement);
vNewPos = vNewPos + vMovement * fElapsedTime;
}
if(bLeft == true)
{
mTransformation = Node->getAbsoluteTransformation();
vMovement = vector3df(fSpeed,0,0);
mTransformation.rotateVect(vMovement);
vNewPos = vNewPos + vMovement * fElapsedTime;
}
if(bRight == true)
{
mTransformation = Node->getAbsoluteTransformation();
vMovement = vector3df(-fSpeed,0,0);
mTransformation.rotateVect(vMovement);
vNewPos = vNewPos + vMovement * fElapsedTime;
}
Node->setPosition(vNewPos);
}



void Startup()
{
//Open Ini
IrrIni* ini = createIniFile("config.ini");
//Load Ini and close if error
if(!ini->load())
{
ini->drop();
}
//Read Data
fSpeed = ini->getValueF("cCube","fSpeed");
fRotSpeed = ini->getValueF("cCube","fRotSpeed");
kForward = ini->getValueK("cCube","kForward");
kBackward = ini->getValueK("cCube","kBackward");
kLeft = ini->getValueK("cCube","kLeft");
kRight = ini->getValueK("cCube","kRight");

//Close Ini
ini->drop();

bForward = false;
bBackward = false;
bLeft = false;
bRight = false;
}
};


The Server:
Code: [Select]

//Moving Cubes 2 Server
//Includes
#include "stdafx.h"
#include <SFML/System.hpp>
#include <SFML/Network.hpp>
#include <iomanip>
#include <iostream>
#include <windows.h>
#include <stdio.h>
#include <string>

//Libaries

//Klassen
#include "cClient.h"



int main()
{
sf::SocketTCP Listener;
if(!Listener.Listen(12345))
{
//Error
printf("Error during listening!\nProgramm will close in 2 seconds!\n");
Sleep(2000);
Listener.Close();
return 0;
}
printf("Listening...\n");

cClient Client[4];

for(int i = 0;i < 4; ++i)
{
Client[i].bUsed = false;
}

sf::Packet Packet;
sf::SelectorTCP Selector;
Selector.Add(Listener);

while(true)
{
int iReadableSockets = Selector.Wait(0.01);
for(int i = 0;i < iReadableSockets; ++i)
{
sf::SocketTCP Socket = Selector.GetSocketReady(i);

if(Socket == Listener)
{
//New Connection
for(int i = 0;i < 4; ++i)
{
if(Client[i].bUsed == false)
{
Client[i].bUsed = true;
Listener.Accept(Client[i].Socket);
Selector.Add(Client[i].Socket);
printf("New Client connected (%i)!\n",i);
break; //for schleife verlassen;
}
}
}
else //Socket ist ein Client
{
if(Socket.Receive(Packet) == sf::Socket::Done)
{
char message[256];
Packet >> message;
printf("%s\n",message);
Packet.Clear();
Packet << false << message;
//Message an alle Clients Schicken
for(int i = 0;i < 4; ++i)
{
if(Client[i].bUsed == true)
{
if(Client[i].Socket.Send(Packet) != sf::Socket::Done)
{
//Error
printf("Error while sending the Packet to Client %i!\nClient %i was removed.\n",i,i);
Client[i].bUsed = false;
Selector.Remove(Client[i].Socket);
}
}
}
}
else
{
// Error : we better remove the socket from the selector
//Selector.Remove(Socket); */
}
}
}
//Auf Spielstart überprüfen
if(GetAsyncKeyState('Q') & 0x8000)
{
printf("\nGame started!\n\n");
//Welche Spieler und Clientnummer senden
for(int i = 0;i < 4; ++i)
{
if(Client[i].bUsed == true)
{
Packet.Clear();
Packet << true << Client[0].bUsed << Client[1].bUsed << Client[2].bUsed << Client[3].bUsed << i;
Client[i].Socket.Send(Packet);
}
}

while(true) //Hauptschleife
{
int iReadableSockets = Selector.Wait();
for(int i = 0;i < iReadableSockets; ++i) //Für jeden gesendet Client
{
sf::SocketTCP Socket = Selector.GetSocketReady(i);
Socket.Receive(Packet);
int iClient;
int iKeycode;
Packet >> iClient >> iKeycode;  
Packet.Clear();
Packet << iClient << iKeycode;  

for(int i = 0;i < 4; ++i)
{
if(Client[i].bUsed == true && i != iClient) //Nicht and den Sender zurücksenden
{
Client[i].Socket.Send(Packet);
}
}
printf("Data from Client %i sended!\n", iClient);
}
}
}
}
    return 0;
}

The Class cClient included in the Server only contains the Socket "Socket" and the bolean "bUsed".

Im using Irrlicht as 3d Engine.

This Code works almost fine.
The only Problem is that the Position of the Cubes on each Client is a bit different.

Mindiell

  • Hero Member
  • *****
  • Posts: 1261
    • ICQ Messenger - 41484135
    • View Profile
Server Client managment
« Reply #4 on: September 20, 2010, 09:11:12 am »
Your code is very strange : You are using some std::cin and printf, mixing C and C++.

By the way, this is not the cause of your FPS :)
- Are you writing something on the console while drawing ?
- Are you compiling in Debug ?
- Can you calculate time used in some functions ? (Maybe you can deactivate the GUI drawing to see what is happening ?)
- Can you make a code without IrrLicht in order to see how the network is important in your code ?
- Try to review your code :
     - The client is using a Selector : why ?
     - You are setting the Socket to non blocking twice
     - Be sure to stop the Thread when the game is beginning
     - You are basing the movement of cubes on the time elapsed on each client. Depending on the network and the computer used, results will be completely different !
Mindiell
----