Using ThreadPoolExecutor and DiscardPolicy - java

I need to make a client queue with ThreadPoolExecutor and an ability to drop clients if it exceeds some number (5 for example). It is kinda DDOS protection. When client #6 is requesting my server - it got dropped, etc. I got my server and client code, but I don't know how to realize ThreadPoolExecutor and DiscardPolicy. Ideas or examples?
Simple server:
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import java.util.logging.Level;
import java.util.logging.Logger;
public class Server {
public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
ServerSocket server = new ServerSocket (3000);
ExecutorService es = Executors.newFixedThreadPool(2);
Semaphore semaphore = new Semaphore (2);
while(true){
semaphore.acquire();
Socket accept2 = server.accept();
es.execute(()->{
try (Socket accept = accept2) {
serve(accept);
} catch (Exception exception) {
Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, exception);
}
finally {
semaphore.release();
}
});
}
}
private static void serve(final Socket accept) throws ClassNotFoundException, IOException {
InputStream inputStream = accept.getInputStream();
OutputStream outputStream = accept.getOutputStream();
ObjectInputStream inputStream2 = new ObjectInputStream (inputStream);
while (true){
Object readObject = inputStream2.readObject();
System.out.println(readObject);
}
}
}
And a simple client:
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.net.Socket;
public class Client {
public static void main(String[] args) throws IOException, InterruptedException {
Socket socket = new Socket ("localhost", 3000);
ObjectOutputStream oos = new ObjectOutputStream (
socket.getOutputStream());
oos.writeObject("First!");
Thread.sleep(10000);
oos.writeObject("First again!");
Thread.sleep(10000);
oos.writeObject("First again again!");
}
}

Use ThreadPoolExecutor with DiscardPolicy as below:
int poolSize=1;
int maxPoolSize=2;
int queueSize=5;
long aliveTive=1000;
ArrayBlockingQueue<Runnable> queue= new ArrayBlockingQueue<Runnable>(queueSize);
ThreadPoolExecutor executor= new ThreadPoolExecutor(poolSize,maxPoolSize,aliveTive,
TimeUnit.MILLISECONDS,queue,new ThreadPoolExecutor.DiscardPolicy());
}
Rejected tasks:
New tasks submitted in method execute(Runnable) will be rejected when the Executor has been shut down, and also when the Executor uses finite bounds for both maximum threads and work queue capacity, and is saturated.
In either case, the execute method invokes the RejectedExecutionHandler.rejectedExecution(Runnable, ThreadPoolExecutor) method of its RejectedExecutionHandler.
Four predefined handler policies are provided:
In the default ThreadPoolExecutor.AbortPolicy, the handler throws a runtime RejectedExecutionException upon rejection.
In ThreadPoolExecutor.CallerRunsPolicy, the thread that invokes execute itself runs the task. This provides a simple feedback control mechanism that will slow down the rate that new tasks are submitted.
In ThreadPoolExecutor.DiscardPolicy, a task that cannot be executed is simply dropped.
In ThreadPoolExecutor.DiscardOldestPolicy, if the executor is not shut down, the task at the head of the work queue is dropped, and then execution is retried (which can fail again, causing this to be repeated.)
Have a look at this documentation page for more details

Related

Running a live Java Server on Amazon AWS

I am developing a Client-Server application with several other programmers, in Java. At this point in time I do not want to be running the code locally. I want to be able to connect to the Server from any machine.
I wrote a test server and test client, just to make sure that things are working properly. But they are not. I am using Amazon AWS EC2 Linux that comes with Java. I am able to compile and run my Server after I SSH into the EC2, but the Client on my local disk is just not connecting. Here is the code.
// Code found online (https://cs.lmu.edu/~ray/notes/javanetexamples/)
import java.io.IOException;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
public class TestServer {
public static void main(String[] args) throws Exception {
try (ServerSocket listener = new ServerSocket(50000)) {
System.out.println("The capitalization server is running...");
System.out.println(listener.getInetAddress());
ExecutorService pool = Executors.newFixedThreadPool(20);
while (true) {
pool.execute(new Capitalizer(listener.accept()));
}
}
}
private static class Capitalizer implements Runnable {
private Socket socket;
Capitalizer(Socket socket) {
this.socket = socket;
}
#Override
public void run() {
System.out.println("Connected: " + socket);
try {
Scanner in = new Scanner(socket.getInputStream());
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
while (in.hasNextLine()) {
out.println(in.nextLine().toUpperCase());
}
} catch (Exception e) {
System.out.println("Error:" + socket);
} finally {
try { socket.close(); } catch (IOException e) {}
System.out.println("Closed: " + socket);
}
}
}
}
// Code found online (https://cs.lmu.edu/~ray/notes/javanetexamples/)
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;
public class TestClient {
public static void main(String[] args) throws Exception {
try (Socket socket = new Socket("ADDRESS HERE", 50000)) {
System.out.println("Enter lines of text then Ctrl+D or Ctrl+C to quit");
Scanner scanner = new Scanner(System.in);
Scanner in = new Scanner(socket.getInputStream());
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
while (scanner.hasNextLine()) {
out.println(scanner.nextLine());
System.out.println(in.nextLine());
}
}
}
}
In place of "ADDRESS HERE" in the Client, I have tried the private IP and public IP of my Amazon EC2 instance. I have also tried the public DNS name. Nothing seems to work. There is just no connection from the Client to the Server. In fact, "Enter lines of text then Ctrl+D or Ctrl+C to quit" never prints.
All help is appreciated. Thank you.
Allow your IP address to send request to the EC2. For this, you need to go to your Security Group and add your IP there. Follow these steps-
GO to your AWS console.
Click on EC2, then under Resources you will find Security Groups.
Select your security group.
Follow the steps in the given image.
Since you're able to connect to EC2 instance via SSH, your Security Group allows this.
Now you need to allow requests from the client in this Security Group. You will either need to provide a concrete IP, IP range or allow all IPs (not recommended) in the group.
You can find how to do this here.

Closing and releasing JMS resources

The question is simple: How do I properly close and release JMS resources in a Java SE application. I use IBM MQ v8.
My problem is that IBM MQ for JMS seems to start a thread named "JMSCCThreadPoolMaster" which doesn't die when there's no more JMS in the application. It lives on until the application itself dies. This is not what I want. I want to be able to close down that thread pool programmatically. My application only does 2 secs of JMS on startup and then goes on to to do other things for weeks or even months in a fairly resource constrained environment. It seems unreasonable that that I'm not able to tell JMS that I'm done with using it after the first 2 secs, so that resources are properly released.
Here's a little test to prove the point:
package org.test.jms.producer.simpleconsumer;
import com.ibm.msg.client.jms.JmsConnectionFactory;
import com.ibm.msg.client.jms.JmsConstants;
import com.ibm.msg.client.jms.JmsFactoryFactory;
import com.ibm.msg.client.wmq.WMQConstants;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.jms.Connection;
import javax.jms.JMSException;
import javax.jms.MessageConsumer;
import javax.jms.Queue;
import javax.jms.Session;
public class MyTest {
private static final Logger LOGGER = Logger.getLogger(MyTest.class.getName());
public static void main(String[] args) throws JMSException, InterruptedException {
// Do some JMS stuff in a separate thread.
Thread jmsThread = new Thread(new JmsRunnable());
jmsThread.start();
// Wait some time to allow any background thread to properly
// close down.
Thread.sleep(60*1000);
// Print the threads that exist at this point in time.
Thread[] threads = new Thread[100];
int noOfThreads = Thread.enumerate(threads);
for (Thread t : threads) {
if (t != null) {
System.out.println(" Active thread : " + t.getName());
}
}
}
private static class JmsRunnable implements Runnable {
#Override
public void run() {
try {
// just do a connect and then immediately disconnect.
JmsFactoryFactory ff = JmsFactoryFactory.getInstance(JmsConstants.WMQ_PROVIDER);
JmsConnectionFactory factory = ff.createConnectionFactory();
Map<String, Object> props = new HashMap<>();
props.put(WMQConstants.WMQ_CONNECTION_MODE, WMQConstants.WMQ_CM_CLIENT);
props.put(WMQConstants.WMQ_HOST_NAME, "localhost");
props.put(WMQConstants.WMQ_QUEUE_MANAGER, "dev");
props.put(WMQConstants.WMQ_CHANNEL, "mychannel");
factory.setBatchProperties(props);
Connection connection = factory.createConnection(); // ++
connection.close();
LOGGER.log(Level.INFO, "Thread is closing");
} catch (JMSException ex) {
LOGGER.log(Level.SEVERE, "Something bad happened", ex);
}
}
}
}
At the point where I list active threads there should no longer be any active JMS resources held onto by application. Yet there's this background thread.
The line marked with "++" is what triggers the creation of the background thread named "JMSCCThreadPoolMaster".
How to properly close down? A solution specific to IBM MQ is acceptable, i.e. it will be ok for me to cast to IBM MQ specific JMS class.

Java Socket Server for Game Login/Authentication

I am currently working on a Java Application using the classes under java.net.* for a MMORPG I am creating. It'll be connected with a Unity3D Game (using .NET Sockets for TCP). I am unsure how to handle the login/authentication of players.
Suggestions? I was thinking about handling authentication this via a secure form over https, creating and storing a temporary login key in the database, and then sending the key back to the client, allotting them a minute to connect to a game server using the randomly generated key. Is this a secure and reliable solution, or is there something better I can do?
Server Class
import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
public class Server extends Thread {
public static final int MAX_CLIENTS = 500;
private ServerSocket listener;
protected ArrayList<Client> clients;
public Server(int listenPort) throws IOException {
listener = new ServerSocket(
listenPort, MAX_CLIENTS,
InetAddress.getLocalHost()
);
clients = new ArrayList<Client>();
}
#Override
public void run() {
while (true) {
try {
Socket socket = listener.accept();
Client client = new Client(socket, this);
clients.add(client);
new Thread(client).start();
} catch (IOException e) {}
}
}
public static void main(String[] args) throws IOException {
new Server(4428).start();
}
}
Client Class
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
public class Client implements Runnable {
private Socket socket;
private Server server;
private BufferedReader in;
private PrintWriter out;
public Client(Socket sock, Server serv) {
socket = sock;
server = serv;
in = null;
out = null;
}
#Override
public void run() {
try {
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
out = new PrintWriter(socket.getOutputStream(), true);
while (true) {
// Read Data with read()
}
} catch (IOException e) {}
}
public void read() throws IOException {
}
public void send(String data) {
}
}
I would recommend using HTTPS for login and for important account actions (buy/sell/transfer items). When the client logins to the server over HTTPS the server should generate a long (64-128 bytes) random session id that is stored in the database. Also generate a temporary one-time authentication token (long random value) for the client's TCP connection.
The reason for using HTTPS is to help stop MITM attacks from stealing the users in game assets.
If the traffic between client & server is low you could use a TLS socket instead of a normal TCP socket. Just make sure to have the client validate(Signed by a trusted CA and that the domain matches) the server's certificate.
Even if you use HTTPS for important actions a MITM attack could still mess with the users actions (moving, attacking, chat) or change what the user sees (hide monsters or other users).

multithreading in java

I want "runnable" to run at 5tps. This is not executing paralelly.
package tt;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
public class mySpawner {
public int tillDone = 0;
public int tillMax = 0;
public ArrayList arrayList;
private myWorker myworking;
private ScheduledExecutorService service = Executors.newScheduledThreadPool(50);
Runnable runnable = new Runnable() {
#Override
public void run() {
try {
System.out.println(System.nanoTime());
Thread.sleep(7000);
} catch (InterruptedException ex) {
Logger.getLogger(mySpawner.class.getName()).log(Level.SEVERE, null, ex);
}
}
};
public void activate() {
try {
service = Executors.newScheduledThreadPool(50);
service.scheduleAtFixedRate(runnable, 0, 200, TimeUnit.MILLISECONDS);
} catch (Exception e) {//Catch exception if any
System.err.println("Error: " + e.getMessage());
}
}
public void deactivate() {
service.shutdown();
}
}
Consider this:
Your tasks are sleeping for 7 seconds during their execution
You are scheduling a new task every 200ms
You only have 50 threads in your executor
It should be clear, I hope, that you'll run out of pooled threads in just a few seconds, and you'll lose your parallelism. You need to balance this better, either by reducing the rate or reducing the sleep. Increasing the pool size won't help, you'll still run out of threads.
scheduleAtFixedRate does only spawn a single thread but executes the runnable provided with a fixed rate.
The action runs in less amount of time than the given period: in this case it is respawned with exactly the specified period.
The action runs longer (your case): the action is started again immediately.
If you want to have the desired behaviour you may use the following pattern: Just execute the runnable once:
service.schedule(runnable, 0, TimeUnit.MILLISECONDS);
but inside the runnable's run method add the next invokation by
service.schedule(runnable, 200, TimeUnit.MILLISECONDS);
Nevertheless consider the arithmetic as described in the answer by skaffman.
Update: Howard is right, my first example was wrong.
I verified this works if you change your active() method:
service = Executors.newScheduledThreadPool(50);
new Thread() {
public void run() {
long nextTime = System.currentTimeMillis();
while (true) {
service.submit(runnable);
long waitTime = nextTime - System.currentTimeMillis();
Thread.sleep(Math.max(0, waitTime));
nextTime += 200;
}
}
}.start();

HTTP Request Object

Is there an object within the standard Java SE that can accept a HTTP request from a socket? I have found how to create and send one, however I have not found a way to retrieve a HTTP object from a socket. I can create one my self, but I would rather rely on a heavily tested object.
This seems like something that would be readily available given the structure of JSP.
There is a small HTTP server in the Java 6 SDK (not sure if it will be in the JRE or in non-Sun JVM's).
From http://www.java2s.com/Code/Java/JDK-6/LightweightHTTPServer.htm :
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Executors;
import com.sun.net.httpserver.Headers;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
public class HttpServerDemo {
public static void main(String[] args) throws IOException {
InetSocketAddress addr = new InetSocketAddress(8080);
HttpServer server = HttpServer.create(addr, 0);
server.createContext("/", new MyHandler());
server.setExecutor(Executors.newCachedThreadPool());
server.start();
System.out.println("Server is listening on port 8080" );
}
}
class MyHandler implements HttpHandler {
public void handle(HttpExchange exchange) throws IOException {
String requestMethod = exchange.getRequestMethod();
if (requestMethod.equalsIgnoreCase("GET")) {
Headers responseHeaders = exchange.getResponseHeaders();
responseHeaders.set("Content-Type", "text/plain");
exchange.sendResponseHeaders(200, 0);
OutputStream responseBody = exchange.getResponseBody();
Headers requestHeaders = exchange.getRequestHeaders();
Set<String> keySet = requestHeaders.keySet();
Iterator<String> iter = keySet.iterator();
while (iter.hasNext()) {
String key = iter.next();
List values = requestHeaders.get(key);
String s = key + " = " + values.toString() + "\n";
responseBody.write(s.getBytes());
}
responseBody.close();
}
}
}
Yeah, you make a new HTTP Request object from what you accept on the socket. What you do after that is up to you, but it should probably involve an HTTP Response.
import java.io.*;
import java.net.*;
import java.util.*;
public final class WebServer {
public static void main(String args[]) throws Exception {
int PORT = 8080;
ServerSocket listenSocket = new ServerSocket(PORT);
while(true) {
HttpRequest request = new HttpRequest(listenSocket.accept());
Thread thread = new Thread(request);
thread.start();
}
}
}
From: http://www.devhood.com/tutorials/tutorial_details.aspx?tutorial_id=396
There's some more work to be done in the tutorial, but it does look nice.
It looks like you are looking for a Servlet. A servlet is an API that lets you receive and respond to an HTTP request.
Your servlet gets deployed in a container, which is basically the actual Web server that will take care of all the protocol complexities. (The most populare are Tomcat and Jetty)

Categories

Resources