Server / Thread (threading & connection handling) #2

Continuing my first article this time I’m going to implement threading into my small application. For that I’ll use a Server and a Thread class and the Executor stuff.

First of all, I’m changing a snippet in my main class:

Server server = null;
server = new Server(serverAddress, serverPort, serverThreads, serverThreadTimeout, verboseOutput);
 
server.run();

becomes

Server server = null;
server = new Server();
server.setAddress(serverAddress);
server.setPort(serverPort);
server.setThreads(serverThreads);
server.setVerbose(verboseOutput);
server.setTimeout(serverThreadTimeout);
 
server.run();

The reason for this change is simple: Currently all default-settings are set in my main class. That means if one wants to use the server class, he/she has to provide all five parameters. That’s considered bad and hence I’m using setters and sane defaults within my server class. That is called „Configuration by Exception“.

Here are the defaults and the setters, should be pretty self-explanatory:

package com.example.lyrapolicy;
 
import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
 
public class Server
{
    private InetAddress addr;
    private int         port;
    private int         threads;
    private int         timeout;
    private boolean     verbose;
 
    Server()
    {
        try
        {
            this.addr = InetAddress.getByName("localhost");
        } catch (UnknownHostException e)
        {
            e.printStackTrace();
        }
        this.port = 4444;
        this.threads = 10;
        this.timeout = 100;
        this.verbose = false;
    }
 
    public void setAddress(String address)
    {
        try
        {
            this.addr = InetAddress.getByName(address);
        } catch (UnknownHostException e)
        {
            e.printStackTrace();
        }
    }
 
    public void setPort(int port)
    {
        this.port = port;
    }
 
    public void setThreads(int threads)
    {
        this.threads = threads;
    }
 
    public void setVerbose(boolean verbose)
    {
        this.verbose = verbose;
    }
 
    public void setTimeout(int timeout)
    {
        this.timeout = timeout;
    }

The interesting part starts now. The „run“ method:

    public void run()
    {
        boolean keepRunning = true;
        ExecutorService executor = Executors.newFixedThreadPool(this.threads);
 
        try
        {
            ServerSocket listener = new ServerSocket(this.port, 0, this.addr);
            Socket connection;
 
            while (keepRunning)
            {
                connection = listener.accept();
                System.out.println("Received new connection: " + connection);
                Runnable worker = new Thread(connection);
                executor.execute(worker);
            }
        } catch (IOException ioe)
        {
            System.out.println("IOException on socket listen: " + ioe);
            ioe.printStackTrace();
        }
 
        // This will make the executor accept no new threads
        // and finish all existing threads in the queue
        executor.shutdown();
 
        // Wait until all threads are finished
        while (!executor.isTerminated())
        {
            try
            {
                java.lang.Thread.sleep(500);
            } catch (InterruptedException ire)
            {
                System.out.println("Interrupted Exception on shutdown: " + ire);
                ire.printStackTrace();
            }
        }
 
        System.out.println("Finished all threads");
    }

You can see here, how I’m opening a socket to listen on and how I’m handing the „connection“ to my thread class. By the way, „sleep(500)“ is there for a reason: If you’re omitting it, you’re wasting resources. Step by Step (listening+handing over):

connection = listener.accept()
 
Runnable worker = new Thread(connection);
executor.execute(worker);

My thread-class now receives the connection and can do something with that:

package com.example.lyrapolicy;
 
import java.net.Socket;
 
public class Thread implements Runnable
{
    private final Socket connection;
 
    Thread(Socket connection)
    {
        this.connection = connection;
    }
 
    public void run()
    {
 
    }
}

Executing my Java Application and connecting to it using telnet I get:

Received new connection: Socket[addr=/127.0.0.1,port=34869,localport=4444]
Received new connection: Socket[addr=/127.0.0.1,port=34870,localport=4444]

Pretty cool 🙂 Hopefully I can continue to stumble that fast through Java.

No Comments

Post a Comment