I have been trying to find for some time why my Handler does not trigger the events at all but I had no luck in finding it. I will post the entire class and hopefully someone notices a stupid mistake or something.
The class is only managing the lifespan of some sockets (I am doing that because the android devices seem to be very moody when it comes to reopening ports shortly after closing them). The class is a singleton as I want to have awareness of what ports I use everywhere.
package com.ltd.jeefo.alex.routeassistant.wifi.sync.utils;
import android.annotation.SuppressLint;
import android.os.Handler;
import android.support.annotation.Nullable;
import com.ltd.jeefo.alex.routeassistant.logging.ILog;
import com.ltd.jeefo.alex.routeassistant.logging.ScopedLogger;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Date;
import java.util.HashMap;
/**
* Created by Alex on 16/02/18.
*/
public class SocketsManager {
private static final SocketsManager ourInstance = new SocketsManager();
private static final Handler handler = new Handler();
public static SocketsManager getInstance() {
return ourInstance;
}
#SuppressLint("UseSparseArrays")
private static final HashMap<Integer, ManagedServerSocket> serverSockets = new HashMap<>();
private SocketsManager() {
}
/**
* Method used for obtaining the server socket for a given port
* #param port the port where we want the socket to be opened
* #return the server socket to be used or null if we couldn't start a server socket at that port
*/
public ManagedServerSocket getSocketAtPort(final int port) {
ManagedServerSocket managedServerSocket;
if (serverSockets.containsKey(port)) {
managedServerSocket = serverSockets.get(port);
} else {
managedServerSocket = new ManagedServerSocket(port, handler);
serverSockets.put(port, managedServerSocket);
}
return managedServerSocket;
}
/**
* Closes all the sockets after some delay
*
* #param msDelay the delay in milliseconds
*/
public void closeAllSocketsAfterDelay(final long msDelay) {
for (final ManagedServerSocket managedSocket : serverSockets.values()) {
managedSocket.RequestSocketClosingAfterDelay(msDelay);
}
}
enum ServerSocketStatus {
OPEN_NOT_REQUESTED,
OPEN_FAILED,
OPENED, // there is always a close request started by default, just in case
USER_CLOSE_REQUESTED,
CLOSED
}
public class ManagedServerSocket {
private final ILog logger;
private final static long DEFAULT_CLOSING_TIME_MILLS = 3600000; // one hour
private final static long DEFAULT_RETRY_TIME_MILLS = 15000; // 15 seconds
private final Handler mHandler;
private final int mPort;
private ServerSocket mSocket;
private SocketsManager.ServerSocketStatus serverSocketStatus;
private Long closingTime;
private Runnable defaultClosingRunnable;
private Runnable explicitClosingRunnable;
private ManagedServerSocket(final int port, final Handler handler) {
this.mPort = port;
this.mHandler = handler;
logger = new ScopedLogger(null, ManagedServerSocket.class, "Port", Integer.toString(mPort));
serverSocketStatus = SocketsManager.ServerSocketStatus.OPEN_NOT_REQUESTED;
defaultClosingRunnable = new Runnable() {
#Override
public void run() {
try {
logger.Warn("Server socket closing automatically at port %s after long delay",
Integer.toString(mPort));
mSocket.close();
serverSocketStatus = SocketsManager.ServerSocketStatus.CLOSED;
closingTime = new Date().getTime();
} catch (IOException e) {
e.printStackTrace();
logger.Error(e, "Failed to close server socket at port %s after delay", Integer.toString(mPort));
}
}
};
explicitClosingRunnable = new Runnable() {
#Override
public void run() {
try {
logger.Debug("Socket closing after delay");
mSocket.close();
serverSocketStatus = SocketsManager.ServerSocketStatus.CLOSED;
closingTime = new Date().getTime();
} catch (IOException e) {
e.printStackTrace();
logger.Error(e, "Failed to close server socket after delay");
}
}
};
}
public void RequestSocketClosingAfterDelay(long delayMills) {
logger.Debug("Close socket after delay %s ms", Long.toString(delayMills));
switch (serverSocketStatus) {
case OPEN_NOT_REQUESTED:
logger.Warn("Closing port that was never opened");
return;
case OPEN_FAILED:
logger.Error("Cannot close a socket that failed to open");
return;
case CLOSED:
logger.Warn("Cannot request closing an already closed socket");
return;
case OPENED:
mHandler.removeCallbacks(defaultClosingRunnable);
break;
case USER_CLOSE_REQUESTED:
logger.Warn("Requested to close a socket that was already requested for closing");
mHandler.removeCallbacks(explicitClosingRunnable);
break;
}
mHandler.postDelayed(explicitClosingRunnable, delayMills);
serverSocketStatus = SocketsManager.ServerSocketStatus.USER_CLOSE_REQUESTED;
}
#Nullable
private ServerSocket RequestSocketForUsage() {
boolean socketIsOpened = true;
switch (serverSocketStatus) {
case USER_CLOSE_REQUESTED:
mHandler.removeCallbacks(explicitClosingRunnable);
break;
case OPENED:
mHandler.removeCallbacks(defaultClosingRunnable);
break;
case CLOSED:
case OPEN_FAILED:
case OPEN_NOT_REQUESTED:
socketIsOpened = tryOpenServerSocket();
break;
}
if (!socketIsOpened) {
serverSocketStatus = SocketsManager.ServerSocketStatus.OPEN_FAILED;
logger.Error("Failed to open the socket server and return it");
return null;
}
// Add back the default closing handler now
mHandler.postDelayed(defaultClosingRunnable, DEFAULT_CLOSING_TIME_MILLS);
serverSocketStatus = SocketsManager.ServerSocketStatus.OPENED;
return mSocket;
}
#Nullable
public Socket accept() throws IOException {
ServerSocket socket = RequestSocketForUsage();
if (socket != null) {
return socket.accept();
} else {
return null;
}
}
public SocketsManager.ServerSocketStatus getStatus() {
return serverSocketStatus;
}
private boolean tryOpenServerSocket() {
int attempt = 0;
do {
++attempt;
try {
this.mSocket = new ServerSocket(mPort);
break;
} catch (Exception e) {
logger.Warn(e, "Failed to start ServerSocket on attempt: %s", Integer.toString(attempt));
synchronized (this) {
try {
wait(DEFAULT_RETRY_TIME_MILLS);
} catch (InterruptedException e1) {
logger.Error("Retry wait() interrupted");
e1.printStackTrace();
}
}
}
} while (attempt < 6);
if (this.mSocket == null) {
logger.Error("Failed to start ServerSocket");
return false;
} else {
logger.Info("ServerSocket started");
return true;
}
}
}
}
----------------------------------------- LATER EDIT -----------------------------------------
I am always triggering the getSocketAtPort() method inside asyncTasks which seems to be part of the problem.
I now opened a socket (using getSocketAtPort()) inside an activity (inside onCreate()) before calling it in asyncTasks. When I do that all the handlers start working (including the ones requested inside the asyncTask). My guess is that the problem has something to do with threading.
So, I was trying to create a chat for multiple users via client-server communication. Connecting and chatting works quite nicely already, however, if one client disconnects from the server (triggered by the keyword exit as the program is console-based atm because the UI is not yet finished), one of the other ClientIO-Threads shuts down additionally to the one related to the disconnecting client. I just don't have any idea why, as those Threads only handle the output of the client that is sending a message.
I tested the program with 3 clients. It seems that if you close client 1 or 2 (with exit; ID in order of connection, starting at 0), the ClientIO-Thread of client 0 shuts down. If you close client 0, Thread 1 shuts down.
Why does that happen? How do I fix it?
Please go easy on me if there's something wrong about how I put the question, first time I ask myself. Thanks in advance!
Code:
Server:
class Server:
import java.io.*;
import java.net.*;
public class Server extends Thread{
int n = 0;
private Socket angekommenerClient;
private ServerSocket sSocket;
Liste client_Liste;
public Server (int port) {
try {
//System.out.println("konst1");
sSocket = new ServerSocket (port);
//System.out.println("konst2");
client_Liste=new Liste();
}catch (Exception e){e.printStackTrace();}
}
public void run(){
try {
//System.out.println("try");
InputStreamReader isr;
BufferedReader br;
while (true) {
//System.out.println("while");
/**Verbindungsannahme**/
angekommenerClient = sSocket.accept();
System.out.println("accept");
InputStream input=angekommenerClient.getInputStream();
OutputStream output=angekommenerClient.getOutputStream();
/**Übergabe Username**/
isr = new InputStreamReader(input);
br = new BufferedReader(isr);
String username = br.readLine();
/**Datenerfassung**/
client_PC neu = new client_PC(angekommenerClient,output,angekommenerClient.getInetAddress(), n, username);
client_Liste.insert(neu);
n++;
client_Liste.toFirst();
System.out.println("test "+((client_PC)client_Liste.getObject()).getID());
/**Vebindungsaufbau**/
new Connection (neu, new BufferedReader(new InputStreamReader(input)));
}
}catch (Exception e){e.printStackTrace();}
}
class Connection{
private BufferedReader client_input; // vom Client
private client_PC client;
private String client_anwender;
private ClientIO cIO;
public Connection(client_PC c, BufferedReader ci){
client=c;
client_input=ci;
cIO=new ClientIO();
cIO.start();
}
class ClientIO extends Thread{
boolean closed = false;
public void run(){
PrintStream ps = null;
while(!client.getSocket().isClosed() && !closed){
try{
if(client_input.ready()){
if(!client_Liste.isEmpty()){
/**Nachricht einlesen**/
System.out.println("listen");
String msg = client_input.readLine();
System.out.println("Input: "+msg);
/**Abmeldung erfahren**/
if(msg.equals("exit")){
closed = true;
}
/**Nachricht weiterleiten...**/
client_Liste.toFirst();
while(client_Liste.hasAccess()){
client_PC cpc = ((client_PC)client_Liste.getObject());
System.out.println("ID: "+cpc.getID());
/**...außer an sich selbst**/
if(cpc.getID()!=client.getID()){
ps = new PrintStream(cpc.getOutput());
ps.println(client.getUsername() + "(" + client.getID() + "): " + msg);
}
client_Liste.next();
}
System.out.println("finish");
}
}
}catch(Exception e){e.printStackTrace();};
}
/**Offenes schließen**/
if(ps != null){
ps.close();
}
System.out.println("disconnected" + client.getID());
stop();
}
}
}
}
class client_PC:
import java.io.*;
import java.net.*;
public class client_PC{
private Socket client_Socket;
private OutputStream client_Output;
private InetAddress client_IP;
private Object client_Info=null;
private int ID;
private String username;
public client_PC(Socket c_Socket,OutputStream c_Output,InetAddress c_IP, int id, String uname){
client_Socket=c_Socket;
client_Output=c_Output;
client_IP=c_IP;
ID = id;
username = uname;
}
public InetAddress getInetAddress(){
return client_IP;
}
public Socket getSocket(){
return client_Socket;
}
public int getID(){
return ID;
}
public OutputStream getOutput(){
return client_Output;
}
public void setInfo(Object info){
client_Info=info;
}
public Object getInfo(){
return client_Info;
}
public String getUsername(){
return username;
}
}
class Liste:
public class Liste{
private ListElement ListKopf;
private ListElement VorAktuellerZeiger, AktuellerZeiger;
Liste(){
ListKopf=null;
AktuellerZeiger=null;
VorAktuellerZeiger=null;
}
boolean isEmpty(){
return (ListKopf==null);
}
public boolean hasAccess() {
return (!this.isEmpty() && AktuellerZeiger!=null);
}
public void next(){
if (this.hasAccess()){
ListElement Hilf=AktuellerZeiger;
AktuellerZeiger=AktuellerZeiger.naechstes;
VorAktuellerZeiger=Hilf;
}
}
public void toFirst() {
AktuellerZeiger=ListKopf;
VorAktuellerZeiger=null;
}
public void toLast() {
if(!hasAccess())this.toFirst();
if(AktuellerZeiger!=null){
while(AktuellerZeiger.naechstes!=null)
next();
}
}
public Object getObject(){
if (this.hasAccess())
return AktuellerZeiger.Inhalt;
else
return null;
}
public void setObject(Object pObject){
if (pObject!=null && this.hasAccess()){
remove();
insvor(pObject);
}
}
private void insvor(Object x){
ListElement Neu= new ListElement(x,AktuellerZeiger);
if(VorAktuellerZeiger==null){ListKopf=Neu; AktuellerZeiger=Neu;}
else {VorAktuellerZeiger.naechstes=Neu;}
}
private void insnach(Object x){
next();
insvor(x);
}
public void insert(Object pObject){
if (pObject!=null)
insvor(pObject);
}
public void append(Object pObject){
if (pObject!=null){
this.toLast();
if(this.hasAccess())
insnach(pObject);
}
}
public void remove(){
if(AktuellerZeiger!=null){
AktuellerZeiger=AktuellerZeiger.naechstes;
if(VorAktuellerZeiger==null){ListKopf=AktuellerZeiger;}
else {VorAktuellerZeiger.naechstes=AktuellerZeiger;}
}
}
}
class ListElement:
public class ListElement{
protected Object Inhalt;
protected ListElement naechstes;
ListElement (Object x, ListElement n){
Inhalt = x;
naechstes = n;
}
}
Client:
class Client:
import java.io.*;
import java.net.*;
public class Client
{
//String IP = "10.16.139.3";
String IP = "localhost";
String name;
int port = 5000;
Socket socket;
ClientThread t1, t2;
public Client(String n){
name = n;
}
public void main() throws IOException{
/**Socket**/
socket = new Socket(IP, port);
/**Übergabe Name**/
PrintStream ps = new PrintStream(socket.getOutputStream());
ps.println(name);
/**Verbindungs-Threads**/
t1 = new ClientThread(System.in, socket.getOutputStream(), true);
t2 = new ClientThread(socket.getInputStream(), System.out, false);
t1.start();
t2.start();
while(t1.isAlive() && t2.isAlive()){}
ps.close();
socket.close();
}
}
class ClientThread:
import java.awt.*;
import java.lang.*;
import java.io.*;
import java.net.*;
public class ClientThread extends Thread{
boolean halt = false, isSender;
InputStream is;
InputStreamReader isr;
BufferedReader br;
String msg;
OutputStream os;
PrintStream ps;
public ClientThread(InputStream s1, OutputStream s2, boolean s)
{
try{
isSender = s;
is = s1;
isr = new InputStreamReader(is);
br = new BufferedReader(isr);
os = s2;
ps = new PrintStream(os);
}catch(Exception e){e.printStackTrace();}
}
public void run(){
while (!halt){
try{
if(br.ready()){
msg = br.readLine();
if(msg != null){
ps.println(msg);
if((msg.equals("exit") || msg.trim().equals("null"))&&isSender){stopp(); stop();}
}
else{
System.out.println("Error msg: "+msg);
}
}
}catch(Exception e){e.printStackTrace();}
}
}
public void stopp(){
halt = true;
}
public void weiter(){
halt = false;
}
}
I can't seem to figure out how to notify my Server class that a connection was lost. My server code is:
public class Server {
static int port = 4444;
static boolean listening = true;
static ArrayList<Thread>Clients = new ArrayList<Thread>();
static MatchMaker arena;
public static void main(String[] args) {
Initialize();
Thread startConnections = new Thread(run());
startConnections.start();
}
private static Runnable run(){
System.out.println("(" + new SimpleDateFormat("HH:mm:ss").format(new Date()) + ") Started listening on port: " + port);
try(ServerSocket socket = new ServerSocket(port)){
while(listening){
if(Clients.size() <= 4){
Socket clientSocket = socket.accept();
MultiThread connection = new MultiThread(clientSocket, arena, );
Clients.add(connection);
System.out.println("Client connected from " + clientSocket.getRemoteSocketAddress() + " Assigned ID: " + connection.getId());
System.out.println("Currently connected clients(" + Clients.size() + "): ");
for(int i = 0; i < Clients.size(); i++)
System.out.println(" - " + Clients.get(i).getId());
connection.start();
}
}
}
catch(Exception e){
e.printStackTrace();
}
return null;
}
private static void Initialize(){
arena = new MatchMaker();
}
}
The problem here is that since this class keeps track of the connected clients I want it to notice when a client has lost connection. The MultiThread class already has a functional way of detecting clients that lost connection, however I don't know how to pass that information back to the Server class. I've tried passing the server class to MultiThread as a parameter, but it said I couldn't use 'this' in a static manner.
You can keep them in synchronized map like:
Map<Integer, ClientObject> connectedClients = new HashMap<Integer, ClientObject>(); //key integer will be the client id
Other suggestion:
Map<String, ClientObject> connectedClients = new HashMap<String, ClientObject>(); //key String will be the client IP&userName (you decide)
Fist of all use thread safe collection for monitoring the client connection so replace the following
ArrayList Clients = new ArrayList();
with
ConcurrentLinkedQueue Clients = new ConcurrentLinkedQueue();
But your problem is that you are trying to use limited resource in thread safe manner so best option would be using Semaphore. I have re factored your class a bit to give an idea.Hope it helps. Plz look closely on 'SERVER_INSTANCE'.
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.Semaphore;
public class Server {
private final int MAX_AVAILABLE = 4;
public final Semaphore SERVER_INSTANCE = new Semaphore(MAX_AVAILABLE, true);
static int port = 4444;
static volatile boolean listening = true;
static MatchMaker arena;
public static void main(String[] args) {
Initialize();
Thread startConnections = new Thread(run());
startConnections.start();
}
private static void Initialize() {
//do somthing
}
private static Runnable run(){
System.out.println("(" + new SimpleDateFormat("HH:mm:ss").format(new Date()) + ") Started listening on port: " + port);
ServerSocket socket = null;
while(listening){
try {
socket = new ServerSocket(port);
try {
SERVER_INSTANCE.acquire();
Socket clientSocket = socket.accept();
MultiThread connection = new MultiThread(clientSocket, arena, SERVER_INSTANCE);
} catch (InterruptedException e) {
e.printStackTrace();
}
} catch (IOException e1) {
e1.printStackTrace();
}
}
return null;
}
static class MultiThread implements Runnable{
Semaphore serverInstance ;
public MultiThread(Socket clientSocket, MatchMaker arena, Semaphore serverInstance) {
serverInstance = serverInstance;
}
#Override
public void run() {
try {
serverInstance.acquire();
//Do your work here
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
serverInstance.release();
}
}
}
class MatchMaker {
}
}
I'm trying to implement WebSockets with a Javascript-based client and a Java-based server. I think I've done all the correct steps, but for an unknown reason, I can't establish the connection with both.
When the server socket receives a connection, it handles to form a websocket-accept response, and it sends back to the client, but the connection in the client socket instantly close, weird that there's no handshake problem.
Does anyone have an idea what might be the problem?
Here's my server code implemented in java:
package server;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import server.message.Message;
import server.message.SpeakMessage;
public class Server implements ConnectionListener {
private static final int PORT = 1509;
private MessageDispatcher dispatcher = new MessageDispatcher();
private List<ConnectionManager> clients = new ArrayList<>();
public void listen() {
try (ServerSocket server = new ServerSocket(PORT)) {
System.out.printf("Listening on port %d...%n", PORT);
while (true) {
System.out.println("Waiting for connection...");
Socket client = server.accept();
System.out.println("Incoming connection - Attempting to establish connection...");
ConnectionManager manager = new ConnectionManager(client, dispatcher, this);
manager.start();
}
} catch (IOException e) {
System.out.println("Unable to start server");
e.printStackTrace();
}
System.exit(0);
}
public void execute() {
try {
while (true) {
if (dispatcher.isEmpty()) {
Thread.sleep(100);
continue;
}
Message msg = dispatcher.read();
if (msg instanceof SpeakMessage)
broadcast(MessageEncoder.spoke(((SpeakMessage) msg).getText()));
}
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
}
public static void main(String[] args) {
final Server server = new Server();
new Thread(new Runnable() {
#Override
public void run() {
server.listen();
}
}).start();
server.execute();
}
public synchronized void broadcast(byte[] message) {
for (ConnectionManager client : clients) {
client.send(message);
}
}
#Override
public synchronized void clientConnected(ConnectionManager who) {
clients.add(who);
System.out.println("Connected client " + clients.size());
}
#Override
public synchronized void clientDisconnected(ConnectionManager who) {
clients.remove(who);
}
}
Heres subclass ConnectionManager of server:
package server;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.net.Socket;
import java.security.MessageDigest;
import java.util.Properties;
import server.message.HandshakeMessage;
import server.message.Message;
public class ConnectionManager {
private static final int CLIENT_VERSION = 1;
private Socket socket;
private MessageDecoder decoder = new MessageDecoder();
private MessageDispatcher dispatcher;
private ConnectionListener listener;
public ConnectionManager(Socket connection, MessageDispatcher dispatcher, ConnectionListener listener) {
socket = connection;
this.dispatcher = dispatcher;
this.listener = listener;
}
public void start() {
Thread t = new Thread(new ChannelReader());
t.setName("Client thread");
t.setDaemon(true);
t.start();
}
public void send(byte[] data) {
if (socket == null)
return;
try {
DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
dos.write(data);
dos.flush();
} catch (IOException e) {
disconnect("Client closed the connection");
}
}
private class ChannelReader implements Runnable {
private boolean accepted = false;
private String ret = null;
#Override
public void run() {
try {
DataInputStream in = new DataInputStream(socket.getInputStream());
while (socket != null && socket.isConnected()) {
int len = in.readShort();
if (len < 0) {
disconnect("Invalid message length.");
}
String s;
readLine(in);
Properties props = new Properties();
while((s=readLine(in)) != null && !s.equals("")) {
String[] q = s.split(": ");
props.put(q[0], q[1]);
}
if(props.get("Upgrade").equals("websocket") && props.get("Sec-WebSocket-Version").equals("13")) { // check if is websocket 8
String key = (String) props.get("Sec-WebSocket-Key");
String r = key + "" + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; // magic key
MessageDigest md = MessageDigest.getInstance("SHA-1");
md.reset();
md.update(r.getBytes());
byte[] sha1hash = md.digest();
String returnBase = base64(sha1hash);
ret = "HTTP/1.1 101 Switching Protocols\r\n";
ret+="Upgrade: websocket\r\n";
ret+="Connection: Upgrade\r\n";
ret+="Sec-WebSocket-Accept: "+returnBase;
} else {
disconnect("Client got wrong version of websocket");
}
Message msg = decoder.decode((String) props.get("Sec-WebSocket-Protocol"));
if (!accepted) {
doHandshake(msg);
} else if (dispatcher != null) {
dispatcher.dispatch(msg);
}
}
} catch (Exception e) {
disconnect(e.getMessage());
e.printStackTrace();
}
}
private void doHandshake(Message msg) {
if (!(msg instanceof HandshakeMessage)) {
disconnect("Missing handshake message");
return;
}
HandshakeMessage handshake = (HandshakeMessage) msg;
if (handshake.getVersion() != CLIENT_VERSION) {
disconnect("Client failed in handshake.");
return;
}
send(ret.getBytes());
accepted = true;
listener.clientConnected(ConnectionManager.this);
}
private String base64(byte[] input) throws ClassNotFoundException,
SecurityException, NoSuchMethodException, IllegalArgumentException,
IllegalAccessException, InvocationTargetException, InstantiationException {
Class<?> c = Class.forName("sun.misc.BASE64Encoder");
java.lang.reflect.Method m = c.getMethod("encode", new Class<?>[]{byte[].class});
String s = (String) m.invoke(c.newInstance(), input);
return s;
}
private String readLine(InputStream in) {
try{
String line = "";
int pread;
int read = 0;
while(true) {
pread = read;
read = in.read();
if(read!=13&&read!=10)
line += (char) read;
if(pread==13&&read==10) break;
}
return line;
}catch(IOException ex){
}
return null;
}
}
public synchronized void disconnect(String message) {
System.err.println(message);
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
}
}
socket = null;
listener.clientDisconnected(ConnectionManager.this);
}
}
And the MessageDispatcher:
package server;
import java.util.Queue;
import java.util.concurrent.LinkedBlockingDeque;
import server.message.Message;
public class MessageDispatcher {
Queue<Message> messageQueue = new LinkedBlockingDeque<>();
public void dispatch(Message message) {
messageQueue.offer(message);
}
public Message read() {
return messageQueue.poll();
}
public boolean isEmpty() {
return messageQueue.isEmpty();
}
}
And heres my client code implemented in javascript:
var canvas, // Canvas DOM element
ctx, // Canvas rendering context
socket; // Socket connection
function init() {
// Initialise the canvas
canvas = document.getElementById("gameCanvas");
ctx = canvas.getContext("2d");
// Maximise the canvas
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
// Initialise socket connection
if (window.WebSocket) {
socket = new WebSocket("ws://localhost:1509/", ["1", "YURI"]);
socket.onopen = onSocketConnected();
socket.onclose = onSocketDisconnect();
socket.onmessage = onSocketMessage();
socket.onerror = onSocketError();
} else {
alert("The browser does not support websocket.");
}
};
// Socket message
function onSocketMessage(message) {
console.log('Message: ' + message.data);
};
// Socket error
function onSocketError(error) {
console.log('Error: ' + error.data);
};
// Socket connected
function onSocketConnected() {
console.log("Connected to socket server");
};
// Socket disconnected
function onSocketDisconnect() {
console.log("Disconnected from socket server");
};
I think, it is because you are using the Socket Package on the Java Server Side and the WebSocket API on the Client Side. Your idea is really good but the wrong technology.
Keep the WebSocket on the Client Side (Javascript) becaue you don't have lots of other possibilities, but try JWebSocket on the Server side (Java). In Fact WebSocket is using TCP/IP but its own communication protocol over TCP/IP. The Java Socket Package is purely TCP/IP. Re-write your server with JWebSocket, all details about JWebSocket can be found at:
http://jwebsocket.org/.
I hope my answer will help you.
you must specify end of return packet with "\r\n\r\n"
ret = "HTTP/1.1 101 Switching Protocols\r\n";
ret+="Upgrade: websocket\r\n";
ret+="Connection: Upgrade\r\n";
ret+="Sec-WebSocket-Accept: "+returnBase + "\r\n\r\n";
and for create accept key i use
public class WSKeyGenerator {
private final static String MAGIC_KEY =
"258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
public static String getKey(String strWebSocketKey) throws
NoSuchAlgorithmException {
strWebSocketKey += MAGIC_KEY;
MessageDigest shaMD = MessageDigest.getInstance("SHA-1");
shaMD.reset();
shaMD.update(strWebSocketKey.getBytes());
byte messageDigest[] = shaMD.digest();
BASE64Encoder b64 = new BASE64Encoder();
return b64.encode(messageDigest);
}
}
I recommend that use the http://websocket.org/echo.html to check the server's websocket functionality
I made a very simple port scanner, but it runs too slow, so I'm looking for a way to make it scan faster. Here is my code:
public boolean portIsOpen(String ip, int port, int timeout) {
try {
Socket socket = new Socket();
socket.connect(new InetSocketAddress(ip, port), timeout);
socket.close();
return true;
} catch (Exception ex) {
return false;
}
}
This code tests if a specific port is open on a specific ip. For timeout I used a minimum value of 200 because when I go lower it doesn't have enough time to test the port.
It works well, but takes too much to scan from 0 to 65535. Is there any other way that could maybe scan from 0 to 65535 in less than 5 minutes?
If you need 200ms for each of the 65536 ports (in the worst case, a firewall is blocking everything, thus making you hit your timeout for every single port), the maths is pretty simple: you need 13k seconds, or about 3 hours and a half.
You have 2 (non-exclusive) options to make it faster:
reduce your timeout
paralellize your code
Since the operation is I/O bound (in contrast to CPU bound -- that is, you spend time waiting for I/O, and not for some huge calculation to complete), you can use many, many threads. Try starting with 20. They would divide the 3 hours and a half among them, so the maximum expected time is about 10 minutes. Just remember that this will put pressure on the other side, ie, the scanned host will see huge network activity with "unreasonable" or "strange" patterns, making the scan extremely easy to detect.
The easiest way (ie, with minimal changes) is to use the ExecutorService and Future APIs:
public static Future<Boolean> portIsOpen(final ExecutorService es, final String ip, final int port, final int timeout) {
return es.submit(new Callable<Boolean>() {
#Override public Boolean call() {
try {
Socket socket = new Socket();
socket.connect(new InetSocketAddress(ip, port), timeout);
socket.close();
return true;
} catch (Exception ex) {
return false;
}
}
});
}
Then, you can do something like:
public static void main(final String... args) {
final ExecutorService es = Executors.newFixedThreadPool(20);
final String ip = "127.0.0.1";
final int timeout = 200;
final List<Future<Boolean>> futures = new ArrayList<>();
for (int port = 1; port <= 65535; port++) {
futures.add(portIsOpen(es, ip, port, timeout));
}
es.shutdown();
int openPorts = 0;
for (final Future<Boolean> f : futures) {
if (f.get()) {
openPorts++;
}
}
System.out.println("There are " + openPorts + " open ports on host " + ip + " (probed with a timeout of " + timeout + "ms)");
}
If you need to know which ports are open (and not just how many, as in the above example), you'd need to change the return type of the function to Future<SomethingElse>, where SomethingElse would hold the port and the result of the scan, something like:
public final class ScanResult {
private final int port;
private final boolean isOpen;
// constructor
// getters
}
Then, change Boolean to ScanResult in the first snippet, and return new ScanResult(port, true) or new ScanResult(port, false) instead of just true or false
EDIT: Actually, I just noticed: in this particular case, you don't need the ScanResult class to hold result + port, and still know which port is open. Since you add the futures to a List, which is ordered, and, later on, you process them in the same order you added them, you could have a counter that you'd increment on each iteration to know which port you are dealing with. But, hey, this is just to be complete and precise. Don't ever try doing that, it is horrible, I'm mostly ashamed that I thought about this... Using the ScanResult object is much cleaner, the code is way easier to read and maintain, and allows you to, later, for example, use a CompletionService to improve the scanner.
Apart from parallelizing the scan, you can use more advanced port scanning techniques like the ones (TCP SYN and TCP FIN scanning) explained here: http://nmap.org/nmap_doc.html. VB code of an implementation can be found here: http://h.ackack.net/spoon-worlds-fastest-port-scanner.html
In order to use these techniques, however, you need to use raw TCP/IP sockets. You should use RockSaw library for this.
Code sample is inspired by "Bruno Reis"
class PortScanner {
public static void main(final String... args) throws InterruptedException, ExecutionException {
final ExecutorService es = Executors.newFixedThreadPool(20);
final String ip = "127.0.0.1";
final int timeout = 200;
final List<Future<ScanResult>> futures = new ArrayList<>();
for (int port = 1; port <= 65535; port++) {
// for (int port = 1; port <= 80; port++) {
futures.add(portIsOpen(es, ip, port, timeout));
}
es.awaitTermination(200L, TimeUnit.MILLISECONDS);
int openPorts = 0;
for (final Future<ScanResult> f : futures) {
if (f.get().isOpen()) {
openPorts++;
System.out.println(f.get().getPort());
}
}
System.out.println("There are " + openPorts + " open ports on host " + ip + " (probed with a timeout of "
+ timeout + "ms)");
}
public static Future<ScanResult> portIsOpen(final ExecutorService es, final String ip, final int port,
final int timeout) {
return es.submit(new Callable<ScanResult>() {
#Override
public ScanResult call() {
try {
Socket socket = new Socket();
socket.connect(new InetSocketAddress(ip, port), timeout);
socket.close();
return new ScanResult(port, true);
} catch (Exception ex) {
return new ScanResult(port, false);
}
}
});
}
public static class ScanResult {
private int port;
private boolean isOpen;
public ScanResult(int port, boolean isOpen) {
super();
this.port = port;
this.isOpen = isOpen;
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
public boolean isOpen() {
return isOpen;
}
public void setOpen(boolean isOpen) {
this.isOpen = isOpen;
}
}
}
I wrote my own asynchronous portscanner java service that can scan ports via TCP-SYN-Scan like Nmap does. It also support IMCP ping scans and can work with a very high throughput (depending on what the network can sustain):
https://github.com/subes/invesdwin-webproxy
Internally it uses a java binding pcap and exposes its services via JMS/AMQP. Though you can also use it directly in your application if you don't mind it having root permissions.
If you decide to use the Nmap option and want to continue with Java, you should look at Nmap4j on SourceForge.net.
It's a simple API that allows you to integrate Nmap into a java app.
Nay, fastest way here is to use the dynamically created thread method
Executors.newCachedThreadPool();
This way it uses threads until all of them are taken, then when all of them are taken and there is a new task it will open up a new thread and preform the new task on it.
Here's my code snippet (Creds due to Jack and Bruno Reis)
I also added the function to search any IP address you type in for some added functionality and ease of use.
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
class PortScanner {
public static void main(final String... args) throws InterruptedException, ExecutionException
{
final ExecutorService es = Executors.newCachedThreadPool();
System.out.print("Please input the ip address you would like to scan for open ports: ");
Scanner inputScanner = new Scanner(System.in);
final String ip = inputScanner.nextLine();
final int timeout = 200;
final List<Future<ScanResult>> futures = new ArrayList<>();
for (int port = 1; port <= 65535; port++) {
// for (int port = 1; port <= 80; port++) {
futures.add(portIsOpen(es, ip, port, timeout));
}
es.awaitTermination(200L, TimeUnit.MILLISECONDS);
int openPorts = 0;
for (final Future<ScanResult> f : futures) {
if (f.get().isOpen()) {
openPorts++;
System.out.println(f.get().getPort());
}
}
System.out.println("There are " + openPorts + " open ports on host " + ip + " (probed with a timeout of "
+ timeout + "ms)");
es.shutdown();
}
public static Future<ScanResult> portIsOpen(final ExecutorService es, final String ip, final int port,
final int timeout)
{
return es.submit(new Callable<ScanResult>() {
#Override
public ScanResult call() {
try {
Socket socket = new Socket();
socket.connect(new InetSocketAddress(ip, port), timeout);
socket.close();
return new ScanResult(port, true);
} catch (Exception ex) {
return new ScanResult(port, false);
}
}
});
}
public static class ScanResult {
private int port;
private boolean isOpen;
public ScanResult(int port, boolean isOpen) {
super();
this.port = port;
this.isOpen = isOpen;
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
public boolean isOpen() {
return isOpen;
}
public void setOpen(boolean isOpen) {
this.isOpen = isOpen;
}
}
}
I may be late to this but you can do a bulk port scan by doing the following using NIO2 single-threaded. By following NIO2 code with a single thread, I am able to scan all the hosts for a given port. Please try a reasonable timeout and make sure you have large File Discriptor for process
public static List<HostTarget> getRechabilityStatus(String...hosts,final int port, final int bulkDevicesPingTimeoutinMS) throws Exception {
List<AsynchronousSocketChannel> channels = new ArrayList<>(hosts.length);
try {
List<CompletableFuture<HostTarget>> all = new ArrayList<>(hosts.length);
List<HostTarget> allHosts = new ArrayList(hosts.length);
for (String host : hosts) {
InetSocketAddress address = new InetSocketAddress(host, port);
HostTarget target = new HostTarget();
target.setIpAddress(host);
allHosts.add(target);
AsynchronousSocketChannel client = AsynchronousSocketChannel.open();
channels.add(client);
final CompletableFuture<HostTarget> targetFuture = new CompletableFuture<>();
all.add(targetFuture);
client.connect(address, target, new CompletionHandler<Void, HostTarget>() {
#Override
public void completed(Void result, HostTarget attachment) {
attachment.setIsReachable(true);
targetFuture.complete(attachment);
}
#Override
public void failed(Throwable exc, HostTarget attachment) {
attachment.setIsReachable(false);
attachment.errrorMessage = exc.getMessage();
targetFuture.complete(attachment);
}
});
}
try {
if(bulkDevicesPingTimeoutinMS > 0) {
CompletableFuture.allOf(all.toArray(new CompletableFuture[]{})).get(bulkDevicesPingTimeoutinMS, TimeUnit.MILLISECONDS);
}else{
// wait for all future to be complete 1000 scan is taking 7 seconds.
CompletableFuture.allOf(all.toArray(new CompletableFuture[]{})).join();
}
} catch (Exception timeoutException) {
// ignore
}
return allHosts;
}finally {
for(AsynchronousSocketChannel channel : channels){
try{
channel.close();
}catch (Exception e){
if(LOGGER.isDebugEnabled()) {
LOGGER.error("Erorr while closing socket",e);
}
}
}
}
static class HostTarget {
String ipAddress;
Boolean isReachable;
public String getIpAddress() {
return ipAddress;
}
public Boolean getIsReachable() {
return isReachable;
}
public void setIpAddress(String ipAddress) {
this.ipAddress = ipAddress;
}
public void setIsReachable(Boolean isReachable) {
this.isReachable = isReachable;
}
}
Inspired by you all, but just this Code realy worked!
class PortScaner
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class PortScaner {
public static void main(String[] args) throws InterruptedException, ExecutionException {
final ExecutorService es = Executors.newFixedThreadPool(20);
final String ip = "127.0.0.1";
final int timeout = 200;
final List<Future<ScanResult>> futures = new ArrayList<>();
for (int port = 1; port <= 65535; port++)
futures.add(portIsOpen(es, ip, port, timeout));
es.shutdown();
int openPorts = 0;
for (final Future<ScanResult> f : futures)
if (f.get().isOpen()) {
openPorts++;
System.out.println(f.get());
}
System.out.println("There are " + openPorts + " open ports on host " + ip + " (probed with a timeout of " + timeout + "ms)");
}
public static Future<ScanResult> portIsOpen(final ExecutorService es, final String ip, final int port, final int timeout) {
return es.submit(
new Callable<ScanResult>() {
#Override
public ScanResult call() {
try {
Socket socket = new Socket();
socket.connect(new InetSocketAddress(ip, port), timeout);
socket.close();
return new ScanResult(port, true);
} catch (Exception ex) {
return new ScanResult(port, false);
}
}
});
}
}
class ScanResult
public final class ScanResult {
private final int port;
private final boolean isOpen;
public ScanResult(int port, boolean isOpen) {
super();
this.port = port;
this.isOpen = isOpen;
}
/**
* #return the port
*/
public int getPort() {
return port;
}
/**
* #return the isOpen
*/
public boolean isOpen() {
return isOpen;
}
#Override
public String toString() {
return "ScanResult [port=" + port + ", isOpen=" + isOpen + "]";
}
}