/PNet

High level Java network library

Primary LanguageJavaMIT LicenseMIT

Warning: this library is unmaintained.

PNet

PNet is an easy to use network library for Java 1.6 or higher.

Features

  • Guaranteed data transfer using TCP
  • Safe transfer using TLS
  • Support for GZIP compression
  • Asynchronous
  • Completely thread safe
  • Optimized, see benchmarks
  • Universal logging using SLF4J

Known issues:

  • None

Download

PNet can be downloaded from the Maven Central Repository. PNet is released under the MIT license.


How to use


Packets

All data is sent using a Packet. These Packets are immutable and contain the following fields:

  1. PacketType (Request or Reply)
  2. Packet ID
  3. Data

PacketType and Packet ID can be used to identify incoming Packets. Normally, you should not be creating Packets yourself.

Building Packets

To create a Packet, use a PacketBuilder. This helper object contains several methods to allow easy creation of Packets.

Packet packet = new PacketBuilder(Packet.PacketType.Request)
                .withInt(99)
                .withString("abc")
                .withBoolean(true)
                .build();

Reading Packets

Just like the PacketBuilder, there is a PacketReader.

PacketReader packetReader = new PacketReader(packet);
int i = packetReader.readInt();

The data of the Packet must be read in the same order as it was written!


Creating a Server

There are 2 different Server implementations available: PlainServer and TLSServer.

Server server = new PlainServer();
Server server = new TLSServer(keyStoreStream, keyStorePassword, keyStoreType);

To use a Server, you might want to add a PNetListener to catch events.

server.setListener(new PNetListener()
{
    @Override
    public void onConnect(final Client c)
    {
        // Hello client!
    }

    @Override
    public void onDisconnect(final Client c)
    {
        // Goodbye :(
    }

    @Override
    public void onReceive(final Packet p, final Client c) throws IOException
    {
        // Handle Packet here
    }
});

The Server can be started: server.start(port) and stopped server.stop().


Creating a Client

There are 2 different Client implementations available: PlainClient and TLSClient.

Client client = new PlainClient();
Client client = new TLSClient(trustStoreStream, trustStorePassword, trustStoreType);

A client fires events just like a Server does.

client.setClientListener(new PNetListener()
{
    @Override
    public void onConnect(final Client c)
    {
        // Hello server!
    }

    @Override
    public void onDisconnect(final Client c)
    {
        // Farewell
    }

    @Override
    public void onReceive(final Packet p, final Client c) throws IOException
    {
        // Handle Packet?
    }
});

Use connect(host, port) to connect, and client.close() to disconnect.

Extra Client functionality

PNet contains 2 classes which can simplify using Clients even more.

  1. AsyncClient
  2. AutoClient

Any Client implementation can be passed to add functionality to.

The AsyncClient adds asynchronous functionality to a Client.

AsyncClient asyncClient = new AsyncClient(new PlainClient());
asyncClient.connectAsync("localhost", 8080, new AsyncListener()
{
    @Override
    public void onCompletion(final boolean success)
    {
        // Success?
    }
});
asyncClient.sendAsync(packet, new AsyncListener()
{
    @Override
    public void onCompletion(final boolean success)
    {
        // Success?
    }
});

The AutoClient automatically connects to given host:port so you don't have to check if the Client is connected.

AutoClient autoClient = new AutoClient(new TLSClient(), "localhost", 8080);

These implementations can be stacked.

AsyncClient stackedClient = new AsyncClient(new AutoClient(new TLSClient(), "localhost", 8080));

By stacking these implementations, you now have an asynchronous automatically connecting Client.

Note that order is important.

AutoClient invalid = new AutoClient(new AsyncClient(new TLSClient()), "localhost", 8080);

In this example, the AutoClient will call the default connect and send, which will render the AsyncClient completely useless. If used correctly, the AsyncClient will expose connectAsync and sendAsync, which will call connect and sync from the AutoClient asynchronously.


Using TLS

When using TLSServer, a key store is required. When using TLSClient, a trust store is required.

server = new TLSServer(
                keyStoreStream,
                keyStorePassword,
                keyStoreType
);
client = new TLSClient(
                trustStoreStream,
                trustStorePassword,
                trustStoreType
);

SSL debug output can be turned on by calling TLS.setSSLDebug().

To get up and running quickly, I recommend using Portecle.

  1. Create a new PKCS12 keystore (your keystore)
  2. Generate a keypair
  3. Export head certificate
  4. Create a new PKCS12 keystore (your truststore)
  5. Import the exported certificate

PNet is configured to use the latest, most secure TLS protocols and cipher suites available.

Using compression

To compress a Packet, use the PacketCompressor helper class.

Packet compressed = PacketCompressor.compress(packet);
Packet decompressed = PacketCompressor.decompress(packet);

Smarter Packet handling

A common mistake people make is to handle all different Packets in the main onReceive event handler. When handling various Packets with various Packet IDs, make sure to use a PacketDistributer. A pNetListener implementation is available to link your distributer to your Client or Server.

PacketDistributer packetDistributer = new PacketDistributer();
client.setClientListener(new DistributerListener(packetDistributer));
server.setListener(new DistributerListener(packetDistributer));

For each Packet ID you want to handle, add a PacketHandler implementation.

short someID = 666;
packetDistributer.addHandler(someID, new PacketHandler()
{
    @Override
    public void handlePacket(final Packet p, final Client c) throws IOException
    {
        // Handle this evil Packet for me please
    }
});

Even better: separate all the handlers into their own class.

short anotherID = 123;
packetDistributer.addHandler(anotherID, new anotherHandlerClass());

A default handler can be set by using packetDistributer.setDefaultHandler(PacketHandler).


Multithreading Note

PNet uses a threadpool to handle all threading. If your application needs to shut down immediately, this can be done by killing all threads using ThreadManager.shutdown().