Networking

Hello all together :smiley:

I’m currently trying to get a network game going.
I’m using Sockets and Objekt Serialization, because thats what we are doing in class and I need to use them later in exams.
After alot of working and trying out, I got the Server to send an Object and the Client to recieve it.

But for some miraculous reason, it will send the Object and recieve it, but will not update it.
So its something client sided. Because the server only recieves the old object.

So it will send the Player Object: with x 100 and y 100. Eventhough I updated it on the client side to eg x 140 and y 132

Oh and when your checking it, maybe someone could tell me why I get two connections when connecting to the server?

Thanks alot :smiley:

Heres the code:

Server:

import java.io.*;
import java.net.*;

public class Server extends Thread {

   private ServerSocket arrayServer;
 

   public static void main(String argv[]) throws Exception {
     new Server();
   }

   public Server() throws Exception {
     arrayServer = new ServerSocket(9999);
     System.out.println("Server listening on port 4000.");
     this.start();
   } 

   public void run() {
     while(true) {
       try {
        System.out.println("Waiting for connections.");
        Socket client = arrayServer.accept();
        System.out.println("Accepted a connection from: "+
client.getInetAddress());
        Connect c = new Connect(client);
       } catch(Exception e) {}
     }
   }
}

class Connect extends Thread {
   private Socket client = null;
   private ObjectInputStream ois = null;
   private ObjectOutputStream oos = null;
    
   public Connect() {}

   public Connect(Socket clientSocket) {
     client = clientSocket;
     try {
      ois = new ObjectInputStream(client.getInputStream());
      oos = new ObjectOutputStream(client.getOutputStream());
     } catch(Exception e1) {
         try {
            client.close();
         }catch(Exception e) {
           System.out.println(e.getMessage());
         }
         return;
     }
     this.start();
   }

   public void run() {
      
	   while (true) {
	   
		Object obj = null;
		 
		try {
			obj = ois.readObject();
			System.out.println((Player)obj);
			
			if (obj instanceof Player) {
				oos.writeObject((Player)obj);
				//oos.flush();
			}
			
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		 
		 /*// close connections
         ois.close();
         oos.close();
         client.close(); */
      }    
   }
}

Client (with Slick2D):



import java.awt.Point;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.ArrayList;

import org.newdawn.slick.Color;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Image;
import org.newdawn.slick.Input;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.Sound;
import org.newdawn.slick.geom.Circle;
import org.newdawn.slick.geom.Rectangle;
import org.newdawn.slick.particles.ConfigurableEmitter;
import org.newdawn.slick.particles.ParticleEmitter;
import org.newdawn.slick.particles.ParticleIO;
import org.newdawn.slick.particles.ParticleSystem;
import org.newdawn.slick.particles.effects.FireEmitter;
import org.newdawn.slick.state.BasicGameState;
import org.newdawn.slick.state.StateBasedGame;
 
public class GameplayState extends BasicGameState {
 
    int stateID = -1;
 
    GameplayState( int stateID ) 
    {
       this.stateID = stateID;
    }
 
    @Override
    public int getID() {
        return stateID;
    }
 
    //Attribute
    GameClient client = null;
    
    Player me;
    ArrayList<Player> players = new ArrayList<Player>();
    String debugStr = "";

    public void init(GameContainer gc, StateBasedGame sbg) throws SlickException {
 
    	// Objekt client erzeugen
        client = new GameClient();
        //client.starteClient("127.0.0.1", 9999);
        
        me = new Player(0,100,100);
        me.nick = "ad";
        
    }
 
    public void render(GameContainer gc, StateBasedGame sbg, Graphics g) throws SlickException {
    	
    	for (Player p: players) {
    		g.drawRect(p.x, p.y, p.width, p.height);
    	}
    	
    	g.drawString(debugStr, 10, 20);
    }
   
    
    
    public void update(GameContainer gc, StateBasedGame sbg, int delta) throws SlickException {
    	
    	//Handle Keyinputs Clientsided
    	Input input = gc.getInput();
    	
    	if (input.isKeyDown(input.KEY_W)) {
    		me.moveUp();
    	}
    	
    	if (input.isKeyDown(input.KEY_S)) {
    		me.moveDown();
    	}
    	
    	if (input.isKeyDown(input.KEY_A)) {
    		me.moveLeft();
    	}
    	
    	if (input.isKeyDown(input.KEY_D)) {
    		me.moveRight();
    	}
    	
    	debugStr = me.toString();
    	
    	client.sendTCP(me);
    }
    
 
    
 // innere Klasse GameClient
    public class GameClient {
      private String       host;
      private int          port;
      private ReaderThread reader;
      private Socket       socket;
      ObjectOutputStream oos = null;
      ObjectInputStream ois = null;
      
      public GameClient(){
    	  starteClient("127.0.0.1",9999);
      }

      public boolean starteClient(String host, int port){
          try {
            socket = new Socket(host, port);
            
            // connect war erfolgreich
            this.host= host;
            this.port= port;
            
            oos = new ObjectOutputStream(socket.getOutputStream());
            ois = new ObjectInputStream(socket.getInputStream());
            
            // Lese Thread starten
            reader = new ReaderThread();
            reader.start();
            return true;
          }
          catch (IOException e){
            System.err.println(e);
            return false;
          }
          
          
      }

      public void sendTCP(Object o){
    	  try {
              oos.writeObject(o);
              //oos.flush();
          } catch (IOException ex) {
              //Logger.getLogger(JChatView.class.getName()).log(Level.SEVERE, null, ex);
          }

  }
      

        // innere Klasse um parallel eingehende Nachrichten zu lesen
          class ReaderThread extends Thread {
        	public void run(){
               
               while (true) {
            	   
                    try {
						Player obj = (Player)ois.readObject();
						
							boolean b = false;
							int i = 0;
							
							for (Player p: players) {
								
								
								if (p == obj) {
									b = true;
									players.set(i, obj);
									//System.out.println(obj);
									//System.out.println("Recieved Player "+i+"["+players.size()+"]");
								}
								
								i++;
							}
							
							if (!b) {
								players.add(obj);
								System.out.println("Recieved New Player");
							}
							
						
						
						//System.out.println("Recieved Player: "+obj.toString());
						
					} catch (IOException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					} catch (ClassNotFoundException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
                    
                    
                   
               }
               
               
            }
          } // Ende innere Klasse ClientReader


      public void beendeClient() {
         try {
           oos.close();
           ois.close();
           socket.close();
         }
         catch (IOException e){
           System.err.println(e);
         }
      }
  
    }// innere Klasse Client
 
}

And the Player Class:

import java.awt.Rectangle;
import java.io.Serializable;

public class Player implements Serializable {

	
	int id;
	String nick;

	float x,y;
	double aimAngle;

	int width = 50, height = 50;

	Rectangle r;

	public Player(int id, float x, float y) {
		this.id = id;
		this.x = x;
		this.y = y;
	}

	
	
	public int getId() {
		return id;
	}



	public void setId(int id) {
		this.id = id;
	}



	public String getNick() {
		return nick;
	}



	public void setNick(String nick) {
		this.nick = nick;
	}



	public float getX() {
		return x;
	}



	public void setX(float x) {
		this.x = x;
	}



	public float getY() {
		return y;
	}



	public void setY(float y) {
		this.y = y;
	}



	public double getAimAngle() {
		return aimAngle;
	}



	public void setAimAngle(double aimAngle) {
		this.aimAngle = aimAngle;
	}



	public int getWidth() {
		return width;
	}



	public void setWidth(int width) {
		this.width = width;
	}



	public int getHeight() {
		return height;
	}



	public void setHeight(int height) {
		this.height = height;
	}


	public void moveUp() {
		y -= 1;
	}
	
	public void moveDown() {
		y += 1;
	}

	public void moveLeft() {
		x -= 1;
	}
	
	public void moveRight() {
		x += 1;
	}
	
	public Rectangle getRect() {
		return new Rectangle((int)x,(int)y,width,height);
	}

	public String toString() {
		return this.nick +";"+ this.x +";"+ this.y +";"+ this.aimAngle +";"+ this.width +";"+ this.height +";"+ this.id;

	}
}

Client line 162 is

 if (p == obj) {

it should be

if( p.equals( obj ) ) {

EDIT: Found the problem. I needed to oos.reset(); the OutputStream, so it would disregard the object if it has been sent.

He doesn’t have an “equals()” method in his Player class so that won’t change anything.

@Zushii
Yes but you also need to change that line 162 to “if(obj instanceof Player) {”
Since all objects coming in will not be the same as existing ones.

Ah yes, I forgot to mention in my earlier post that ObjectOutputStream checks to see if that object has already been sent and only notifies the other side about it. It doesn’t send a new copy. Instead of using “oos.reset()”, you need to use “oos.writeUnshared(Object)” and “ois.readUnshared()”.

I’ve got a new Problem.

In my Player Class I have implemented a ArrayList. Missile is a serializable Class and is just the missile.
I can add missiles client sided, but when I send the Player class containing the ArrayList with missiles the arraylist ist empty.

This is fairly weird. Since I can send ArrayList with no problem on its own. Is there a certain method I have to use here?

Try using “writeUnshared” instead of “writeObject”

I actually did that^^
The class shown in my first post is older.

Thats why I am confused.

Post the current code… better a minimal self contained test case (usually you’ll find the problem yourself in the process of creating a minimal selfcontained test case anyway ;))

Hello,
I have a question about this:
I wouldn’t send objects through the network, but only text, that stands for my missile.
As an example:
I would send:
m:11:move:11/22

m = missile
11 = ID of the missile
move = the command
11 = the new x-coordinate
22 = the new y-coordinate.

So why sending objects, when text should be a little bit faster?

if you want less text you could send byte messages… where you change move to a number and the symbols through a a few selected bytes…

biro

don’t hijack topics, start your own!

EDIT: Sorry about that rant. Your post is absolutely fine - I should have read it to the end to realize, that you are proposing a simpler alternative… :-\

You are absolutely right, defining an own simple text based network “protocol”, would make things more deterministic, easier to debug and probably faster. On the downside, you can only send and receive data, your network code knows of.

Using serialization may have the advantage of being more abstract and you are getting the send and receive logic more or less for free.

All that is fine, but we can’t just abandon a bug that is supposed to work fine.
Zushii, could you show us some code?