I am new to networking, and I am trying to network a board game that I have created using java.A friend of mine pointed me towards the Kryonet library. So far, it's great. I don't have to deal with sockets!
The problem I'm coming across is sending objects. Mainly, I have a Board type object. This object contains other objects, such as ArrayList objects and Fort objects.
I tried just registering the Board object, but I received these errors:
Exception in thread "Server" com.esotericsoftware.kryo.KryoException: java.lang.
IllegalArgumentException: Class is not registered: Game.Tile
Note: To register this class use: kryo.register(Game.Tile.class);
Serialization trace:
t0 (Game.Board)
at com.esotericsoftware.kryo.serializers.FieldSerializer$ObjectField.write(FieldSerializer.java:585)
at com.esotericsoftware.kryo.serializers.FieldSerializer.write(FieldSerializer.java:213)
at com.esotericsoftware.kryo.Kryo.writeClassAndObject(Kryo.java:571)
at com.esotericsoftware.kryonet.KryoSerialization.write(KryoSerializatio
n.java:50)
at com.esotericsoftware.kryonet.TcpConnection.send(TcpConnection.java:192)
etc....
Ok fine, Then I will also register Tile.class,
More errors, but then I need to register ArrayList.class - so I register it, and again more errors, so I register Fort.class.
When I register Fort.class, I enter into an infinite loop and get a ton of errors like this:
at com.esotericsoftware.kryo.serializers.FieldSerializer$ObjectField.write(FieldSerializer.java:564)
at com.esotericsoftware.kryo.serializers.FieldSerializer.write(FieldSerializer.java:213)
at com.esotericsoftware.kryo.Kryo.writeObject(Kryo.java:504)
at com.esotericsoftware.kryo.serializers.FieldSerializer$ObjectField.write(FieldSerializer.java:564)
at com.esotericsoftware.kryo.serializers.FieldSerializer.write(FieldSerializer.java:213)
at com.esotericsoftware.kryo.Kryo.writeObject(Kryo.java:504)
at com.esotericsoftware.kryo.serializers.FieldSerializer$ObjectField.write(FieldSerializer.java:564)
This leads me to believe I don't quite understand how to register properly and I can't find much information about how to register nested objects. My Fort class is actually an enumerated class but I'm not sure if that makes a difference? Any help would be greatly appreciated!
I have included a class with most of my networking code so you can see an idea of what I am trying to do.
This is my code for the networking:
public class Network extends Listener {
private Server server;
private Client client;
private boolean isServer;
private boolean messageReceived;
private PacketMessage message;
private Board board;
public Network(boolean isServer, Board board) throws IOException {
messageReceived = false;
this.board = board;
this.isServer = isServer;
if (isServer) {
initServer();
// receive();
} else {
initClient();
//probably want to run this in main
client();
}
}
private void initServer() throws IOException {
// 127.0.0.1 means myself
// ports up to 1024 are special and reserved
server = new Server();
registerClasses(server.getKryo());
server.bind(8000, 8001);
// starting a new thread
server.start();
// call my received and my connected
server.addListener(this);
}
private void initClient() throws IOException {
// 127.0.0.1 means myself
// ports up to 1024 are special and reserved
client = new Client();
registerClasses(client.getKryo());
// starting a new thread
client.start();
client.connect(5000, "127.0.0.1", 8000, 8001);
// call my received and call my connected
client.addListener(this);
}
//call in main
//
public void client(){
while(true){
sendRequest();
receive();
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
// tell Kryo what things it's going to have to send
private void registerClasses(Kryo kryo) {
kryo.register(Request.class);
kryo.register(PacketMessage.class);
kryo.register(Fort.class);
kryo.register(ArrayList.class);
kryo.register(Tile.class);
kryo.register(Board.class);
}
private void sendRequest() {
client.sendTCP(new Request());
}
private void receive() {
messageReceived = false;
while (!messageReceived) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
// message.message is really packet.message
System.out.println("Received a message from the host: "
+ message.message);
}
public void received(Connection c, Object p) {
System.out.println("Received Message");
// Is the received packet the same class as PacketMessage.class?
if (p instanceof PacketMessage) {
// Cast it so we can access the message within
// PacketMessage packet =(PacketMessage) p;
// System.out.println("Received a message from the host: "+pa cket.message);
message = (PacketMessage) p;
// We have now received the message!
messageReceived = true;
}
else if (p instanceof Request){
// Create a message packet
PacketMessage packetMessage = new PacketMessage();
// Assign the message text
packetMessage.message = "Hello friend! The time is: "
+ new Date().toString();
// Send the message
//probably want another method to send
c.sendTCP(packetMessage);
c.sendTCP(board);
}
}
// This is run when a connection is received!
public void connected(Connection c) {
System.out.println("Received a connection from "
+ c.getRemoteAddressTCP().getHostString());
}
}
What is likely happening is that your Fort class contains a member of type Board, and this circular reference causes an infinite loop when serializing Fort.
Use the transient keyword to exclude members from serialization, or remove the circular reference altogether.
Related
I have a gRPC client in a kafka application. This means the client will constantly open and close channels.
public class UserAgentClient {
protected final Logger logger = LoggerFactory.getLogger(getClass());
private static final Config uaparserConfig = ConfigFactory.load().getConfig(ua);
private final ManagedChannel channel;
private final UserAgentServiceGrpc.UserAgentServiceBlockingStub userAgentBlockingStub;
public UserAgentParserClient() {
this(ManagedChannelBuilder.forAddress(uaConfig.getString("host"), uaConfig.getInt("port")).usePlaintext());
}
public UserAgentClient(ManagedChannelBuilder<?> usePlaintext) {
channel = usePlaintext.build();
userAgentBlockingStub = UserAgentServiceGrpc.newBlockingStub(channel);
}
public UserAgentParseResponse getUserAgent(String userAgent ) {
UserAgentRequest request = UserAgentRequest.newBuilder().setUserAgent(userAgent).build();
UserAgentParseResponse response = null;
try {
response = userAgentBlockingStub.parseUserAgent(request);
} catch(Exception e) {
logger.warn("An exception has occurred during gRPC call to the user agent.", e.getMessage());
}
shutdown();
return response;
}
public void shutdown() {
try {
channel.shutdown();
} catch (InterruptedException ie) {
logger.warn("Interrupted exception during gRPC channel close", ie);
}
}
}
I was wondering if I can keep the channel open the whole time? Or do I have to open a channel every time I make a new call? I was wondering because I was testing the performance and it seems to improve drastically if I just keep the channel open. On the other hand is there something that I'm missing?
creating a new channel has huge overhead, you should keep the channel open as long as possible.
Since the opening and closing of channel is expensive I removed the channel = usePlaintext.build(); completely from my client
Instead I'm opening and closing it in my kafka Transformer. In my class UserAgentDataEnricher that implements Transformer.
public class UserAgentDataEnricher implements Transformer<byte[], EnrichedData, KeyValue<byte[], EnrichedData>> {
private UserAgentParserClient userAgentParserClient;
#Override
public void init(ProcessorContext context) {
this.context = context;
open();
// schedule a punctuate() method every 15 minutes
this.context.schedule(900000, PunctuationType.WALL_CLOCK_TIME, (timestamp) -> {
close();
open();
logger.info("Re-opening of user agent channel is initialized");
});
}
#Override
public void close() {
userAgentParserClient.shutdown();
}
private void open() {
channel = ManagedChannelBuilder.forAddress("localhost", 50051).usePlaintext().build();
userAgentClient = new UserAgentClient(channel);
}
...
}
and now I initialize my client like that:
public UserAgentClient(ManagedChannel channel) {
this.channel = channel;
userAgentBlockingStub = UserAgentServiceGrpc.newBlockingStub(channel);
}
I managed to setup an Hystrix Command to be called from an Undertow HTTP Handler:
public void handleRequest(HttpServerExchange exchange) throws Exception {
if (exchange.isInIoThread()) {
exchange.dispatch(this);
return;
}
RpcClient rpcClient = new RpcClient(/* ... */);
try {
byte[] response = new RpcCommand(rpcClient).execute();
// send the response
} catch (Exception e) {
// send an error
}
}
This works nice. But now, I would like to use the observable feature of Hystrix, calling observe instead of execute, making the code non-blocking.
public void handleRequest(HttpServerExchange exchange) throws Exception {
RpcClient rpcClient = new RpcClient(/* ... */);
new RpcCommand(rpcClient).observe().subscribe(new Observer<byte[]>(){
#Override
public void onCompleted() {
}
#Override
public void onError(Throwable throwable) {
exchange.setStatusCode(StatusCodes.INTERNAL_SERVER_ERROR);
exchange.endExchange();
}
#Override
public void onNext(byte[] body) {
exchange.getResponseHeaders().add(Headers.CONTENT_TYPE, "text/plain");
exchange.getResponseSender().send(ByteBuffer.wrap(body));
}
});
}
As expected (reading the doc), the handler returns immediately and as a consequence, the exchange is ended; when the onNext callback is executed, it fails with an exception:
Caused by: java.lang.IllegalStateException: UT000127: Response has already been sent
at io.undertow.io.AsyncSenderImpl.send(AsyncSenderImpl.java:122)
at io.undertow.io.AsyncSenderImpl.send(AsyncSenderImpl.java:272)
at com.xxx.poc.undertow.DiyServerBootstrap$1$1.onNext(DiyServerBootstrap.java:141)
at com.xxx.poc.undertow.DiyServerBootstrap$1$1.onNext(DiyServerBootstrap.java:115)
at rx.internal.util.ObserverSubscriber.onNext(ObserverSubscriber.java:34)
Is there a way to tell Undertow that the handler is doing IO asynchronously? I expect to use a lot of non-blocking code to access database and other services.
Thanks in advance!
You should dispatch() a Runnable to have the exchange not end when the handleRequest method returns. Since the creation of the client and subscription are pretty simple tasks, you can do it on the same thread with SameThreadExecutor.INSTANCE like this:
public void handleRequest(HttpServerExchange exchange) throws Exception {
exchange.dispatch(SameThreadExecutor.INSTANCE, () -> {
RpcClient rpcClient = new RpcClient(/* ... */);
new RpcCommand(rpcClient).observe().subscribe(new Observer<byte[]>(){
//...
});
});
}
(If you do not pass an executor to dispatch(), it will dispatch it to the XNIO worker thread pool. If you wish to do the client creation and subscription on your own executor, then you should pass that instead.)
Good night guys!
I'm having the following problem ...
I have a web application that runs a "thread" that takes messages from the queue (MSMQ) ... Everything works correctly .. the problem is when I get this message, I can not display .. because the method that returns the message content is a "static" ..
I need to perform a function in JS to display this message.
conclusion:
The method "ProcessMessage" can not be named because he is not a static method ...
My main goal is to call a function in JS passing as parameter (m.Body.ToString ()) which is the content of the message.
Can anyone help me?
Thank you for sharing your knowledge!
This is my code.
public void StartThread()
{
try
{
while (true)
{
PrepareQueue();
}
}
catch (Exception)
{ }
}
public static void PrepareQueue()
{
MessageQueue myQueue = new MessageQueue(".\\private$\\CTIQueue");
myQueue.Formatter = new XmlMessageFormatter(new Type[] { typeof(String) });
// Add an event handler for the ReceiveCompleted event.
myQueue.ReceiveCompleted += new ReceiveCompletedEventHandler(MyReceiveCompleted);
// Define wait handles for multiple operations.
WaitHandle[] waitHandleArray = new WaitHandle[10];
for (int i = 0; i < 10; i++)
{
// Begin asynchronous operations.
waitHandleArray[i] = myQueue.BeginReceive().AsyncWaitHandle;
}
// Specify to wait for all operations to return.
WaitHandle.WaitAll(waitHandleArray);
return;
}
private static void MyReceiveCompleted(Object source, ReceiveCompletedEventArgs asyncResult)
{
try
{
Thread.Sleep(2000);
MessageQueue mq = (MessageQueue)source;
// End the asynchronous receive operation.
System.Messaging.Message m = mq.EndReceive(asyncResult.AsyncResult);
ProcessMessage(m.Body.ToString()); <-- MY PROBLEM
}
catch (MessageQueueException)
{ }
return;
}
public void ProcessMessage(string message)
{
ScriptManager.RegisterStartupScript(this, GetType(), "popup", "NewCaller('" + message + "');", true);
}
Why not instantiate an object of the class and call ProcessMessage on it? Static methods can instantiate an object of the enclosing class and invoke instance methods on it.
private static void MyReceiveCompleted(Object source, ReceiveCompletedEventArgs asyncResult)
{
try
{
Thread.Sleep(2000);
MessageQueue mq = (MessageQueue)source;
// End the asynchronous receive operation.
System.Messaging.Message m = mq.EndReceive(asyncResult.AsyncResult);
new MyClass().ProcessMessage(m.Body.ToString()); <-- MY PROBLEM
}
catch (MessageQueueException)
{ }
return;
}
But if you are planning to invoke a client side code from server side, with reactive action happening at the server's end(which I think is your case) -- then I would prefer you use ASP.NET SignalR to signal the client that something interesting has happened at the server's end.
I am new to Netty. I am using “Netty 3.6.2.Final”. I have created a Netty Client (MyClient) that talks to a remote server (The server implements a custom protocol based on TCP). I create a new ClientBootstrap instance for each MyClient instance (within the constructor).
My question is if I share “NioClientSocketChannelFactory” factory object among all the instances of MyClient then when/how do I release all the resources associated with the “NioClientSocketChannelFactory”?
In other words, since my Netty Client runs inside a JBOSS container running 24x7, should I release all resources by calling “bootstrap.releaseExternalResources();” and when/where should I do so?
More Info: My Netty Client is called from two scenarios inside a JBOSS container. First, in an infinite for loop with each time passing the string that needs to be sent to the remote server (in effect similar to below code)
for( ; ; ){
//Prepare the stringToSend
//Send a string and receive a string
String returnedString=new MyClient().handle(stringToSend);
}
Another scenarios is my Netty Client is called within concurrent threads with each thread calling “new MyClient().handle(stringToSend);”.
I have given the skeleton code below. It is very similar to the TelnetClient example at Netty website.
MyClient
import org.jboss.netty.bootstrap.ClientBootstrap;
import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory;
public class MyClient {
//Instantiate this only once per application
private final static Timer timer = new HashedWheelTimer();
//All below must come from configuration
private final String host ="127.0.0.1";
private final int port =9699;
private final InetSocketAddress address = new InetSocketAddress(host, port);
private ClientBootstrap bootstrap;
//Timeout when the server sends nothing for n seconds.
static final int READ_TIMEOUT = 5;
public MyClient(){
bootstrap = new ClientBootstrap(NioClientSocketFactorySingleton.getInstance());
}
public String handle(String messageToSend){
bootstrap.setOption("connectTimeoutMillis", 20000);
bootstrap.setOption("tcpNoDelay", true);
bootstrap.setOption("keepAlive", true);
bootstrap.setOption("remoteAddress", address);
bootstrap.setPipelineFactory(new MyClientPipelineFactory(messageToSend,bootstrap,timer));
// Start the connection attempt.
ChannelFuture future = bootstrap.connect();
// Wait until the connection attempt succeeds or fails.
channel = future.awaitUninterruptibly().getChannel();
if (!future.isSuccess()) {
return null;
}
// Wait until the connection is closed or the connection attempt fails.
channel.getCloseFuture().awaitUninterruptibly();
MyClientHandler myClientHandler=(MyClientHandler)channel.getPipeline().getLast();
String messageReceived=myClientHandler.getMessageReceived();
return messageReceived;
}
}
Singleton NioClientSocketChannelFactory
public class NioClientSocketFactorySingleton {
private static NioClientSocketChannelFactory nioClientSocketChannelFactory;
private NioClientSocketFactorySingleton() {
}
public static synchronized NioClientSocketChannelFactory getInstance() {
if ( nioClientSocketChannelFactory == null) {
nioClientSocketChannelFactory=new NioClientSocketChannelFactory(
Executors.newCachedThreadPool(),
Executors.newCachedThreadPool());
}
return nioClientSocketChannelFactory;
}
protected void finalize() throws Throwable {
try{
if(nioClientSocketChannelFactory!=null){
// Shut down thread pools to exit.
nioClientSocketChannelFactory.releaseExternalResources();
}
}catch(Exception e){
//Can't do anything much
}
}
}
MyClientPipelineFactory
public class MyClientPipelineFactory implements ChannelPipelineFactory {
private String messageToSend;
private ClientBootstrap bootstrap;
private Timer timer;
public MyClientPipelineFactory(){
}
public MyClientPipelineFactory(String messageToSend){
this.messageToSend=messageToSend;
}
public MyClientPipelineFactory(String messageToSend,ClientBootstrap bootstrap, Timer timer){
this.messageToSend=messageToSend;
this.bootstrap=bootstrap;
this.timer=timer;
}
public ChannelPipeline getPipeline() throws Exception {
// Create a default pipeline implementation.
ChannelPipeline pipeline = pipeline();
// Add the text line codec combination first,
//pipeline.addLast("framer", new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
pipeline.addLast("decoder", new StringDecoder());
pipeline.addLast("encoder", new StringEncoder());
//Add readtimeout
pipeline.addLast("timeout", new ReadTimeoutHandler(timer, MyClient.READ_TIMEOUT));
// and then business logic.
pipeline.addLast("handler", new MyClientHandler(messageToSend,bootstrap));
return pipeline;
}
}
MyClientHandler
public class MyClientHandler extends SimpleChannelUpstreamHandler {
private String messageToSend="";
private String messageReceived="";
public MyClientHandler(String messageToSend,ClientBootstrap bootstrap) {
this.messageToSend=messageToSend;
this.bootstrap=bootstrap;
}
#Override
public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e){
e.getChannel().write(messageToSend);
}
#Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e){
messageReceived=e.getMessage().toString();
//This take the control back to the MyClient
e.getChannel().close();
}
#Override
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) {
// Close the connection when an exception is raised.
e.getChannel().close();
}
}
You should only call releaseExternalResources() once you are sure you not need it anymore. This may be for example when the application gets stopped or undeployed.
I'm making a small game in LibGDX. I'm saving the player's username locally as well as on a server. The problem is that the application is not waiting for the result of the call so the online database's ID is not saved locally. Here's the overall flow of the code:
//Create a new user object
User user = new User(name);
//Store the user in the online database
NetworkService networkService = new NetworkService();
String id = networkService.saveUser(user);
//Set the newly generated dbase ID on the local object
user.setId(id);
//Store the user locally
game.getUserService().persist(user);
in this code, the id variable is not getting set because the saveUser function is returning immediately. How can I make the application wait for the result of the network request so I can work with results from the server communication?
This is the code for saveUser:
public String saveUser(User user) {
Map<String, String> parameters = new HashMap<String, String>();
parameters.put("action", "save_user");
parameters.put("json", user.toJSON());
HttpRequest httpGet = new HttpRequest(HttpMethods.POST);
httpGet.setUrl("http://localhost:8080/provisioner");
httpGet.setContent(HttpParametersUtils.convertHttpParameters(parameters));
WerewolfsResponseListener responseListener = new WerewolfsResponseListener();
Gdx.net.sendHttpRequest (httpGet, responseListener);
return responseListener.getLastResponse();
}
This is the WerewolfsResponseListener class:
class WerewolfsResponseListener implements HttpResponseListener {
private String lastResponse = "";
public void handleHttpResponse(HttpResponse httpResponse) {
System.out.println(httpResponse.getResultAsString());
this.lastResponse = httpResponse.getResultAsString();
}
public void failed(Throwable t) {
System.out.println("Saving user failed: "+t.getMessage());
this.lastResponse = null;
}
public String getLastResponse() {
return lastResponse;
}
}
The asynchrony you are seeing is from Gdx.net.sendHttpRequest. The methods on the second parameter (your WerewolfsResponseListener) will be invoked whenever the request comes back. The success/failure methods will not be invoked "inline".
There are two basic approaches for dealing with callbacks structured like this: "polling" or "events".
With polling, your main game loop could "check" the responseListener to see if its succeeded or failed. (You would need to modify your current listener a bit to disambiguate the success case and the empty string.) Once you see a valid response, you can then do the user.setId() and such.
With "events" then you can just put the user.setId() call inside the responseListener callback, so it will be executed whenever the network responds. This is a bit more of a natural fit to the Libgdx net API. (It does mean your response listener will need a reference to the user object.)
It is not possible to "wait" inline for the network call to return. The Libgdx network API (correctly) assumes you do not want to block indefinitely in your render thread, so its not structured for that (the listener will be queued up as a Runnable, so the earliest it can run is on the next render call).
I would not recommend this to any human being, but if you need to test something in a quick and dirty fashion and absolutely must block, this will work. There's no timeout, so again, be prepared for absolute filth:
long wait = 10;
while(!listener.isDone())
{
Gdx.app.log("Net", "Waiting for response");
try
{
Thread.sleep(wait *= 2);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
public static class BlockingResponseListener implements HttpResponseListener
{
private String data;
private boolean done = false;
private boolean succeeded = false;
#Override
public void handleHttpResponse(HttpResponse httpResponse)
{
Gdx.app.log("Net", "response code was "+httpResponse.getStatus().getStatusCode());
data = httpResponse.getResultAsString();
succeeded = true;
done = true;
}
#Override
public void failed(Throwable t)
{
done = true;
succeeded = false;
Gdx.app.log("Net", "Failed due to exception ["+t.getMessage()+"]");
}
public boolean succeeded()
{
return succeeded;
}
public boolean isDone()
{
return done;
}
public String getData()
{
return data;
}
}