2016-01-18 15 views
0

我想使用RMI使用LibGDX和Kryo​​net库进行游戏。所以我创建了干净的项目。我想现在要做的是,设置服务器侦听端口10048和新的连接到打印的我会得到通过调用客户端类的方法客户的名字......Kryonet RMI,不能等待连接的更新线程的响应

下面是代码:

ICardsTableImpl.java

package clzola.cardstable.client; 

public interface ICardsTableGameImpl { 
    public String getName(); 
} 

CardsTableServer.java

package clzola.cardstable.server; 

import clzola.cardstable.client.ICardsTableGameImpl; 
import com.esotericsoftware.kryo.Kryo; 
import com.esotericsoftware.kryonet.Connection; 
import com.esotericsoftware.kryonet.Server; 
import com.esotericsoftware.kryonet.rmi.ObjectSpace; 
import com.esotericsoftware.minlog.Log; 

import java.io.IOException; 
import java.util.HashMap; 


public class CardsTableServer extends Server { 
    private HashMap<Integer, Connection> connections; 

    public CardsTableServer() throws IOException { 
     connections = new HashMap<Integer, Connection>(); 
     addListener(new NetworkListener(this)); 

     Kryo kryo = getKryo(); 
     ObjectSpace.registerClasses(kryo); 
     kryo.register(ICardsTableGameImpl.class); 

     bind(10048); 
    } 

    @Override 
    protected Connection newConnection() { 
     Player player = new Player(); 
     addConnection(player); 
     return player; 
    } 


    public void addConnection(Connection connection) { 
     this.connections.put(connection.getID(), connection); 
    } 

    public Connection getConnection(int connectionId) { 
     return this.connections.get(connectionId); 
    } 

    public Connection removeConnection(int connectionId) { 
     return this.connections.remove(connectionId); 
    } 

    public static void main(String[] args) throws IOException { 
     Log.set(Log.LEVEL_DEBUG); 
     CardsTableServer server = new CardsTableServer(); 
     server.start(); 
    } 
} 

NetworkListener.java

package clzola.cardstable.server; 

import clzola.cardstable.client.ICardsTableGameImpl; 
import com.badlogic.gdx.Gdx; 
import com.esotericsoftware.kryonet.Connection; 
import com.esotericsoftware.kryonet.Listener; 
import com.esotericsoftware.kryonet.rmi.ObjectSpace; 

public class NetworkListener extends Listener { 
    private CardsTableServer server; 

    public NetworkListener(CardsTableServer server) { 
     this.server = server; 
    } 

    @Override 
    public void connected(Connection connection) { 
     Player player = ((Player) connection); 

     ICardsTableGameImpl game = ObjectSpace.getRemoteObject(player, 0, ICardsTableGameImpl.class); 
     player.name = game.getName(); // This is where I get excpetion... 

     Gdx.app.log("Server", "Player name: " + player.name); 
    } 

    @Override 
    public void disconnected(Connection connection) { 
     server.removeConnection(connection.getID()); 
    } 
} 

Player.java

package clzola.cardstable.server; 

import com.esotericsoftware.kryonet.Connection; 

public class Player extends Connection { 
    public String name; 
} 

CardsTableGame.java

package clzola.cardstable.client; 

import com.badlogic.gdx.ApplicationAdapter; 
import com.badlogic.gdx.Gdx; 
import com.badlogic.gdx.graphics.GL20; 
import com.badlogic.gdx.graphics.g2d.SpriteBatch; 
import com.badlogic.gdx.scenes.scene2d.Stage; 
import com.badlogic.gdx.utils.viewport.ScreenViewport; 
import com.esotericsoftware.kryo.Kryo; 
import com.esotericsoftware.kryonet.Client; 
import com.esotericsoftware.kryonet.rmi.ObjectSpace; 

public class CardsTableGame extends ApplicationAdapter implements ICardsTableGameImpl { 
    SpriteBatch batch; 
    Stage stage; 
    Client client; 
    String name = "Lazar"; 
    ObjectSpace objectSpace; 

    @Override 
    public void create() { 
     batch = new SpriteBatch(); 
     stage = new Stage(new ScreenViewport(), batch); 

     try { 
      client = new Client(); 
      client.start(); 

      Kryo kryo = client.getKryo(); 
      ObjectSpace.registerClasses(kryo); 
      kryo.register(ICardsTableGameImpl.class); 

      ObjectSpace objectSpace = new ObjectSpace(); 
      objectSpace.register(0, this); 
      objectSpace.addConnection(client); 

      client.connect(5000, "127.0.0.1", 10048); 
     } catch (Exception e) { 
      Gdx.app.log("CardsTableGame", e.getMessage(), e); 
     } 
    } 

    @Override 
    public void render() { 
     Gdx.gl.glClearColor(0, 0, 0, 1); 
     Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); 
    } 

    @Override 
    public String getName() { 
     return this.name; 
    } 
} 

它运行后,我得到的服务器端异常:

Exception in thread "Server" java.lang.IllegalStateException: Cannot wait for an RMI response on the connection's update thread. 
    at com.esotericsoftware.kryonet.rmi.ObjectSpace$RemoteInvocationHandler.waitForResponse(ObjectSpace.java:420) 
    at com.esotericsoftware.kryonet.rmi.ObjectSpace$RemoteInvocationHandler.invoke(ObjectSpace.java:408) 
    at com.sun.proxy.$Proxy0.getName(Unknown Source) 
    at clzola.cardstable.server.NetworkListener.connected(NetworkListener.java:24) 
    at com.esotericsoftware.kryonet.Server$1.connected(Server.java:48) 
    at com.esotericsoftware.kryonet.Connection.notifyConnected(Connection.java:214) 
    at com.esotericsoftware.kryonet.Server.acceptOperation(Server.java:417) 
    at com.esotericsoftware.kryonet.Server.update(Server.java:249) 
    at com.esotericsoftware.kryonet.Server.run(Server.java:372) 
    at java.lang.Thread.run(Thread.java:745) 

而我不知道为什么......我做错了什么? (这是我第一次尝试使用RMI)

+0

为什么?为什么不让客户端在连接请求中提供自己的名字?当你不需要它们时不要添加回调。 – EJP

+0

如何在连接请求中添加名称?上面的代码只是简单的测试,看看RMI如何与KryoNet协同工作。如果这不起作用,我怎么能期望其他更复杂的调用成功。另外一个问题,我想知道如果我可以在Android设备上使用KryoNet RMI? – clzola

+0

在相应地调整其签名后,将该名称作为该方法的另一个参数传递。或者在剧组结束后直接从'玩家'获得。你的第二个问题是修辞。我没有关于Android的信息。我从来没有见过自己的KryoNet点。你可以用香草RMI来实现所有这些。 – EJP

回答

1

Listener由Kryonet-update-thread执行。该线程定期检查套接字以接收消息。调用game.getName()会使主叫方等待答案通过网络传送。如果你在更新线程上这样做,你可能会让你的服务器陷入僵局,因为kryonet无法收到它正在等待的答案,因为你阻塞了更新线程。这就是它抛出异常的原因。

在kryonet git的rmi example中,他们通过使用在其自己的线程上工作的Listener来解决此问题。

// The ThreadedListener means the network thread won't be blocked when waiting for RMI responses. 
    client.addListener(new ThreadedListener(new Listener() { 
     public void connected (final Connection connection) { 
      TestObject test = ObjectSpace.getRemoteObject(connection, 42, TestObject.class); 
      // Normal remote method call. 
      assertEquals(43.21f, test.other()); 
      // Make a remote method call that returns another remote proxy object. 
      OtherObject otherObject = test.getOtherObject(); 
      // Normal remote method call on the second object. 
      assertEquals(12.34f, otherObject.value()); 
      // When a remote proxy object is sent, the other side recieves its actual remote object. 
      connection.sendTCP(otherObject); 
     } 
    }));