I have a nodeJS server setup to accept socket connections, this seems to work fine with my web applications.
Now I'm trying to setup the same server to accept socket connections from Kryonet library on Android, iOS(Though RoboVM) & Desktop.
Node setup:
gameserver.js
var server = app.listen(9999, function()
{
var host = server.address().address;
var port = server.address().port;
console.log('Gameserver listening at http://%s:%s', host, port);
});
//Socket IO stuff.
var io = require('socket.io').listen(server);
require('./live_game_api.js')(io);
live_api.js
module.exports = function(io)
{
io.sockets.on('connection', function(socket)
{
console.log('user connected to server.');
socket.on('test', function(msg){
console.log('message: ' + msg);
});
});
}
Then within my app I've got:
new Thread(new Runnable() {
#Override
public void run()
{
try
{
Client client = new Client();
client.start();
client.addListener(new Listener() {
public void connected(Connection connection) {
PolyUtils.log("Connected");
}
#Override
public void disconnected(Connection connection) {
TextNotifierController.getInstance().displayTextBottom(UPStrings.Disconnected_from_mothership);
super.disconnected(connection);
}
#Override
public void received(Connection connection, Object object) {
PolyUtils.log("received:" + connection.isConnected());
super.received(connection, object);
}
#Override
public void idle(Connection connection) {
super.idle(connection);
}
});
//192.168.1.11:9999
client.connect(SOCKET_CONNECTION_TIMEOUT, ServerController.SOCKET_DOMAIN, ServerController.SOCKET_NUMBER, -1);
Gdx.app.postRunnable(new Runnable() {
#Override
public void run() {
setupSocket();
}
});
}
catch(Exception exception)
{
Gdx.app.postRunnable(new Runnable() {
#Override
public void run() {
hasConnection = false;
TextNotifierController.getInstance().displayText(UPStrings.Error_connecting_to_mothership, TextNotifierController.nearBottomVec);
}
});
exception.printStackTrace();
}
}
}).start();
I get the following error when connecting on the client:
00:00 INFO: Connecting: /192.168.1.11:9999
java.net.SocketTimeoutException: Connected, but timed out during TCP registration.
Related
I am using this Java library to communication between Node.js and a Java application using socket.io.
Here is my Java implementation:
socket = IO.socket("http://localhost:3000");
socket.on(Socket.EVENT_CONNECT, new Emitter.Listener() {
#Override
public void call(Object... args) {
System.out.println("Connected!");
}
}).on("error", new Emitter.Listener() {
#Override
public void call(Object... args) {
System.out.println("error");
}
});
socket.connect();
And here is my Node.js implementation:
const localsocket = require('socket.io')();
localsocket.on('connection', () => {
console.log('Connected!');
localsocket.emit('error', {messsage: "error!~!"})
});
localsocket.on('poke', (msg) => {
console.log("poked");
});
localsocket.listen(3000);
console.log("listening on port 3000");
As you can see, as soon as the Java code connects, the Javascript broadcasts an error which the Java code receives.
The Java code outputs:
Connected!
error
And the Node.js code outputs:
Listening on port 3000
Connected!
Now, I also have a button in the Java code which executes the following:
if (socket.connected()) {
System.out.println("do poke");
socket.emit("poke", new JSONObject("{ \"message\" : \"hello\" }"));
}
And when I press this button, the message do poke appears in the Java console, but no message appears in the Node.js terminal.
The full Java code:
private Socket socket;
#FXML private ToggleButton button;
public Main(String com) { // constructor
try {
socket = IO.socket("http://localhost:3000");
socket.on(Socket.EVENT_CONNECT, new Emitter.Listener() {
#Override
public void call(Object... args) {
System.out.println("connected woo!");
}
}).on("error", new Emitter.Listener() {
#Override
public void call(Object... args) {
System.out.println("error");
}
});
socket.connect();
} catch (URISyntaxException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
#FXML
public void buttonToggle() {
if (button.isSelected()) {
if (socket.connected()) {
System.out.println("do poke");
socket.emit("poke", new JSONObject("{ \"message\" : \"hello\" }"));
}
}
}
So, I managed to figure out a way that works in case anyone else runs into the same issue.
I just had to redo my Javascript code a little bit and define a framework for the server
const app = require('express')();
const server = app.listen(3000);
const io_local = require('socket.io')(server);
io_local.on('connection', (socket) => {
console.log('New connection!');
socket.on('poke', () => {
console.log("poked");
});
socket.on('error', () => {
console.log("error");
});
socket.emit('error', {message: "error"});
});
And the Java side is the same. Everything works as expected.
I have the following class. I'm trying to have the WebSocket reconnect in case of failure
public class WebSocketClient extends WebSocketListener {
volatile OkHttpClient client;
volatile WebSocket webSocket;
volatile Boolean isConnected = false;
public WebSocketClient() {
Proxy proxy = null;
if (Main.useProxy) {
tinder.CustomProxy proxyCustom = ProxyManager.GetStaticProxy(ThreadLocalManager.account.get().getProxyId());
proxy = new Proxy(Proxy.Type.HTTP,
new InetSocketAddress(proxyCustom.getProxyIp(), proxyCustom.getProxyPort()));
}
client = new OkHttpClient.Builder().proxy(proxy).readTimeout(2, TimeUnit.SECONDS)
.connectTimeout(2, TimeUnit.SECONDS).build();
Request request = new Request.Builder().url("wss://echo.com/ws")
.addHeader("Accept-Language", "en").build();
webSocket = client.newWebSocket(request, this);
}
#Override
public void onOpen(WebSocket webSocket, Response response) {
AnsiConsole.out.println(Ansi.ansi().fg(Ansi.Color.GREEN).a("Socket connection successful").reset());
isConnected = true;
}
#Override
public void onMessage(WebSocket webSocket, String text) {
System.out.println("Text MESSAGE: " + text);
}
#Override
public void onMessage(WebSocket webSocket, ByteString bytes) {
}
#Override
public void onClosing(WebSocket webSocket, int code, String reason) {
webSocket.close(1000, null);
System.out.println("CLOSE: " + code + " " + reason);
isConnected = false;
}
#Override
public void onFailure(WebSocket webSocket, Throwable t, Response response) {
isConnected = false;
AnsiConsole.out
.println(Ansi.ansi().fg(Ansi.Color.RED).a("Socket connection failed! will try to reconnect").reset());
while (!isConnected) {
try {
AnsiConsole.out
.println(Ansi.ansi().fg(Ansi.Color.YELLOW).a("Waiting to try socket connection!").reset());
Thread.sleep(4000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Request request = new Request.Builder().url("wss://echo.com/ws")
.addHeader("Accept-Language", "en").build();
webSocket = client.newWebSocket(request, this);
}
if (isConnected) {
AnsiConsole.out.println(Ansi.ansi().fg(Ansi.Color.GREEN).a("Socket connection successful").reset());
}
}
public void close() {
if (webSocket != null) {
webSocket.close(1000, "Connection closed");
}
client.dispatcher().executorService().shutdown();
}
}
The problem is if it takes a few attempts to reconnect, then the onFailure method will get called multiple times. Causing multiple web socket connections instead of one.
How can I have the single connection reconnect when the websocket disconnects?
public class WebSocketClient extends WebSocketListener {
volatile OkHttpClient client;
volatile WebSocket webSocket;
volatile Boolean isConnected = false;
public WebSocketClient() {
Proxy proxy = null;
if (Main.useProxy) {
tinder.CustomProxy proxyCustom = ProxyManager.GetStaticProxy(ThreadLocalManager.account.get().getProxyId());
proxy = new Proxy(Proxy.Type.HTTP,
new InetSocketAddress(proxyCustom.getProxyIp(), proxyCustom.getProxyPort()));
}
client = new OkHttpClient.Builder().proxy(proxy).readTimeout(2, TimeUnit.SECONDS)
.connectTimeout(2, TimeUnit.SECONDS).build();
Request request = new Request.Builder().url("wss://echo.com/ws")
.addHeader("Accept-Language", "en").build();
webSocket = client.newWebSocket(request, this);
// First Change
client.connectionPool.evictAll();
}
#Override
public void onOpen(WebSocket webSocket, Response response) {
AnsiConsole.out.println(Ansi.ansi().fg(Ansi.Color.GREEN).a("Socket connection successful").reset());
isConnected = true;
}
#Override
public void onMessage(WebSocket webSocket, String text) {
System.out.println("Text MESSAGE: " + text);
}
#Override
public void onMessage(WebSocket webSocket, ByteString bytes) {
}
#Override
public void onClosing(WebSocket webSocket, int code, String reason) {
webSocket.close(1000, null);
System.out.println("CLOSE: " + code + " " + reason);
isConnected = false;
}
#Override
public void onFailure(WebSocket webSocket, Throwable t, Response response) {
// Second Change
webSocket.close(1000, null);
close();
Thread.sleep(10000);
Request request = new Request.Builder().url("wss://echo.com/ws")
.addHeader("Accept-Language", "en").build();
webSocket = client.newWebSocket(request, this);
}
public void close() {
if (webSocket != null) {
webSocket.close(1000, "Connection closed");
}
}
}
For multiple idle connection client provide a connectionPool
client.connectionPool().evictAll();
the evictAll() method evicts all the connections.
I created a basic selfhosted SignalR server with the following code:
class Program
{
static void Main(string[] args)
{
// This will *ONLY* bind to localhost, if you want to bind to all addresses
// use http://*:8080 to bind to all addresses.
// See http://msdn.microsoft.com/en-us/library/system.net.httplistener.aspx
// for more information.
string url = "http://localhost:8080";
using (WebApp.Start(url))
{
Console.WriteLine("Server running on {0}", url);
Console.ReadLine();
}
}
}
class Startup
{
public void Configuration(IAppBuilder app)
{
app.UseCors(CorsOptions.AllowAll);
app.MapSignalR();
}
}
public class MyHub : Hub
{
public void Send(string name, string message)
{
Clients.All.addMessage(name, message);
}
}
Which is taken from: https://learn.microsoft.com/en-us/aspnet/signalr/overview/deployment/tutorial-signalr-self-host and works with the Javascript client.
I am now trying to create a Java client and got the following code that is simply supposed to send a message to the server:
String host = "http://localhost:8080";
HubConnection connection = new HubConnection(host);
HubProxy proxy = connection.createHubProxy("MyHub");
connection.start();
try {
System.out.println("Sendng message...");
proxy.invoke( "Send", "Client", "Hello world!" ).get();
System.out.println("Message sent!");
} catch (InterruptedException e) {
System.out.println("err1");
// Handle ...
} catch (ExecutionException e) {
System.out.println("err2");
// Handle ...
}
The problem that im having is that the message is not received by the server, it seems like the code is stuck at the invoke call and doesn't print the Hello world! message. Does someone know what im doing wrong?
hubProxy.invoke("sendMessageByUser", Message, WebApiToken).done(new Action<Void>() {
#Override
public void run(Void aVoid) {
if (aVoid != null)
handler.post(new Runnable() {
#Override
public void run() {
Toast.makeText(MyApplicationService.this, "Mesaj gönderildi", Toast.LENGTH_SHORT).show();
}
});
}
}).onError(new ErrorCallback() {
#Override
public void onError(final Throwable error) {
handler.post(new Runnable() {
#Override
public void run() {
Toast.makeText(MyApplicationService.this.getApplicationContext(), "Bir hata oluştu" + error.toString(), Toast.LENGTH_SHORT).show();
}
});
}
});
I have application which uses both TCP and UDP protocols. Main assumption is that the client connects to server via TCP protocol and when connection is established, UDP datagrams are being send.
I have to support two scenarios of connecting to server:
- client connects when server is running
- client connects when server is down and retries connection until server starts again
For the first scenario everything works pretty fine: I got working both connections.
The problem is with second scenario. When client tries few times to connect via TCP and finally connects, the UDP connection function throws an exception:
java.net.SocketException: No buffer space available (maximum connections reached?): bind
at sun.nio.ch.Net.bind0(Native Method)
at sun.nio.ch.Net.bind(Net.java:344)
at sun.nio.ch.DatagramChannelImpl.bind(DatagramChannelImpl.java:684)
at sun.nio.ch.DatagramSocketAdaptor.bind(DatagramSocketAdaptor.java:91)
at io.netty.channel.socket.nio.NioDatagramChannel.doBind(NioDatagramChannel.java:192)
at io.netty.channel.AbstractChannel$AbstractUnsafe.bind(AbstractChannel.java:484)
at io.netty.channel.DefaultChannelPipeline$HeadContext.bind(DefaultChannelPipeline.java:1080)
at io.netty.channel.AbstractChannelHandlerContext.invokeBind(AbstractChannelHandlerContext.java:430)
at io.netty.channel.AbstractChannelHandlerContext.bind(AbstractChannelHandlerContext.java:415)
at io.netty.channel.DefaultChannelPipeline.bind(DefaultChannelPipeline.java:903)
at io.netty.channel.AbstractChannel.bind(AbstractChannel.java:197)
at io.netty.bootstrap.AbstractBootstrap$2.run(AbstractBootstrap.java:350)
at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:380)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:357)
at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:116)
at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:137)
at java.lang.Thread.run(Thread.java:722)
When I restart client application without doing anything with server, client will connect with any problems.
What can cause a problem?
In below I attach source code of classes. All source code comes from examples placed in official Netty project page. The only thing which I have midified is that I replaced static variables and functions with non-static ones. It was caused that in future I will need many TCP-UDP connections to multiple servers.
public final class UptimeClient {
static final String HOST = System.getProperty("host", "192.168.2.193");
static final int PORT = Integer.parseInt(System.getProperty("port", "2011"));
static final int RECONNECT_DELAY = Integer.parseInt(System.getProperty("reconnectDelay", "5"));
static final int READ_TIMEOUT = Integer.parseInt(System.getProperty("readTimeout", "10"));
private static UptimeClientHandler handler;
public void runClient() throws Exception {
configureBootstrap(new Bootstrap()).connect();
}
private Bootstrap configureBootstrap(Bootstrap b) {
return configureBootstrap(b, new NioEventLoopGroup());
}
#Override
protected Object clone() throws CloneNotSupportedException {
return super.clone(); //To change body of generated methods, choose Tools | Templates.
}
Bootstrap configureBootstrap(Bootstrap b, EventLoopGroup g) {
if(handler == null){
handler = new UptimeClientHandler(this);
}
b.group(g)
.channel(NioSocketChannel.class)
.remoteAddress(HOST, PORT)
.handler(new ChannelInitializer<SocketChannel>() {
#Override
public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new IdleStateHandler(READ_TIMEOUT, 0, 0), handler);
}
});
return b;
}
void connect(Bootstrap b) {
b.connect().addListener(new ChannelFutureListener() {
#Override
public void operationComplete(ChannelFuture future) throws Exception {
if (future.cause() != null) {
handler.startTime = -1;
handler.println("Failed to connect: " + future.cause());
}
}
});
}
}
#Sharable
public class UptimeClientHandler extends SimpleChannelInboundHandler<Object> {
UptimeClient client;
public UptimeClientHandler(UptimeClient client){
this.client = client;
}
long startTime = -1;
#Override
public void channelActive(ChannelHandlerContext ctx) {
try {
if (startTime < 0) {
startTime = System.currentTimeMillis();
}
println("Connected to: " + ctx.channel().remoteAddress());
new QuoteOfTheMomentClient(null).run();
} catch (Exception ex) {
Logger.getLogger(UptimeClientHandler.class.getName()).log(Level.SEVERE, null, ex);
}
}
#Override
public void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
}
#Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) {
if (!(evt instanceof IdleStateEvent)) {
return;
}
IdleStateEvent e = (IdleStateEvent) evt;
if (e.state() == IdleState.READER_IDLE) {
// The connection was OK but there was no traffic for last period.
println("Disconnecting due to no inbound traffic");
ctx.close();
}
}
#Override
public void channelInactive(final ChannelHandlerContext ctx) {
println("Disconnected from: " + ctx.channel().remoteAddress());
}
#Override
public void channelUnregistered(final ChannelHandlerContext ctx) throws Exception {
println("Sleeping for: " + UptimeClient.RECONNECT_DELAY + 's');
final EventLoop loop = ctx.channel().eventLoop();
loop.schedule(new Runnable() {
#Override
public void run() {
println("Reconnecting to: " + UptimeClient.HOST + ':' + UptimeClient.PORT);
client.connect(client.configureBootstrap(new Bootstrap(), loop));
}
}, UptimeClient.RECONNECT_DELAY, TimeUnit.SECONDS);
}
#Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
void println(String msg) {
if (startTime < 0) {
System.err.format("[SERVER IS DOWN] %s%n", msg);
} else {
System.err.format("[UPTIME: %5ds] %s%n", (System.currentTimeMillis() - startTime) / 1000, msg);
}
}
}
public final class QuoteOfTheMomentClient {
private ServerData config;
public QuoteOfTheMomentClient(ServerData config){
this.config = config;
}
public void run() throws Exception {
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(group)
.channel(NioDatagramChannel.class)
.option(ChannelOption.SO_BROADCAST, true)
.handler(new QuoteOfTheMomentClientHandler());
Channel ch = b.bind(0).sync().channel();
ch.writeAndFlush(new DatagramPacket(
Unpooled.copiedBuffer("QOTM?", CharsetUtil.UTF_8),
new InetSocketAddress("192.168.2.193", 8193))).sync();
if (!ch.closeFuture().await(5000)) {
System.err.println("QOTM request timed out.");
}
}
catch(Exception ex)
{
ex.printStackTrace();
}
finally {
group.shutdownGracefully();
}
}
}
public class QuoteOfTheMomentClientHandler extends SimpleChannelInboundHandler<DatagramPacket> {
#Override
public void channelRead0(ChannelHandlerContext ctx, DatagramPacket msg) throws Exception {
String response = msg.content().toString(CharsetUtil.UTF_8);
if (response.startsWith("QOTM: ")) {
System.out.println("Quote of the Moment: " + response.substring(6));
ctx.close();
}
}
#Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
}
If your server is Windows Server 2008 (R2 or R2 SP1), this problem is likely described and solved by this stackoverflow answer which refers to Microsoft KB article #2577795
This issue occurs because of a race condition in the Ancillary Function Driver
for WinSock (Afd.sys) that causes sockets to be leaked. With time, the issue
that is described in the "Symptoms" section occurs if all available socket
resources are exhausted.
If your server is Windows Server 2003, this problem is likely described and solved by this stackoverflow answer which refers to Microsoft KB article #196271
The default maximum number of ephemeral TCP ports is 5000 in the products that
are included in the "Applies to" section. A new parameter has been added in
these products. To increase the maximum number of ephemeral ports, follow these
steps...
...which basically means that you have run out of ephemeral ports.
I have a client-side java code running in my Android Activity using the Gottox/socket.io.-java-client implementation on Github. This is the client code that needs to simple connect to a server and receive messages from it from time to time. Please bear with me as I'm very new to this domain and might be understanding this completely wrong!
This is what my client code looks like right now:
package com.example.culami;
import io.socket.IOAcknowledge;
import io.socket.IOCallback;
import io.socket.SocketIO;
import io.socket.SocketIOException;
import org.json.JSONException;
import org.json.JSONObject;
public class AcknowledgeExample implements IOCallback {
private SocketIO socket;
int connectionEstablished;
/**
* #param args
*/
/*public static void main(String[] args) {
try {
new AcknowledgeExample();
} catch (Exception e) {
e.printStackTrace();
}
}*/
public AcknowledgeExample() throws Exception
{
connectionEstablished = 0;
socket = new SocketIO();
socket.connect("http://192.168.0.108:3000/", this);
//socket.connect("http://localhost:3000/", this);
// Sends a string to the server.
//socket.send("Hello Server");
// Sends a JSON object to the server.
//socket.send(new JSONObject().put("key", "value").put("key2", "another value"));
//socket.send("server says hello!");
// Emits an event to the server.
//socket.emit("event", "argument1", "argument2", 13.37);
}
#Override
public void onMessage(JSONObject json, IOAcknowledge ack) {
try {
System.out.println("Server said:" + json.toString(2));
} catch (JSONException e) {
e.printStackTrace();
}
}
#Override
public void onMessage(String data, IOAcknowledge ack) {
System.out.println("Server said: " + data);
}
#Override
public void onError(SocketIOException socketIOException) {
System.out.println("an Error occured");
socketIOException.printStackTrace();
}
#Override
public void onDisconnect() {
System.out.println("Connection terminated.");
}
#Override
public void onConnect() {
System.out.println("Connection established");
connectionEstablished = 1;
}
#Override
public void on(String event, IOAcknowledge ack, Object... args) {
System.out.println("Server triggered event '" + event + "'");
}
}
The server side code I'm currently trying to work with is taken from Socket.io's getting started tutorial page and looks as under:
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
app.get('/', function(req, res)
{
//res.sendFile(__dirname + '/index.html');
res.send('<h1>Hello world</h1>');
});
io.on('connection', function(socket)
{
console.log('a user connected');
/*socket.on('chat message', function(msg)
{
io.emit('chat message', msg);
});*/
});
All I need is to figure out a way to make my client and server codes connect. The server side code needs to be java script as sends the client a string keyword/message from time to time. Any pointers/suggestions/fixes will be highly appreciated.