My server has few handlers
new ConnectionHandler(),
new MessageDecoder(),
new PacketHandler(),
new MessageEncoder()
It seems that last handler should be called when the server sends data to the client, but it never called.
Here is code of the handler
public class MessageEncoder extends ChannelOutboundHandlerAdapter {
#Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
System.out.println("from encoder");
NetCommand command = (NetCommand)msg;
byte[] data = JsonSerializer.getInstance().Serialize(command);
ByteBuf encoded = ctx.alloc().buffer(4+data.length);
encoded.writeInt(data.length).writeBytes(data);
ctx.writeAndFlush(encoded);
}
}
As you see i'm using POJO instead of ByteBuf, but it does not work. And even when I try to send ByteBuf the last handler is not called too.
Also here is how I send the data
#Override
public void run()
{
Packet packet;
NetCommand data;
Session session;
while ( isActive )
{
try {
session = (Session) this.sessionQueue.take();
packet = session.getWritePacketQueue().take();
data = packet.getData();
System.out.println("data code: "+data.netCode);
ChannelHandlerContext ctx = packet.getSender().getContext();
ctx.writeAndFlush(data);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
What did I do wrong?
Most likely the ChannelHandlerContext you use for writeAndFlush() belongs to a ChannelHandler which is befor your last handler in the pipeline. If you want to ensure that the write starts at the tail / end of the pipeline use ctx.channel().writeAndFlush(...)
Related
In my current code i had a servlet from which if i create post to the servlet it will open a new websocket client , that mean 10 client connection each running for same purpose but with different api and secret , so i need to close particular session
I am using Jetty :: Websocket :: Client v9.4.48.v20220622
Please suggest , as i can get the session details but unable to use because it's not working with String data type . only in Session session it is working and i am unable to store session details anywhere else , as only in String data type i can save .
Whereas a is my API and b is my Secret Key ;
PS : Websocket connection is working fine to send expected data
class connector {
String a;
String b;
public void start() {
WebSocketClient client = new WebSocketClient();
MyWebSocket socket = new MyWebSocket();
try {
client.start();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
URI destUri = null;
try {
destUri = new URI("wss://socket.delta.exchange");
} catch (URISyntaxException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
ClientUpgradeRequest request = new ClientUpgradeRequest();
System.out.println("Connecting to: " + destUri);
try {
client.connect(socket, destUri, request);
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
try {
socket.awaitClose(3600, TimeUnit.SECONDS);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
client.stop();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
#WebSocket
public class MyWebSocket {
private final CountDownLatch closeLatch = new CountDownLatch(1);
#OnWebSocketConnect
public void onConnect(Session session) throws IOException {
session.getRemoteAddress();
System.out.println("Connection opened");
PingPong newObj = new PingPong();
newObj.session = session;
Authorization authMe = new Authorization();
Identifier getSt = new Identifier();
newObj.enableHeartBeat();
System.out.println(session);
session.getRemote().sendString(authMe.data(a, b));
}
#OnWebSocketMessage
public void onMessage(String message) {
MessageHandler objmsg = new MessageHandler();
objmsg.check();
System.out.println(
"Current Thread ID: "
+ Thread.currentThread().getId());
System.out.println("Message from Server: -- " + message);
}
#OnWebSocketClose
public void onClose(int statusCode, String reason) {
System.out.println("WebSocket Closed. Code:" + statusCode);
}
public boolean awaitClose(int duration, TimeUnit unit)
throws InterruptedException {
return this.closeLatch.await(duration, unit);
}
}
}
I want to do session.close() for a particular session details which i got from
session.getRemoteAddress().toString();
Session session ;
String sessionDetailSaved ;
i want to search for sessionDetailSaved and compare with all the on running sessions and close it
Or else any other way i can close particular session with different method may be interrupting session thread but sure it will not completely close connection .
Maven Dependency i am using
<dependency>
<groupId>org.eclipse.jetty.websocket</groupId>
<artifactId>websocket-client</artifactId>
<version>9.4.48.v20220622</version>
</dependency>
Calling Session.close() will initiate a close handshake where the remote endpoint should reply with a response close frame, and once the close response has been received the WebSocket connection will be closed. You can send custom close status code and reason with Session.close(int statusCode, String reason).
You also have the option to call Session.disconnect() which will do a hard close of the underlying connection without sending this close frame.
In regards to your code, it looks like you are never completing the closeLatch in the OnWebSocketClose method, so your awaitClose method will always timeout.
Also, if possible you should try to re-use the same WebSocketClient instance for multiple connections because it is a heavy weight object. It is expensive to create a new one for each request.
Edited my question for clarification and code:
My goal is to pass my String data from my background thread, to my main application thread. Any help is appreciated.
Here is the code that creates the main background thread. This is located in my Server.java class
public class Server {
boolean isConnected = false;
Controller controller = new Controller();
public void startHost() {
Thread host = new Thread(() -> {
Controller controller = new Controller();
ServerSocket server = null;
try {
server = new ServerSocket(GeneralConstants.applicationPort);
} catch (BindException e2) {
System.out.println("Port Already in Use!");
} catch (IOException e) {
//do nothing
}
while (true) {
if (server == null) { break; }
try {
Socket client = server.accept();
System.out.println("Client Connected: " + isConnected);
if (!isConnected) {
controller.createClientHandler(client);
isConnected = true;
System.out.println("Client Connected: " + isConnected);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
host.setDaemon(true);
host.start();
}
Here is the code that is then called when a client is connected, located in my Controller.java class.
public synchronized void createClientHandler(Socket client) {
boolean alreadyConnected = false;
if (alreadyConnected) {
//do NOT assign multiple threads for each client
} else {
ClientHandler handleClients = new ClientHandler("client", client);
}
}
The program then creates two background threads for my client, one to manage receiving messages, and sending messages.
public ClientHandler(String name, Socket s) {
clientSocket = s;
clientName = name;
receiveThread = new Thread(this::receive);
sendThread = new Thread(this::send);
connected = clientSocket.isConnected();
receiveThread.start();
sendThread.start();
}
The thread then successfully creates the inputstream and passes the object to my controller. Which then process and grabs a string assigning it to a variable
public synchronized void handleReceivedPacket(String name, BufferedReader in) {
try {
data = in.readLine();
System.out.println("Successfully assigned data to: " + data);
} catch (IOException e) {
System.out.println("Unable to read result data");
}
}
How do I access my String data from the main thread without getting null?
Aka I can call (or something similar)
controller.returnData();
from my main application. From which it'll either return null (no data yet), or actually return my data. Right now, it's always null.
Edit, this is what's actually calling controller.returnData() {
I don't want to paste a massive amount of code for fear of reaching StackOverflow's code limit, so here's my application structure.
My JavaFX creates the scene, and creates a root gridpane, it then calls a method that creates sub gridpanes based the specified input. Aka, a user can press "Main Menu" that calls my method setScene() which removes the current "sub-root" gridpane and creates a "new" scene. Right now, I have a GameBoard.java class which on button press, calls controller.returnData()
PassOption.setOnAction(event -> {
System.out.println(controller.returnData());
});
There is no functional purpose for this besides testing. If I can receive the data, then I can expand on this using the data.
Start thinking about design. In network applications you typically have to manage the following responsibilites:
Connected clients and their state (connection state, heartbeats, ...)
Received messages from the clients
Messages to transmit to the clients
It makes sense to separate those responsibilities in order to keep the code clean, readable and maintainable.
Separation can mean both, thread-wise and class-wise.
For example, you could implement it as follows:
The class ClientAcceptor is responsible for opening the socket and accepting clients. As soon as a client has connected, it delegates the further work to a controller and then waits for other clients:
public class ClientAcceptor implements Runnable {
#Override
public void run() {
while (true) {
ServerSocket server;
try {
server = new ServerSocket(1992);
Socket client = server.accept();
if (client.isConnected()) {
controller.createClientHandler(client);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
The controller could then create a handler (if the controller decides to do so, e.g. it could also decline the client). The ClientHandler class could look as follows:
public class ClientHandler {
private Thread receiveThread;
private Thread sendThread;
private boolean connected;
private Socket clientSocket;
private String clientName;
private LinkedBlockingDeque<byte[]> sendQueue;
public ClientHandler(String name, Socket s) {
clientSocket = s;
clientName = name;
receiveThread = new Thread(() -> receive());
sendThread = new Thread(() -> send());
connected = clientSocket.isConnected();
receiveThread.start();
sendThread.start();
}
private void receive() {
BufferedInputStream in = null;
try {
in = new BufferedInputStream(clientSocket.getInputStream());
} catch (IOException e) {
connected = false;
}
while (connected) {
try {
byte[] bytes = in.readAllBytes();
if (bytes != null && bytes.length > 0) {
controller.handleReceivedPacket(clientName, bytes);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
private void send() {
BufferedOutputStream out = null;
try {
out = new BufferedOutputStream(clientSocket.getOutputStream());
} catch (IOException e) {
connected = false;
}
while (connected) {
byte[] toSend = sendQueue.getFirst();
if (toSend != null && toSend.length > 0) {
try {
out.write(toSend);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public void send(byte[] packet) {
sendQueue.add(packet);
}
public void close() {
connected = false;
}
}
The ClientHandler is responsible for receiving and transmitting data. If a packet arrives it informes the controller, which parses the packet. The ClientHandler also provides a public API to send data (which is stored in a queue and handled by a thread) and close the connection.
The above code examples are neither tested, nor complete. Take it as a starting point.
I have a small problem. I have trying to use a method in another class to send an object to the server I have. I am using Java with Sockets.
Method:
public void sendMessageToServer(String message) {
if (message != null) {
try {
serverComManager.outputStream.writeObject(message);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Class trying to use the method:
sendMessage.sendMessageToServer("Hello");
The error is thrown at the line:
serverComManager.outputStream.writeObject(message);
Thank you in advance!
~Rane
EDIT: As requested, I have added the 'serverComManager' declaration as well as the code for that class. I have also included the full error. I hope this helps you understand my problem.
Declaration:
ServerCommunicationManager serverComManager = new ServerCommunicationManager();
Code for ServerCommunicationManager:
boolean connected;
//Setup
Socket clientSocket;
ObjectOutputStream outputStream;
ObjectInputStream inputStream;
public boolean connectToHost() throws UnknownHostException, IOException{
clientSocket = new Socket("localhost", 2444);
setupStreams(clientSocket);
if(clientSocket.isConnected()){
connected = true;
}else{
connected = false;
}
return connected;
}
private void setupStreams(Socket s) throws IOException{
outputStream = new ObjectOutputStream(s.getOutputStream());
inputStream = new ObjectInputStream(s.getInputStream());
}
Error:
Exception java.lang.NullPointerException
at SendToServer.sendMessageToServer(SendToServer.java:16)
at DissconnectClient.dissconnectFromServer(DissconnectClient.java:15)
Error Lines:
DissconnectClient 15: sendMessage.sendMessageToServer(abortConnectionKeyword);
SendToServer 16: serverComManager.outputStream.writeObject(message);
NOTE: DisconnectClient is one of the classes I am writing with. Here is the class code:
public class DissconnectClient {
//Variables
private final String keyword = "DISSCONNECT";
//Setup
SendToServer sendMessage = new SendToServer();
public void dissconnectFromServer(){
sendMessage.sendMessageToServer(keyword);
}
}
I cannot see where do you assign a value of "serverComManager" or where do you create an isntance of this. Maybe in a constructor method ot the class which has the method "sendMessageToServer" you're doing something like this.serverComManager = (...). I'm not sure how you are handle the logic of "serverComManager" but so far, my approach to solve the issue would be the following (if I'm writing a client that sends a message to the server). And considering there's no code provided for your "serverConnManager", maybe you could identify something missing in your current implementation.
public void sendMessageToServer(String message) {
if (message != null) {
try {
//Assume I already have an instance of client Socket:
//Socket outgoingConn = new Socket(host, port)
//1. I get the OutputStream of my outgoing connection
OutputStream outStream = outgoingConn.getOutputStream();
//2. Create an object output stream
ObjectOutputStream objectWriter = new ObjectOutputStream(outStream);
//3. Write the object
objectWriter.writeObject(message);
//Close the io if required (would recommend try-with-resources if using jdk7)
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
If you are working just with String messages, BufferedWriter orBufferedReadr would be enough, if you try to handle complex objects that can be both "beans" or Strings, better if you create something like:
public class MessageBean implements Serializable {
private MessageType type;
private Object param;
//Getters/Setters
}
MessageType could be an enum specifying the type of objects supported, since param field is an object you can handle as an String or as a bean. Then work based on the MessageType or using the "instanceof". But Well, this is just a suggestion if you want to try something further.
Hope it helps. Happy coding!
Regards.
I'm writing a application that has a connection to a measuring device.
This device can be connected by serial and networkconnection.
The serial side I'm done with and catches the data that is send by using a SerialPortEvent.
Now I'm trying to accomplish the same thing with a socket. I have the connection working, and I can send/and receive data from the device. Problem with this is that I force a Thread.sleep to wait for all data to be ready. But now I want to automatically catch the receiving data like it did with the SerialPortEvent.
This is a 2 part question:
Is there a similar Event for a socket? Or is a custom solution preferable in this situation? If so, please add explanation.
How to accomplish DATA_AVAILABLE for a socket
Below here is a snippet of the code (only the neccesary catching part) for the SerialEventPort, as a reference to what I also want to accomplish with a socket:
#Override
public void serialEvent(SerialPortEvent event)
{
if (event.getEventType() == SerialPortEvent.DATA_AVAILABLE)
{
try
{
int available = inputStream.available();
byte[] readBuffer = new byte[available];
if (available > 0)
{
inputStream.read(readBuffer);
}
}
}
In this SO answer Sorrow states the following:
I recommend using java.nio.channels.SocketChannel connected with Selector and SelectionKey. This solution is somewhat event-based, but is more complicated than just plain sockets.
If you decide for that solution you will find the code examples in the linked answer.
But, if you are talking about java.net.Socket then, no, there are no events. I like JTeagle's answer on a similar question:
This is often done by spawning a separate thread for the client that continuously makes blocking calls to read() from the stream - that way, as soon as data becomes available the read() call unblocks and can act on what it received ('the event fires'), then it goes back to blocking waiting for the next event.
And in my experience also, that's mostly how sockets are handled in Java. I wrote an implementation of event based socket. Since reading is blockable, a thread is most probably needed not to block your main program:
public class ObservableSocket extends Thread {
private final Socket socket;
private final ArrayList<ObservableSocketListener> listeners;
private volatile boolean isReading;
private int BUFFER_SIZE = 1024;
public ObservableSocket(String host, int port) throws UnknownHostException, IOException {
this.socket = new Socket(host, port);
this.listeners = new ArrayList<ObservableSocketListener>(1);
isReading = true;
this.start();
}
public void addListener(ObservableSocketListener l) {
if (!listeners.contains(l)) {
listeners.add(l);
}
}
public void removeListener(ObservableSocketListener l) {
if (!listeners.contains(l)) {
listeners.remove(l);
}
}
public void die() {
isReading = false;
try {
this.join();
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
public void write(byte[] data) throws IOException {
socket.getOutputStream().write(data);
socket.getOutputStream().flush();
}
private byte[] getData(byte[] buffer, int red) {
byte[] redData = new byte[red];
System.arraycopy(buffer, 0, redData, 0, red);
return redData;
}
#Override
public void run() {
byte[] buffer = new byte[BUFFER_SIZE];
int red;
ObservableSocketEvent event;
try {
while (isReading && (red = socket.getInputStream().read(buffer)) > -1) {
event = new ObservableSocketEvent(this, getData(buffer, red));
for (ObservableSocketListener l : listeners) {
l.dataAvailable(event);
}
}
}
catch (Exception exception) {
event = new ObservableSocketEvent(this, exception);
for (ObservableSocketListener l : listeners) {
l.errorOccured(event);
}
}
finally {
if (socket != null) {
try {
socket.close();
for (ObservableSocketListener l : listeners) {
l.closed(new ObservableSocketEvent(this));
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
}
}
This is the listener class you'll need to implement:
public interface ObservableSocketListener extends EventListener {
public void dataAvailable(ObservableSocketEvent event);
public void errorOccured(ObservableSocketEvent event);
public void closed(ObservableSocketEvent event);
}
And the event class:
public class ObservableSocketEvent extends EventObject {
private final byte[] data;
private final Exception exception;
public ObservableSocketEvent(Object source) {
super(source);
this.data = null;
this.exception = null;
}
public ObservableSocketEvent(Object source, byte[] data) {
super(source);
this.data = data;
this.exception = null;
}
public ObservableSocketEvent(Object source, Exception exception) {
super(source);
this.data = null;
this.exception = exception;
}
public byte[] getData() {
return data;
}
public Exception getException() {
return exception;
}
}
I made a server generating some random data for testing this code, this is how I used it form my client's class main method:
ObservableSocket observableSocket = new ObservableSocket("localhost", 3339);
observableSocket.addListener(new ObservableSocketListener() {
#Override
public void dataAvailable(ObservableSocketEvent event) {
System.out.println("data received: "+new String(event.getData()));
}
#Override
public void closed(ObservableSocketEvent event) {
System.out.println("closing socket");
}
#Override
public void errorOccured(ObservableSocketEvent event) {
System.out.println("error occured");
event.getException().printStackTrace();
}
});
Thread.currentThread().sleep(10000);
observableSocket.die();
And it outputs:
data received: data 0
data received: data 1
data received: data 2
data received: data 3
data received: data 4
closing socket // thread is alive here
BUILD SUCCESSFUL (total time: 10 seconds) // thread dies here
In terms of my test, the sleep in client is needed because the die method:
exits the reading loop (via a flag set to false)
and waits for the thread to die (Thread.join)
Without the sleep, the test client finishes immediatley (the die method works). Without the die method, the ObservableSocket thread lives after the test is over.
When using this code you should be aware of two things:
upon instantiating the ObservableSocket the Socket is immiediatly connected and a Thread is started.
you must call the die method from a thread which is not the ObservableSocket thread (e.g. don't call that method from within that class)
I have the following code structure.
A transaction handler of type Transaction which is a field in a Client Handler class, which talks to a Server. (the client handler and the server are collocated), the client talks to the client handler via serialized object messages.
When a new transaction request comes in from the client, (comes on thread using the readObject() method of an object input stream), I then do a series of trx_handler.setFoo(trx.getFoo))). This works fine, I can handle the first request. But when a subsequent request comes in (which only starts getting executed after the first request finished due to the loop structure, I find that the trx handler has been reinitialised to its default values, the object is still there, but all the values inside are the defaut ones. What can cause this problem?
My first guess would be garbage collection, but in my Client Handler class, there is always a pointer to this trx_handler.
The code below illustrates what happens. A statement would first be of type start, so the trx_handler will be correctly initialised. handle_statement will then be called. Subsequent statements should then be received, but at this point the trx_handler has been reinitialised to its default settings, so the access_set field is null, the session id as well, and none of the modification made to the object in hande_statement are visible
Thanks
public class Handler {
private Statement trx_handler;
/* Constructor initialises trx_handler to new Statement(); */
public ClientHandler(final Socket socket, long uid, Server server, ObjectInputStream ois) throws IOException, Exception {
LOGGER.info("Constructing Handler");
this.uid = uid;
this.server = server;
this.socket = socket;
this.database = server.getDB();
this.trx_sys = database.getTransactionManager();
create_listening(socket, ois);
out = socket.getOutputStream();
oos = new ObjectOutputStream(out);
this.trx_handler = new Statement(false);
}
private void create_incoming(final Socket socket, final ObjectInputStream stream) {
Thread incoming = new Thread() {
#Override
public void run() {
ObjectInputStream ois = stream;
InputStream in = null;
while (true) {
Object statement = null;
try {
statement = ois.readObject();
execute_stat(statement, socket, null);
LOGGER.info("Ready to execute next ");
} catch (SocketException e) {
LOGGER.severe("Connection Closed");
return;
} catch (IOException e) {
LOGGER.severe("Connection Closed");
return;
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
String error_message = e.getMessage();
send_error(socket, error_message);
}
}
}
};
incoming.setDaemon(true);
incoming.start();
}
private synchronized void execute_stat(Statement trx) {
if (trx.getTransactionState() == Consts.trx_end) {
trx_sys.commitTransaction(trx_handler);
return;
} else if (trx.getTransactionState() == Consts.trx_start) {
try {
trx_handler.setAccessSet(trx.getAccessSet());
trx_handler.setSession_id(trx.getSession_id());
trx_sys.startTransaction(trx_handler);
handle_statement(socket, trx_handler);
/* TEST HERE THAT FIELDS IN TRX_HANDLER ARE CORRECTLY SET (INCLUDING SOME MODIFIED IN
handle_statement and they are correctly set */
return;
} catch (Exception ex) {
Logger.getLogger(ClientHandler.class.getName()).log(Level.SEVERE, null, ex);
}
}
try {
LOGGER.info("Execute Trx: stat");
/* Can't see modifications made in the start case */
Statement stats = trx.getStatement();
trx_handler.setStatement(stats);
handle_statement(stats, socket, trx_handler);
} catch (Exception e) {
e.printStackTrace();
}
return;
}
You need to either send a brand new object for each transaction, use ObjectOutputStream.writeUnshared(), or else call ObjectOutputStream.reset() between sends.