I'm trying some multiplayer game ideas out at the moment and am trying to create a Java application to serve a web browser based multiplayer game.
My development environment is Eclipse on the main machine, and notepad + Google Chrome on this laptop.
I'm creating the websocket using javascript at the client end, and using the java.net.Socket at the server end.
I've managed to get a connection acknowledged at both ends, but can't seem to send or recieve any data between them without the client closing the connection (doesn't even error; just seems to freak out at something and call socket.close).
Does anyone have any ideas?
Here's some code:
Client:
<script type="text/javascript">
var socket;
function init() {
socket = new WebSocket("ws://192.168.0.3:10000");
socket.onopen = function() { alert('OPEN: ' + socket.readyState); }
socket.onmessage = function (msg) { alert('DATA: ' + msg.data); }
socket.onerror = function (msg) { alert('DATA: ' + msg.data); }
socket.onclose = function () { alert('CLOSED: ' + socket.readyState); }
}
function onClick() {
socket.send("YAY!");
}
</script>
Server:
public static void main(String args[])
{
System.out.printLn("Websocket server test");
ServerSocket connectSocket = null;
try
{
Socket clientSocket;
connectSocket = new ServerSocket(10000);
System.out.printLn("Waiting for connection...");
clientSocket = connectSocket.accept();
System.out.printLn("Got one!");
PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);
BufferedReader in = new BufferedReader(
new InputStreamReader(clientSocket.getInputStream()));
for(int i=0;i<100;i++) //Shit but easy
{
String data = in.readLine();
System.out.printLn("Got data: " + data);
out.printLn("YAY!");
}
}
catch (IOException e)
{
System.out.printLn("You fail: " + e.getMessage());
}
System.out.printLn("Finished!");
}
Rather than going the painful way of implementing the spec in Java, I'd suggest that you use an existing solution like jWebSocket.
Also if you don't mind leaving Java land, I'd also suggest that you take a look at Node.js for your Server.
Doing both Server and Client in JavaScript will save you lots of time and lots of Code, especially since JSON just doesn't fit that well into static land. Also creating multiplayer servers in Node.js is trivial, since the event based, single threaded model fits the whole thing pretty well.
More information on WebSocket can be found in the FAQ. In case you want to get started with Node.js take a look at the TagWiki.
shameless plug follows
For two multiplayer games that were written using Node.js take a look at my GitHub page.
Try this lib - https://github.com/mrniko/netty-socketio
Based on high performance socket lib Netty. It supports latest protocol of Socket.IO server. Several transports including websocket.
On web side use Socket.IO client javascript lib:
<script type="text/javascript">
var socket = io.connect('http://localhost:81', {
'transports' : [ 'websocket' ],
'reconnection delay' : 2000,
'force new connection' : true
});
socket.on('message', function(data) {
// here is your handler on messages from server
});
// send object to server
var obj = ...
socket.json.send(obj);
</script>
I would suggest our high level solution: Bristleback Server. It contains both server and client, you can choose from several existing low level WebSocket engines (like Jetty, Netty or Tomcat), developing with Bristleback is extremally fast and easy. However, it is still Beta and we are working hard to release a final 1.0.0 version. If you use Maven, we have provided an archetype with ready to use web application.
I am one of the co-creators of Bristleback Server.
As no one yet really answered your question: the reason it does not work, is because you are not implementing the websocket specification. It takes of lot more work to setup a proper websocket connection than just opening a socket, as the websocket connection setup starts with a HTTP upgrade request. Your client is closing the connection, because it does not receive a positive answer on the upgrade request to start with.
I can't help you with sockets, but can i suggest you to use RMI technology? I'm trying to make a multiplayer rpg in java, and i'm using remote method invocation between server and client (it is possible also call-back the client from the server). It's really easy use it, but it uses TCP instead of UDP. In LAN experience there is no lag, on internet I have not tried yet. However, if your game tolerates just a bit retard between request and response, there is no problem.
This is the link of my project, Client and Server classes may be useful for you.
Related
Intro
My code can process all bytes that are sent to a server and decide whether or not to let them go through and eventually send responses. I would like to use this to use the server as web server, web socket server and tcp server in one.
Although my code is written for Minecraft, I am not asking this on a Minecraft forum because answering this question doesn't require any prior knowledge about Minecraft or its codebase.
All you need to know about Minecraft
Minecraft is a Java game that can be played online. When it is being played online, there is a server that opens a ServerSocket and all players have their own client that opens a Socket that will communicate with the ServerSocket of the server.
Anyone can create a Minecraft server and install server-side modifications on their server (for those who know Minecraft, these are usually called plug-ins). My application is such a server-side modification. Most Minecraft servers are being hosted by Minecraft host companies. The owners of the servers have some kind of access to the part of the host computer that manages the server files.
Goal
The goal of my modification is to let the Minecraft server serve more clients than just the Minecraft clients. I would like the same server to also work as web server (for http and https requests) as well as (secure) web socket server and tcp server.
Why no multiple server sockets
The most common solution would be to just create a ServerSocket for the other server types and assign a different port to all of them. However, that is not an option in my case. Most hosts forbid you to open other ports or ask extra money for it. So I need to do it all with just the Minecraft ServerSocket.
What I achieved so far
So far, I have managed to let all bytes that are sent to the minecraft server first go through my code. My code can choose whether or not to let the bytes continue to the Minecraft server code. It can also send responses on its own without the need to inform the Minecraft server code at all.
In principle, what I have managed to do is sufficient to accomplish my goal, but I would like some help with how to continue. I will explain below what I have and have not accomplished so far.
The first byte that is sent by a Minecraft client to the server is always the same, namely 16. This is great because it allows me to easily distinguish Minecraft clients from web browsers and tcp clients.
HTTP requests and websocket connections always start with the same byte, namely 71. HTTPS and secure websockets always start with the byte 22. The TCP connections I was talking about will be sent by my own applications, so I can choose exactly what bytes they will send and I can simply program my modification to respond to that.
I managed to distinguish http requests and websocket connections by their connection property. Http requests always send 'Connection: keep-alive' while websocket connections always send 'Connection: upgrade'. (Although some browsers do the k, a and u in uppercase and others do not.)
Handling normal http requests wasn't very hard to do. Handling TCP connections won't be hard either because I will control everything. But I have issues with the remaining connection types:
Problems I need help with
The web socket protocol is quite large and I would prefer not to handle it completely with only my code. (I tried this before, but I kept having problems with the parts that were rarely used and thus not tested.) So I would like to use some library that allows me to only worry about the payload rather than the entire protocol. Unfortunately, web socket libraries generally want to create the ServerSocket, which is not possible in my case. So does anyone have advice on what to do here?
I haven't found any info on how to read https requests properly. Could someone tell me where to look for the details of this protocol or provide a nice link?
For secure web sockets, I will face the same problems as with the 'normal' web socket connections after I find out how to read the requests.
Code
All my code so far can be found at https://github.com/knokko/Multi-Purpose-Server. The most interesting part is probably the part where my code gets the opportunity to process all bytes before they arrive at the Minecraft code, that code is shown below.
Short question(s)
For those who didn't understand exactly what my question (you could see it as 2 questions that are strongly related) is:
-How I should read https requests and secure web socket handshakes?
-Does anyone know a library that can handle web socket input that doesn't require to create the ServerSocket itself?
// This channel handler will be registered for every connection client that will
// inspect
// any message before it reaches the Minecraft code.
pipeline.addFirst("multipurpose_handler_inspector", new ChannelInboundHandlerAdapter() {
private boolean deactivated;
private ChannelListener listener;
#Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
//super.channelRead will send the content to the minecraft code
try {
if (!deactivated) {
ByteBuf message = (ByteBuf) msg;
if (listener != null) {
listener.read(ctx, message);
} else {
byte firstByte = message.getByte(0);
// All Minecraft connections start with the byte 16
if (firstByte == 16) {
deactivated = true;
super.channelRead(ctx, msg);
}
// All insecure web connections start with the byte 71
else if (firstByte == 71) {
byte[] data = new byte[message.readableBytes()];
message.getBytes(0, data);
WebHandler.Type type = WebHandler.determineConnectionType(data);
if (type == WebHandler.Type.HTTP) {
listener = new HTTPListener();
listener.readInitial(ctx, message);
} else if (type == WebHandler.Type.WEBSOCKET) {
// TODO Find a nice way to handle web socket connections
listener = new WebSocketListener();
listener.readInitial(ctx, message);
} else {
deactivated = true;
super.channelRead(ctx, msg);
}
}
// All secure web connections start with the byte 22
else if (firstByte == 22) {
// TODO implement the secure web protocols and find a way to read this stuff
// and find the difference
System.out.println(
"We are dealing with a secure websocket or https connection");
byte[] data = new byte[message.readableBytes()];
message.getBytes(0, data);
System.out.println(new String(data));
}
// My applications
else if (firstByte == 31) {
listener = new TCPListener();
listener.readInitial(ctx, message);
} else {
System.out.println("Unknown connection type");
deactivated = true;
super.channelRead(ctx, msg);
}
}
} else {
super.channelRead(ctx, msg);
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
});
If you can ALWAYS identify the Minecraft traffic, your best bet might be to run an apache/httpd and/or tomcat server on the same box and forward all non-Minecraft traffic to it. If you do this, the HTTPS stuff might just be a matter of correctly configuring the http server for https traffic.
You may have to configure your code as an http proxy--in fact (Just thought of this) you might want to go out and look for an open source http proxy and just tweak it with your code to extract Minecraft traffic and forward it before doing the rest of the proxy stuff.
I wouldn't do the HTTPs stuff from scratch, it's not terribly difficult but I'd call it non-trivial.
Oh and if your problem is "differentiating Minecraft HTTPS traffic from other HTTPS connections on the same port" I can't help except to say that this might be a good subject for your question :)
To convince some people to switch from old school tech, I need to build a chat demo application that manages more than 10K concurrent connections using Java (like Node.Js stuff).
I have tested Netty 5.0 which is awesome but requires lot of work to be done; on the other hand Jetty 9.3 is great but is slow compared to other competitors.
After some search I found the Vert.x 3 toolkit which is based on Netty with a plethora of great tools (no need to reinvent the wheel), I have seen the examples in git and I was able to build a websocket server, etc.
public void start() throws Exception {
vertx.createHttpServer().websocketHandler(new Handler<ServerWebSocket>() {
#Override
public void handle(ServerWebSocket e) {
// business stuff in the old style not yet lambda
}
}).listen(port);
}
Being new to the Vert.x world, I could not figure out how to manage connected users using it, normally the old fashion way is to use something like:
HashMap<UUID,ServerWebSocket> connectedUsers;
When a connection is established I check if it exists; if not I add it as a new entry and do some functions to send, broadcast, retrieve through the collection and so on.
My question is does Vert.x 3 have something to deal with connections to track them and remove those who left (ping pong), broadcast, etc. or should I implement them from scratch using cookies, session, ....)
I could not find any real example using Vert.x 3.
Basically, the scope of the websocketHandler represents a connection. In your example this is your anonymous class. I created a little websocket chat example where I use the Vert.x event bus to distribute the messages to all the clients.
In the start method of the server we handle the websocket connections. You can implement the closeHandler to monitor client disconnection. There are also handlers for exceptions, ping-pong, etc. You can identify a specific connection by using the textHandlerID, but you have also access to the remote address.
public void start() throws Exception {
vertx.createHttpServer().websocketHandler(handler -> {
System.out.println("client connected: "+handler.textHandlerID());
vertx.eventBus().consumer(CHAT_CHANNEL, message -> {
handler.writeTextMessage((String)message.body());
});
handler.textMessageHandler(message -> {
vertx.eventBus().publish(CHAT_CHANNEL,message);
});
handler.closeHandler(message ->{
System.out.println("client disconnected "+handler.textHandlerID());
});
}).listen(8080);
}
The client example is also written in Java. It just prints all the received messages on the websocket connection to the console. After connection it sends a message.
public void start() throws Exception {
HttpClient client = vertx.createHttpClient();
client.websocket(8080, "localhost", "", websocket -> {
websocket.handler(data -> System.out.println(data.toString("ISO-8859-1")));
websocket.writeTextMessage(NAME+ ":hello from client");
});
}
In web application, i have a chat gadget embedded in web page (.HTML). The back end code of my application Java and the chat gadget communicates with .PHP. I do not have access to .PHP environment.
I can only code in java to handle HTML requests using Java.
Issue:
When i click refresh on browser, the new chat session begins every time.
Even when i jump from one page to other the chat session refreshes and new chat begins.
I am not suppose to do any changes in .PHP environment but need to change code in Java
Question:
I want to mold program in such a way that .PHP environment
thinks that page has not been refreshed and does not break the session.
I think proxy might be solution but how to implement those? Any other solution for same.
To build a proxy, first create a ServerSocket on a port that the widget will talk to, then start accept accepting connection on it.
As new connections come in, create a new Socket to the php server. Then you have to pipe the input from one to the output of the other and vice-versa.
That's a generic proxy. For your case you'd have to add some logic to detect that a connection already exists (probably with a cookie), then reuse the existing socket instead of creating a new.
Unfortunately, it will be a bit of work to parse the input, and get the protocol to match what php is doing.
(edit to add example)
Here's a barebones generic proxy example to get you started. Run this then point your browser to localhost.
public class Proxy {
public static void main(String args[]) throws Exception {
ServerSocket server = new ServerSocket(80);
Socket browser = server.accept();
Socket remote = new Socket("google.com", 80);
pipe(browser.getInputStream(), remote.getOutputStream());
pipe(remote.getInputStream(), browser.getOutputStream());
remote.close();
server.close();
}
private static void pipe(InputStream in, OutputStream out) throws IOException {
while(in.available() == 0) {
Thread.yield();
}
while(in.available() > 0) {
int data = in.read();
System.out.write(data);
out.write(data);
}
}
}
A working solution would need to be multithreaded (or async) and instead of just piping the data between servers you'll have to get in there and inspect it, then decide if you need to open a new socket or re-use an existing one.
I'm going to try to make a simple hack that sends continually streaming integers from an Android App to a Node.js server.
I want to know how to create such a stream in Android and how to receive it in my Node.js server if I am using express for routing the API calls.
If anyone can give me a high level explanation of how this can work that would be great. Specific code examples of creating Node.js ReadStreams from an outside WriteStream would be even better.
Depending on the frequency of the stream, you may want to consider websockets. There are android libraries available that implement the websocket standard (a quick search turned up https://github.com/koush/android-websockets), which claims to implement both websockets, and Socket.IO.
Conveniently, both websockets and Socket.IO are perfect for Node. I like the ws module the most for pure websockets. You can create a websocket server, and feed it an express app to let it handle websocket upgrade requests. Something along the lines of (not tested):
var express = require('express');
var websockets = require('ws')
var app = express();
var wsServer = new WebSocketServer({ noServer: true });
var server = app.listen(3000, function () {
// Express stuff.
});
server.on('upgrade', function (req, sock, head) {
wsServer.handleUpgrade(req, sock, head, function (connection) {
// The connection object will deliver the stream.
// You'll need to listen for 'message' events.
});
});
wsServer.on('error', function (err) {
// Don't forget errors.
});
For Socket.IO, see here.
im trying to write a simple web server in java.
right now ive only got a simple program but id like to extend it so that it can serve multiple browsers by establishing multiple tcp connections.
ive been reading about threading. my understanding is that you can make a new thread and that will continue as if its another program entirely. so with a new thread, it can be like there are 2 web servers which can serve 2 browsers, or x web servers which can serve x web browsers.
im a bit lost on how to create new threads in java though and to give each new thread a connection.
my thoughts are that i would have a loop like this which gets new connections and passes each new connection to a new thread
// make new ServerSocket
while (true) {
Socket newConn = serverSocket.accept();
// make new thread, and pass in newConn
}
can someone give me some guidance on how to move forward?
(also if ive made an error somewhere, please do point it out. im new to threaded programming so its entirely possible ive not properly understood it)
rob
edit:
k thanks all.
i went and wrote something, that java tutorial helped a lot.
ive got a new issue now
i added a loop in my run() method in the new thread which contains a 10 second countdown (using Thread.sleep(1000)) whenever the server receives a request for an image, so i can see which threads are running when. (index.html has 4 images in it)
so i requested the index.html page and my server works fine. then i opened up about a dozen new tabs. my expectation was that the request for the index.html page would be instant but it would take 10 seconds for the images to be sent to the browser (because of that delay i put in there), at which point the server would receive the request for the next index.html page, and so on. overall, i thought that the dozen index.html pages would be served instantly while it would take 10 seconds for the 4 * 12 = 36 images to be served on all tabs.
what actually happened was it took 10 seconds to get the first 4 images, then 10 seconds for the next 4 images, etc. so rather than serving multiple web pages, my server just queues up requests and deals with one page at a time.
i think my program is at fault. but i feel like i might not properly understand how a browser interacts with a server. i thought the browser requests new objects as the html page is parsed. so my server should be receiving dozens of requests if i open a dozen pages. i tried opening up several tabs in FF and then several windows in FF but this did not help.
HOWEVER, when i opened up IE, FF and Chrome, and i asked for index.html at different times (about 2 seconds apart), it looked like each browser was receiving the page simultaneously, in other words, at one point, there were 12 different images being served, 4 to each browser
so i guess im looking for a bit of confirmation that this is the expected behavior? and if so, why is it that i could only see this behavior when i opened up 3 different browsers and not when i opened up multiple tabs?
(for those that asked, i plan ok taking a networks course next year, but im trying to do some of the basic stuff now. so half self learning, half h/w)
If you are looking for something robust look online for a working solution.
If it is for learning purposes, then create your own.
There are several ways to do this. The easiest is to do this As taken from the Java Tutorial :
import java.net.*;
import java.io.*;
public class MultiServer {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = null;
boolean listening = true;
try {
serverSocket = new ServerSocket(4444);
} catch (IOException e) {
System.err.println("Could not listen on port: 4444.");
System.exit(-1);
}
while (listening)
new MultiServerThread(serverSocket.accept()).start();
serverSocket.close();
}
}
import java.net.*;
import java.io.*;
public class MultiServerThread extends Thread {
private Socket socket = null;
public MultiServerThread(Socket socket) {
super("MultiServerThread");
this.socket = socket;
}
public void run() {
try {
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
BufferedReader in = new BufferedReader(
new InputStreamReader(
socket.getInputStream()));
String inputLine, outputLine;
KnockKnockProtocol kkp = new KnockKnockProtocol();
outputLine = kkp.processInput(null);
out.println(outputLine);
while ((inputLine = in.readLine()) != null) {
outputLine = kkp.processInput(inputLine);
out.println(outputLine);
if (outputLine.equals("Bye"))
break;
}
out.close();
in.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
You would implement your logic for processing your requests in:
KnockKnockProtocol kkp = new KnockKnockProtocol();
outputLine = kkp.processInput(null);
You could optimize your code by putting your Threads in a Thread Pool so you did not need to create a new Thread each time.
The part below is subjective and depends on the types of requests and what you do with each one.
If you have a lot of concurrent client requests then NIO is the way to go.
If your requests are short and you have over 10 concurrent ones create a pool.
If your requests are more than 100, then I would start looking at NIO.
You might also consider Netty and Java NIO. There's more than one way to do it.
Sun's classic Java tutorial includes a section on programming with sockets that walks you through an example very similar to the program you're trying to write.
a web server is nothing but a glorified socket server with messaging. tech has been around since the very first network connection was made. i had a project about a year and a half ago that was similar to what your trying to do. Java NIO is the best bet to start with, has connection and thread pooling and all the advanced stuff that a web server needs, but its a bit complicated. if you want a VERY good baseline to start with, check out http://www.quickserver.org/ the system i wrote was based on this and it now handles about 45,000 devices on one server last i heard.