2

Currently I have a server that listens for connections (it is a basic highscore server for a mobile game I have), loops through the connections every 1000ms and listens for any incoming data.

public void readData(Connection c) throws IOException {
    PacketBuffer readBuffer = new PacketBuffer(Server.PACKET_CAPACITY);
    int packetSize = c.getIn().read();
    c.getIn().mark(packetSize);
    byte[] buffer = new byte[packetSize];
    c.getIn().read(buffer, 0, buffer.length);
    readBuffer.setBuffer(buffer);
    packetHandler.addProcess(c, readBuffer);
}

I use my own PacketBuffer and I need to find a way so that c.getIn().read() (That is my connections InputStream) doesn't block. Currently the socket is set to 500ms timeout, and my server would run fine that way. My problem is if someone tries to make their own program to connect to try and hack their own highscores or ddos the server it will become convoluted with a bunch of useless connections that block the thread for 500ms a piece when the connection isn't writing.

1
  • 1
    This sounds like a job for Netty instead of hand-written dispatching code. Commented Jan 28, 2015 at 4:15

3 Answers 3

3

You could try something like this. Every time readData gets called it will check to see if bytes are available to read. I used a while loop here because you want it to process all the data it can before the thread sleeps again. This will ensure messages dont get backed up, if it were to only read one every x milliseconds.

public void readData(Connection c) throws IOException {
    while (c.getIn().available() > 0) {
        int packetSize = c.getIn().read();
        c.getIn().mark(packetSize);
        byte[] buffer = new byte[packetSize];
        c.getIn().read(buffer, 0, buffer.length);
        PacketBuffer readBuffer = new PacketBuffer(Server.PACKET_CAPACITY);
        readBuffer.setBuffer(buffer);
        packetHandler.addProcess(c, readBuffer);
    }

I dont know why you are using the mark method. Looks problematic to me.

You also really need to use a readFully() style method (see DataInputStream) which won't return until it's definitely read the full byte array. Regular reads can always "return short", even when the sender has sent the full data block (due to network packet sizing etc).

Sign up to request clarification or add additional context in comments.

Comments

3

There are two classic ways to implement servers in java.

The first and oldest way is to use a read/write thread pair for each connected client. This is okay for smaller servers without a lot of connected clients as each client requires two threads to manage it. It doesn't scale very well to a lot of concurrent clients.

The second and newer way is to use java.nio.ServerSocketChannel, java.nio.SocketChannel, and java.nio.Selector. These three classes allow you to manage all IO operations for every client you have connected in a single thread. Here is an example for how to implement a very basic server using the java.nio package.

A much better way to implement a server would be to use a third-party framework. A great library that I have used in the past is Netty. It handles all the nitty-gritty details of sockets and provides a fairly clean and simple api that scales well.

Comments

0

You can't. InputStreams are blocking. Period. It's hard to see how non-blocking mode would actually solve the problem you mention. I suggest a redesign is in order.

1 Comment

This is simply not true. You can use method available() on the InputStream of the Socket to check if any bytes can be read without blocking. Additionally, you can use setSoTimeout on Socket and ServerSocket that goes a long way to mitigate the blocking behaviour.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.