codeminders / socket.io-server-java Goto Github PK
View Code? Open in Web Editor NEWThis project forked from avostryakov/socket.io-java
Java Backend for Socket.IO (http://socket.io/)
This project forked from avostryakov/socket.io-java
Java Backend for Socket.IO (http://socket.io/)
Http session isn't available from com.codeminders.socketio.server.Socket with websocket transport at least in Jetty 9.4.7 because of method org.eclipse.jetty.websocket.servlet.UpgradeHttpServletRequest#complete :
public void complete()
{
request = null;
}
As a workaround I have overridden WebsocketConfigurator#modifyHandshake
:
@Override
public void modifyHandshake(
ServerEndpointConfig config,
HandshakeRequest request,
HandshakeResponse response
){
request.getHttpSession(); // it causes session "caching" in UpgradeHttpServletRequest
super.modifyHandshake(config, request, response);
}
But it looks like a hack and it isn't so reliable.
And more, @ServerEndpoint(value="/socket.io/", configurator = WebsocketConfigurator.class)
on WebsocketTransportConnection
does not allow easy override configurator.
I am still getting this exception with the latest 1.0.5 from master:
java.lang.NullPointerException
at com.codeminders.socketio.server.Session.forcePollingCycle(Session.java:494)
at com.codeminders.socketio.server.Session.onPacket(Session.java:300)
at com.codeminders.socketio.server.transport.XHRTransportConnection.handle(XHRTransportConnection.java:78)
at com.codeminders.socketio.server.transport.AbstractHttpTransport.handle(AbstractHttpTransport.java:68)
at com.codeminders.socketio.server.SocketIOServlet.serve(SocketIOServlet.java:146)
at com.codeminders.socketio.server.SocketIOServlet.doPost(SocketIOServlet.java:106)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:707)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:841)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1650)
at org.eclipse.jetty.websocket.server.WebSocketUpgradeFilter.doFilter(WebSocketUpgradeFilter.java:206)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1637)
at org.eclipse.jetty.servlets.CrossOriginFilter.handle(CrossOriginFilter.java:308)
This issue might be an issue with socket.io itself, but I have only ever produced it using socket.io-server-java. It can be recreated using the chat sample that comes with this code.
Steps to reproduce:
1. Modify chat.html so that it declares xhr polling as the transport. This problem is specific to xhr polling (which is what I need to use for my project for various reasons)
var socket = io('http://localhost:8080/chat', {
transports: ['polling']
// transports: ['websocket']
});
2. run ChatServer
3. browse to http://localhost:8080/chat.html
4. put /rbinary in over and over again, while watching the log console
Sooner or later, you'll have this exception show up in the logs:
com.codeminders.socketio.server.SocketIOProtocolException: Expected binary marker in the payload
at ... EngineIOProtocol.binaryDecodePayload(EngineIOProtocol.java:299)
And the Socket.IO connection will be terminated and re-established.
There doesn't appear to be any predictability on when the communication will fail. Sometimes it happens first, sometimes it takes a few /rbinary commands to get it to happen.
The code here is clearly where the exception occurred:
com.codeminders.socketio.protocol.EngineIOProtocol
public static List<EngineIOPacket> binaryDecodePayload(InputStream is)
throws IOException
{
ArrayList<EngineIOPacket> packets = new ArrayList<>();
if(is.read() != 1)
throw new SocketIOProtocolException("Expected binary marker in the payload");
}
I dug in a bit and I learned a few things by going through with a debugger in both Chrome and Firefox and in Java and I learned a few things.
The binary begins with a 1 for all the request where everything works. For the one with a problem, it will begin with a 0 (which triggers the error).
What appears to be happening is that socket.io combines multiple sends into a single binary send. A functional send will follow something like this:
[TEXT POST] 25:42/chat,["server binary"]
[TEXT POST] 42:461-/chat,4[{"_placeholder":true,"num":0}]
[BINARY POST] ��ÿ����� (binary blob)
but when it goes wrong it looks something like this (unfortunately Firefox won't let me copy directly):
[TEXT POST] 25:42/chat,["server binary"]
[BINARY POST] [binarystuffhere]ÿ461-/chat,0[{"_placeholder":true,"num":0}][binarystuffhere]
I copied the latest socket.io.js (1.7.2) down from:
https://github.com/socketio/socket.io-client/blob/master/dist/socket.io.js
and ran with it, and it seemed to have the same problem.
Is this an issue with socket.io creating an invalid message? Or is this an issue with socket.io-server-java not being able to parse a valid message?
It leads to memory leaks, because sessions which has not explicitly closed by client will never be wiped out.
I need new proper release on Maven to be able to make release of NetSpyGlass. I'd rather use your official version instead of the one I built myself and host in my private repository
thanks
This happens when the client connects via broken proxy (which can not be fixed). I am ok if this is just a warning but I would like to make sure this does not cause any resource leakage. It would be nice if this did not cause such a verbose printout as it clogs the logs and there is nothing we can do about it on our end.
2018-01-04 22:09:55,124 WARN qtp2069855160-309 [ty.servlet.ServletHandler]: /socket.io/
java.lang.IllegalStateException: Missing request header 'Sec-WebSocket-Key'
at org.eclipse.jetty.websocket.server.HandshakeRFC6455.doHandshakeResponse(HandshakeRFC6455.java:44)
at org.eclipse.jetty.websocket.server.WebSocketServerFactory.upgrade(WebSocketServerFactory.java:574)
at org.eclipse.jetty.websocket.server.WebSocketServerFactory.acceptWebSocket(WebSocketServerFactory.java:186)
at com.codeminders.socketio.server.transport.jetty.JettyWebSocketTransport.handle(JettyWebSocketTransport.java:103)
at com.codeminders.socketio.server.SocketIOServlet.serve(SocketIOServlet.java:148)
at com.codeminders.socketio.server.SocketIOServlet.doGet(SocketIOServlet.java:101)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:687)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:812)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1669)
at org.eclipse.jetty.servlets.CrossOriginFilter.handle(CrossOriginFilter.java:256)
... which can easily lead to a memory-leak-like behavior if the client opens session using xhr-polling but does not actually poll.
I set the timeout in the onConnect()
listener:
socket.on(this); // attach onDisconnect listener
socket.getSession().setTimeout(Duration.ofSeconds(30).toMillis());
Please advise if I should set timeout differently. At the very least, the queue com.codeminders.socketio.server.transport.XHRTransportConnection#packets
should probably have limited capacity. Maybe even the session could disconnect when the queue becomes full because that means the browser does not read messages
I deployed the Servlet on Tomcat 7.0.67.
`public class Test extends JettySocketIOServlet
{
private static final String ANNOUNCEMENT = "announcement"; // server to all connected clients
private static final String CHAT_MESSAGE = "chat message"; // broadcast to room
private static final String WELCOME = "welcome"; // single event sent by server to specific client
private static final String FORCE_DISCONNECT = "force disconnect"; // client requests server to disconnect
private static final String SERVER_BINARY = "server binary"; // client requests server to send a binary
private static final String CLIENT_BINARY = "client binary"; // client sends binary
private static final long serialVersionUID = 1L;
@Override
@SuppressWarnings("unchecked")
public void init(ServletConfig config) throws ServletException
{
// JdkOverLog4j.install();
System.out.println("Init............");
super.init(config);
of("/chat").on(new ConnectionListener()
{
@Override
public void onConnect(final Socket socket)
{
try
{
socket.emit(WELCOME, "Welcome to Socket.IO Chat, " + socket.getRequest().getRemoteAddr() + "!");
socket.join("room");
}
catch (SocketIOException e)
{
e.printStackTrace();
socket.disconnect(true);
}
socket.on(new DisconnectListener() {
@Override
public void onDisconnect(Socket socket, DisconnectReason reason, String errorMessage)
{
of("/chat").emit(ANNOUNCEMENT, socket.getSession().getSessionId() + " disconnected");
}
});
socket.on(CHAT_MESSAGE, new EventListener()
{
@Override
public Object onEvent(String name, Object[] args, boolean ackRequested)
{
System.out.println("Received chat message: " + args[0]);
try
{
socket.broadcast("room", CHAT_MESSAGE, socket.getId(), args[0]);
}
catch (SocketIOException e)
{
e.printStackTrace();
}
return "OK"; //this object will be sent back to the client in ACK packet
}
});
socket.on(FORCE_DISCONNECT, new EventListener()
{
@Override
public Object onEvent(String name, Object[] args, boolean ackRequested)
{
socket.disconnect(false);
return null;
}
});
socket.on(CLIENT_BINARY, new EventListener()
{
@Override
public Object onEvent(String name, Object[] args, boolean ackRequested)
{
Map map = (Map<Object, Object>)args[0];
InputStream is = (InputStream) map.get("buffer");
ByteArrayOutputStream os = new ByteArrayOutputStream();
try
{
ByteStreams.copy(is, os);
byte []array = os.toByteArray();
String s = "[";
for (byte b : array)
s += " " + b;
s += " ]";
System.out.println("Binary received: " + s);
}
catch (IOException e)
{
e.printStackTrace();
}
return "OK";
}
});
socket.on(SERVER_BINARY, new EventListener()
{
@Override
public Object onEvent(String name, Object[] args, boolean ackRequested)
{
try
{
socket.emit(SERVER_BINARY,
new ByteArrayInputStream(new byte[] {1, 2, 3, 4}),
new ACKListener()
{
@Override
public void onACK(Object[] args)
{
System.out.println("ACK received: " + args[0]);
}
});
}
catch (SocketIOException e)
{
socket.disconnect(true);
}
return null;
}
});
}
});
}
}`
Here is my web.xml:
`
<servlet-name>Test</servlet-name>
<servlet-class>test.Test</servlet-class>
<servlet-name>Test</servlet-name>
<url-pattern>/socket.io/*</url-pattern>
`
When I start up the Tomcat :
javax.servlet.ServletException: Not running on Jetty, JSR-356 support unavailable
at org.eclipse.jetty.websocket.jsr356.server.deploy.WebSocketServerContainerInitializer.onStartup(WebSocketServerContainerInitializer.java:146)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5580)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1574)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1564)
at java.util.concurrent.FutureTask$Sync.innerRun(Unknown Source)
at java.util.concurrent.FutureTask.run(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
....I hava no idea why , Anyone knows?
Revoke 1.0.7 from maven please, I'll make fix ASAP.
I get the following exception when I try:
2017-09-08 16:48:36,797 ERROR main [.z.s.NIOServerCnxnFactory]: Thread Thread[main,5,main] died java.lang.NoSuchMethodError: org.eclipse.jetty.websocket.server.WebSocketServerFactory: method <init>()V not found at com.codeminders.socketio.server.transport.jetty.JettyWebSocketTransport.<init>(JettyWebSocketTransport.java:51) at com.codeminders.socketio.server.transport.jetty.JettyTransportProvider.createWebSocketTransport(JettyTransportProvider.java:37) at com.codeminders.socketio.server.transport.AbstractTransportProvider.init(AbstractTransportProvider.java:31) at com.codeminders.socketio.server.transport.jetty.JettySocketIOServlet.init(JettySocketIOServlet.java:42) at net.happygears.nw2.socket_io.SIOBackendServlet.init(SIOBackendServlet.java:24) at org.eclipse.jetty.servlet.ServletHolder.initServlet(ServletHolder.java:637) at org.eclipse.jetty.servlet.ServletHolder.initialize(ServletHolder.java:421) at org.eclipse.jetty.servlet.ServletHandler.initialize(ServletHandler.java:760) at org.eclipse.jetty.servlet.ServletContextHandler.startContext(ServletContextHandler.java:348) at org.eclipse.jetty.server.handler.ContextHandler.doStart(ContextHandler.java:785) at org.eclipse.jetty.servlet.ServletContextHandler.doStart(ServletContextHandler.java:261) at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68) at org.eclipse.jetty.util.component.ContainerLifeCycle.start(ContainerLifeCycle.java:131) at org.eclipse.jetty.util.component.ContainerLifeCycle.doStart(ContainerLifeCycle.java:113) at org.eclipse.jetty.server.handler.AbstractHandler.doStart(AbstractHandler.java:113) at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68) at org.eclipse.jetty.util.component.ContainerLifeCycle.start(ContainerLifeCycle.java:131) at org.eclipse.jetty.util.component.ContainerLifeCycle.doStart(ContainerLifeCycle.java:113) at org.eclipse.jetty.server.handler.AbstractHandler.doStart(AbstractHandler.java:113) at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68) at org.eclipse.jetty.util.component.ContainerLifeCycle.start(ContainerLifeCycle.java:131) at org.eclipse.jetty.server.Server.start(Server.java:453) at org.eclipse.jetty.util.component.ContainerLifeCycle.doStart(ContainerLifeCycle.java:105) at org.eclipse.jetty.server.handler.AbstractHandler.doStart(AbstractHandler.java:113) at org.eclipse.jetty.server.Server.doStart(Server.java:420) at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68) at net.happygears.nw2.WebServer.start(WebServer.java:1288) at net.happygears.nw2.netspyglass.NetSpyGlass.startWebServer(NetSpyGlass.java:248) at net.happygears.nw2.Nw2UI.run(Nw2UI.java:332) at net.happygears.nw2.ViewsTester.run(ViewsTester.java:23) at net.happygears.nw2.Nw2ViewsTester.main(Nw2ViewsTester.java:28)
I am testing v1.0.3 with jetty 9.2.x (could not get jetty 9.4.x to work for me for unrelated reasons). Server-side socket-io servlet always uses long poll and never switches to websocket. I am attaching a screenshot of the Chrome developer tools panel that shows that the server always returns 200 and never 101 (protocol switch). I have seen the 101 response with socket-io library v1.0.2
Is there some special initialization I should do to enable websocket transport? I need the library to support both websocket and long poll.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.