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

Author Topic: Simple TCP connect between 2 PC's doesn't work  (Read 10400 times)

0 Members and 1 Guest are viewing this topic.

ingwik

  • Jr. Member
  • **
  • Posts: 65
    • View Profile
Simple TCP connect between 2 PC's doesn't work
« Reply #15 on: March 19, 2012, 03:33:54 pm »
Sorry Laurent, I think I've read about blocking and non-blocking calls in the forum and not in the lessons for 1.6 network.

My code isn't working. Why? I just don't know and it is so frustrating since I think I have followed your examples to create working code for a simple two player game.  But as I said, the code just stop at the check if it's done. No cout at all is sent to the player after that and the other sprite doesn't move. Just as if it never actually gets any packets.

Code: [Select]

void PlayerRecieve(class spelare &s)
  {
  spelsocket.SetBlocking(false); //Don't halt
  sf::Packet Received; //Create local packet
  spelare R; //Create local player
  if (spelsocket.Receive(Received) != sf::Socket::Done)
  return;

  if (Received >> R) //If packet isn't empty?
     {
      s.hastighetX = R.hastighetX; //give player new speed
      s.hastighetY = R.hastighetY;
      std::cout << "Recieved: " << std::endl; //Just for checking
       }
       else
      {std::cout << "Nothing recieved: " << std::endl;} //Just for checking
 }


//Ingemar

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Simple TCP connect between 2 PC's doesn't work
« Reply #16 on: March 19, 2012, 03:38:27 pm »
Do you keep on calling PlayerRecieve continuously until something happens?

By the way, you don't have to set the non-blocking mode everytime, once at init time is enough.
Laurent Gomila - SFML developer

ingwik

  • Jr. Member
  • **
  • Posts: 65
    • View Profile
Simple TCP connect between 2 PC's doesn't work
« Reply #17 on: March 19, 2012, 03:49:14 pm »
I have it in the game loop just before the movement. Speed is set to 100 * adjustment (ElapsedTime) to make me be able send integers for the velocity over the network. The function sets the speed on the other players sprite in X and Y, like this:

Code: [Select]
if (server == true)
PlayerRecieve(cow);
else
PlayerRecieve(boy);

boy.sprite.Move(boy.hastighetX * ElapsedTime,boy.hastighetY * ElapsedTime);
cow.sprite.Move(cow.hastighetX * ElapsedTime,cow.hastighetY* ElapsedTime);


If no change has been, PlayerRecieve wont do a thing and the speed is kept. The values for speed in X and Y are saved inside the class.

Quote from: "Laurent"

By the way, you don't have to set the non-blocking mode everytime, once at init time is enough.


Good to know, I'll change the code.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Simple TCP connect between 2 PC's doesn't work
« Reply #18 on: March 19, 2012, 03:54:01 pm »
Ok, looks good.

Now that the pieces of code that you show seem to be correct, it's hard to help you more. The error is probably in the higher-level logic of your program.

Instead of directly trying to make your game work, you should start with something minimal, and build on top of it incrementally, only adding something after the current step works as expected.
Laurent Gomila - SFML developer

ingwik

  • Jr. Member
  • **
  • Posts: 65
    • View Profile
Simple TCP connect between 2 PC's doesn't work
« Reply #19 on: March 19, 2012, 04:06:36 pm »
hmm. I have boiled it down to the " != sf::Socket::Done" routine. I need help to understand the diference between handling structs and simple numbers.

According to the examples on the homepage, this is the correct way to handle a recieving packet:

Code: [Select]
char Buffer[128];
std::size_t Received;
if ([Socketname].Receive(Buffer, sizeof(Buffer), [Packetname]) != sf::Socket::Done)
{
    // Error...
}


So, if I follow the code from the code example for sending structs between computers, I should use:
Code: [Select]
if ([Socketname].Receive([Packetname]) != sf::Socket::Done)
 return;


If I want to just check, I use this mixed code:
Code: [Select]

if ([Socketname].Receive([Packetname]) != sf::Socket::Done)
{
    // Error...
}


And here is the culprit that has annoyed me for hours. I'm getting the Error this way, but since the "return" statement is missing next code executes and I end up having the same movement for both sprites. I've checked what's going into the sending function and all values are fine. It's the recieving that doesn't work. If I use the routine that waits for a "return" value, I won't get anything to sprite no 2 and no other sprite is moved other than the one the player control on the local PC.

The odd thing is that if I use a very simple handle of structs in the game:

Sending:
Code: [Select]
sf::Int32 entete;
sf::Int32 chaine2;
sf::Int32 chaine3;

 if (Who == 's')
entete = 100;
 else
entete = 500;

 if (Who == 's')
chaine2 = 100;
 else
chaine2 = 500;

  if (Who == 's')
chaine3 = 100;
 else
chaine3 = 500;

sf::Packet paquet1;

spelare Bob;
Bob.ID = entete;
Bob.hastighetX = chaine2;
Bob.hastighetY = chaine3;
paquet1<< Bob;


Recieving
Code: [Select]
sf::Packet paquet2;
paquet2 >> Bob;


Everything actually works, even though it's handled outside the function and inside the Main code. The server (s) sends correct values and recieves the correct values from the client, without any kind of check if the socket is done.

So the question is; why is the game stopping at:
Code: [Select]
if ([Socketname].Receive([Packetname]) != sf::Socket::Done)
 return;

When it never halts in the send routine:
Code: [Select]
if ([Socketname].Send([Packetname]) != sf::Socket::Done)
 return;

It seems as if the recieving socket is never Done even when it's put in non-blocking mode.

If I remove this row from the function, nothing works (obviously), but as I said, it do work outside the function in the example above without check if the socket is ready or not.

I can obviously circumvent this issue by handling all calls inside the main loop and not using the socket check in a function at all, but I really want to understand what's going wrong here.

//Ingemar

ingwik

  • Jr. Member
  • **
  • Posts: 65
    • View Profile
Simple TCP connect between 2 PC's doesn't work
« Reply #20 on: March 20, 2012, 12:47:38 pm »
I'm giving up any tries to continue this kind of projekt. I just can't find a way to make it work. Here, I have narrowed down the code to a bare bone. If you hit space, you send the info to the other PC. It's not more complicated than that, but I've tried both with two copies on the same PC and with two different PC:s om the same network and it is nigh impossible to recieve anything and I can't send if I'm a server. As a client sending is just fine.

If someone smarter can find the bug, I'll be happy.


 
Code: [Select]
#include <iostream>
 #include <SFML/System.hpp>
 #include <SFML/Graphics.hpp>
 #include <SFML/Window.hpp>
 #include <SFML/Network.hpp>
 //#include <vector>
 #define SFML_STATIC //No extra DLL-filer
 
 class spelare
 {
 public:
  sf::Int32 ID; //0=pojke, 1=ko (sf::Uint8) ger ascii tecken
  sf::Int32 hastighetX; //Hastighet i X-led, kan vara negativ
  sf::Int32 hastighetY; //Hastighet i Y-led, kan vara negativ
  sf::Sprite sprite; //Bilden som representerar pojken eller kon
 };

  // Server = handles boy
  // Client = handles cow

 //--------------------------------------------------------------
 // Create packet structure
 //--------------------------------------------------------------
 
 sf::Packet &operator <<(sf::Packet &Packet, const spelare &C)
 {
    return Packet << C.ID << C.hastighetX << C.hastighetY;
 }
 
 sf::Packet &operator >>(sf::Packet &Packet, spelare &C)
 {
    return Packet >> C.ID >> C.hastighetX >> C.hastighetY;
 }
 

 // Create a global TCP socket
 sf::SocketTCP spelsocket;

  //Functions
  void RunClient(unsigned short Port);
  void RunServer(unsigned short Port);

  void PlayerSend(class spelare &s);
  void PlayerRecieve( class spelare &s);

 //---------------------------------------------------------
 // Program start
 //---------------------------------------------------------
 int main (int argc, char **argv)
 {  

 char Who = 'Z'; //Are you a client or a server?
//Create a boy
 spelare pojke;
 pojke.hastighetX = 100;
 pojke.hastighetY = 100;
 pojke.ID=0;
 
 //Create a cow
 spelare ko;
 ko.hastighetX = 500;
 ko.hastighetY = 500;
 ko.ID=1;


 //--------------------------------------------------------
 // Show local adress, probably 192.168.x.x or 10.100.x.x or 169.254.x.x
 //-------------------------------------------
  sf::IPAddress Address1 = sf::IPAddress::GetLocalAddress();
  std::string IP1 = Address1.ToString();
  std::cout<<"Your local IP = " << IP1 << std::endl << std::endl;
 
 //Create a port
    const unsigned short Port = 2435;

    // Client or server ?------------------------------------------------
    std::cout << "Do you want to be a server ('s') or a client ('c') ? ";
    std::cin  >> Who;

    if (Who == 's')
        RunServer(Port);
    else
        RunClient(Port);

  spelsocket.SetBlocking(false); //Recieve without stop
 
   std::string caption;
     if (Who == 's')
        caption= "SERVER ";
    else
        caption= "CLIENT ";
 
  sf::RenderWindow App(sf::VideoMode(800, 600, 32), caption);

 while(App.IsOpened())
 { //Gameloop
  sf::Event Event;
       
 while (App.GetEvent(Event))
  { //while 2
 
     if (Event.Type == sf::Event::Closed) //hit [x] symbol?
        App.Close();
 
     if (Event.Type == sf::Event::KeyPressed)
            { //if 1
              if (Event.Key.Code == sf::Key::Escape) // ESC tangenten = close
              App.Close();

            if (Event.Key.Code == sf::Key::Space)
           {
            if (Who == 's')//server
            {
             PlayerSend(pojke); //Send info about boy
             PlayerRecieve(ko); //Recieve info about cow
             }
             else //client
            {
            PlayerSend(ko); //Send info about cow
            PlayerRecieve(pojke); //Recieve info about boy
            }
         }
      } //end if 1
 } //end, while 2
 

} // end Gameloop
 return 0;
 
 } //end  program

 void RunClient(unsigned short Port)
{
    // Ask for server IP
    sf::IPAddress ServerAddress;
    do
    {
        std::cout << "Write down IP to connect to: ";
        std::cin  >> ServerAddress;
    }
    while (!ServerAddress.IsValid());
    if (spelsocket.Connect(Port, ServerAddress) != sf::Socket::Done)
        return;
    std::cout << "Connecting to server " << ServerAddress << std::endl;

 }
 //Serverfunktionerna

  void RunServer(unsigned short Port)
 {
    if (!spelsocket.Listen(Port))
        return;
    std::cout << "Server is listening to port " << Port << ", wait for connect... " << std::endl;

    //Wait for connect
    sf::IPAddress ClientAddress;
    sf::SocketTCP Client;
    spelsocket.Accept(Client, &ClientAddress);
    std::cout << "Client connected : " << ClientAddress << std::endl;
 }


    void PlayerSend(class spelare &s)
{
sf::Packet paquetout;
spelare P; //Dummy player to save info in

P.ID = s.ID;
P.hastighetX = s.hastighetX;
P.hastighetY = s.hastighetY;
paquetout << P;
if (spelsocket.Send(paquetout) != sf::Socket::Done)
{
std::cout<<"Packet can't be sent"<<std::endl;
return;
}
else
{
std::cout<<"Packet is sent"<<std::endl;
std::cout<<"########################## " << std::endl;
std::cout<<"ID = " << P.ID << std::endl;
std::cout<<" X = " << P.hastighetX << std::endl;
std::cout<<" Y = " << P.hastighetY << std::endl;
std::cout<<"########################## " << std::endl;
}
}
  void PlayerRecieve(class spelare &s)
  {
   spelare R; //Dummy player to extract info to
   sf::Packet paquetin;
   if (spelsocket.Receive(paquetin) != sf::Socket::Done)
    {
        std::cout << "Packet is lost" << std::endl;
       return;
    }
    else  
   {
    std::cout<<"Packet is recieved"<<std::endl;
    paquetin >> R;
      std::cout<<"00000000000000000000000000000000 " << std::endl;
      std::cout<<"ID = " << R.ID << std::endl;
      std::cout<<" X = " << R.hastighetX << std::endl;
      std::cout<<" Y = " << R.hastighetY << std::endl;
      std::cout<<"00000000000000000000000000000000000 " << std::endl
    }

  }


//Ingemar

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Simple TCP connect between 2 PC's doesn't work
« Reply #21 on: March 20, 2012, 01:23:52 pm »
On server side, there must be two sockets:
- one for listening to incoming connections
- one that represents the connection to the client

Your mistake is that you're using your global socket for both things. Once you've received a connection from a client:
Code: [Select]
spelsocket.Accept(Client, &ClientAddress);
... the listener socket becomes useless (because you only have one client) and you must use the new one (Client) to communicate with the client; here you were just ignoring the client socket after receiving it.

You would have seen this if you had read more carefully the tutorial and sample application ;)

You should definitely try to find some good article about the basic concepts of IP networking. You won't succeed in anything if you don't first understand how things are supposed to work. Unlike the graphics or audio module of SFML, which abstract things with user-friendly concepts (image, sound, ...), the network module remains close to the low-level stuff, with sockets, listeners, selectors, etc. that can't be understood just by looking at classes and functions names.
Laurent Gomila - SFML developer

ingwik

  • Jr. Member
  • **
  • Posts: 65
    • View Profile
Simple TCP connect between 2 PC's doesn't work
« Reply #22 on: March 20, 2012, 03:58:55 pm »
You're right Laurent, network programming was a bridge to far for me. I thank you for the patience you've showed me and the time you have spent on trying to solve my problems.

//Ingemar

 

anything