I have multiple threads(runnables) in my program. On of theme is handling RS232 communication.
My problem is that code inside the loop is not executed in the order that is written:
while(!serialData.dataToSend.isEmpty())
{
try {
SerialMsgToSend msgObject = serialData.dataToSend.remove();
if(msgObject.type == msgObject.HOLDING_REGISTER)
{
Thread.sleep(COMMAND_WAIT_TIME);
Toolkit.getDefaultToolkit().beep();
modBusManager.singleRegisterWriteToMultipleRegisters(msgObject.unit, msgObject.startRegisterAdress, msgObject.data);
}
else if(msgObject.type == msgObject.COIL)
{
Thread.sleep(COMMAND_WAIT_TIME);
Toolkit.getDefaultToolkit().beep();
modBusManager.writeToCoil(msgObject.unit, msgObject.startRegisterAdress, msgObject.data[0] == 1);
}
Thread.sleep(5000);
readUnitsData(msgObject.unit);
Thread.sleep(5000);
if(msgObject.RESPONSE > 0)
{
serialData.listeners[msgObject.unit - 1].sendResponseToServer(msgObject.RESPONSE);
}
} catch (Exception ex) {
log.error("Exception on sending data: " + ex.toString());
}
}
First I write to ModBus register with calling:
modBusManager.singleRegisterWriteToMultipleRegisters(msgObject.unit, msgObject.startRegisterAdress, msgObject.data);
After that I want to wait 5 seconds that registers are updated, then read them and send information to server.
I read the data with calling method:
readUnitsData(msgObject.unit);
And then I am using listener to tell another thread to send data to server:
serialData.listeners[msgObject.unit - 1].sendResponseToServer(msgObject.RESPONSE);
My problem is that data is sent to server before it gets read/updated so I send old data. I am used that code is executed in the order that is written. Am I using threads in a wrong way or what could be the problem?
Here is method which I call to read data:
private void readUnitsData(int unitID)
{
if(mtxData.climatList[unitID] != null)
{
try
{
log.info("Serial reading data for: " + unitID);
int[] coils = modBusManager.readCoils(unitID + 1,0,87);
String[] holding = modBusManager.readHoldingRegisters(unitID + 1,0,64); //(int slaveAdress, int registerAdress, int registerQuntaity)
if(coils != null && holding != null)
{
System.out.println("send to listner: " + unitID);
serialData.listeners[unitID].newHoldingAndCoilData(holding, coils);
}
} catch (Exception ex)
{
log.error("Exception on run: " + ex.toString());
}
}
}
And method inside other runnable, which is connected to listener:
#Override
public void sendResponseToServer(int responseType)
{
try
{
log.info("listener for sendStatusToServer called: " + responseType);
Thread.sleep(15000);
switch(responseType)
{
case 1:
communicationManager.sendStatus();
break;
case 2:
communicationManager.sendSettings();
break;
}
}catch(Exception ex)
{
log.error("Exception on sendResponseToServer: " + ex);
}
}
I did like #Markus Mitterauer proposed and took apart the code. I found that that it was problem with one of the unitID's which was wrong. Because of that I didn't get any values when reading registers and listener wasn't triggered correctly.
Related
hope everyone is fine with this pandemic.
I receive a sms from a SMSC, and i would like to send him a deliver_sm_resp.
I try to implement it like that :
#Override
public PduResponse firePduRequestReceived(PduRequest pduRequest) {
logger.warn("***** BIND RECEIVER *****");
DeliverSm sms = null;
if ((pduRequest != null) && pduRequest.getName().equals("deliver_sm")) {
sms = (DeliverSm) pduRequest;
}
if ((pduRequest != null) && pduRequest.getName().equals("enquire_link")) {
return pduRequest.createResponse();
}
if ( sms !=null && (int)sms.getDataCoding() == 0 ) {
//message content is English
logger.warn("***** New Message Received *****");
logger.warn("From: " + sms.getSourceAddress().getAddress());
logger.warn("To: " + sms.getDestAddress().getAddress());
logger.warn("Content: " + new String(sms.getShortMessage()));
DeliverSm deliver = new DeliverSm();
deliver.setSourceAddress(sms.getSourceAddress());
deliver.setDestAddress(sms.getDestAddress());
deliver.setDataCoding(sms.getDataCoding());
try {
deliver.setShortMessage(sms.getShortMessage());
} catch (SmppInvalidArgumentException e) {
e.printStackTrace();
}
deliver.setSequenceNumber(sms.getSequenceNumber());
//deliver.setCommandLength(sms.getCommandLength());
deliver.setCommandStatus(sms.getCommandStatus());
runDeliverSmRespSmppSessionHandler(session, deliver);
}
return super.firePduRequestReceived(pduRequest);
}
i call runDeliverSmRespSmppSessionHandler asynchrously, like that :
public class RunDeliverSmRespSmppSessionHandler extends DefaultSmppSessionHandler implements Runnable {
.
.
.
public void run() {
logger.info("welcome to deliver TestSmppSessionHandler RUN");
sendRequestPdu(session, deliver);
}
private void sendRequestPdu(SmppSession session, DeliverSm deliver) {
logger.info("welcome to deliver TestSmppSessionHandler sendRequestPdu");
try {
WindowFuture<Integer,PduRequest,PduResponse> future = session.sendRequestPdu(deliver, 10000, false);
if (!future.await()) {
logger.error("Failed to receive deliver_sm_resp within specified time");
} else if (future.isSuccess()) {
DeliverSmResp deliverSmResp = (DeliverSmResp)future.getResponse();
logger.info("deliver_sm_resp: commandStatus [" + deliverSmResp.getCommandStatus() + "=" + deliverSmResp.getResultMessage() + "]");
} else {
logger.error("Failed to properly receive deliver_sm_resp: " + future.getCause());
}
} catch (Exception e) {
logger.error("message catched in smDeliver : "+e.getMessage()+" get stackTrace : "+e.getStackTrace());
}
}
Unfortunally, i had this error in sendRequestPdu():
04-04-2020 23:15:41 ERROR TestSmppSessionHandler:61 - Failed to receive deliver_sm_resp within specified time
04-04-2020 23:16:06 WARN EnquireLinkTask:37 - Enquire link failed, executing reconnect:
com.cloudhopper.smpp.type.SmppTimeoutException: Unable to accept offer within [10000 ms] (window full)
at com.cloudhopper.smpp.impl.DefaultSmppSession.sendRequestPdu(DefaultSmppSession.java:508)
at com.cloudhopper.smpp.impl.DefaultSmppSession.sendRequestAndGetResponse(DefaultSmppSession.java:464)
Thank you for your helping
to send a response to inform the SMSC than you received your SMS, you have to use
private void sendResponsePdu(SmppSession session, DeliverSmResp deliver) {
logger.info("welcome to deliver TestSmppSessionHandlerV2 sendRequestPdu");
try {
session.sendResponsePdu(deliver);
logger.info("message deliver response sent successfully !!!");
} catch (Exception e) {
logger.error("message catched in smDeliver : "+e.getMessage()+" get stackTrace : "+e.getStackTrace());
}
About DeliverSmResp deliver, you can initialize like that :
DeliverSmResp deliver_sm_resp = new DeliverSmResp();
deliver_sm_resp.setCommandLength(17);
deliver_sm_resp.setCommandStatus(sms.getCommandStatus());
deliver_sm_resp.setSequenceNumber(sms.getSequenceNumber());
deliver_sm_resp.setMessageId("");
I made a ReadMessage thread that should run in the background and read messages when they come in. This is how it looks:
Thread ReadMessages = new Thread(new Runnable() {
public void run() {
try {
while(socket.isConnected()){
ServerMsg = in.readLine();
jTextArea1.append(ServerMsg);
}
} catch (IOException ex) {
System.out.println("Something went wrong! THREAD");
}
}
});
I start it everytime i start my program:
public TwitchBotFenster() throws IOException, Exception {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
initComponents();
ReadMessages.start();
}
The problem I have, is that it only reads the first messages when I connect to twitch irc but if I write something in the chat it doesnt. I dont really get the problem. My thoughts when I made that were, whenever the socket is connected it should read all the messages.
EDIT:
This is how i send messages to the server:
public void SendMessage() throws IOException{
try{
if(BotName == null){
this.jTextArea1.append("You are not logged in!\n");
}else{
this.ClientChatMessage = this.jTextField4.getText();
out.write(":" + BotName + "!" + BotName + "#" + BotName + ".tmi.twitch.tv PRIVMSG #" + this.Channelname + " :" + this.ClientChatMessage + "\n");
out.flush();
this.jTextField4.setText("");
this.jTextArea1.append("*" + BotName + ">> " + ClientChatMessage + "\n");
}
this.jTextField4.setText("");
}catch(Exception exe){
System.out.println("Something went horribly wrong! (SendMessage/func)\n");
}
}
EDIT2:
Messages are sent whenever i press enter in my jTextField:
private void jTextField4ActionPerformed(java.awt.event.ActionEvent evt) {
try {
SendMessage();
} catch (IOException ex) {
System.out.println("Something went horribly wrong! (SendMessage)\n");
}
}
From time to time I come across a class where a bigger part of code are logging calls.
e.g.
public init(Config config) {
logger.info("Configuring ...");
if (config.hasInitInterval()) {
initInterval = config.getInitInterval();
logger.info("Set initInterval to " + initInterval);
}
...
try {
logger.info("Updating access points " + config.getAccessPoints());
updateAccessPoints(config.getAccessPoints())
} catch (Throwable e) {
logger.warn("Init failed due to ", e);
}
...
if (logger.isDebugEnabled ()) {
for(int i = 0; i < config.getModifiers().size(); i++) {
try {
isValidModifier(config.getModifiers().get(i));
} catch (Exception e) {
throw new IllegalArgumentException ("Wrong modifier: " config.getModifiers().get(i));
}
}
}
}
When a class is not formatted well plus contains comments, it's hard to read the code.
I used proxy pattern to partially improve it but it's suitable only to log something before or after a call of method.
What are the best practices to separate functionality from logging?
I'm just getting started with RMI and I'm trying to write a simple program that simulates a train booking system. I have the basics set up - Server, Client, and a Remote object exported. It works fine with one Client connection. However when more than 1 Client connects, the Clients seem to be executing in the same thread. This is the case when I run multiple Clients on the same machine or when I connect a Client from another laptop.
I was under the impression that RMI handled threading on the server side? If not, how do I go about handling multiple Client connections given the code below?
Here are the classes of interest.
Server.....
public class Server {
public Server() {
try {
Booking stub = (Booking) UnicastRemoteObject.exportObject(new BookingProcess(), 0);
Registry registry = LocateRegistry.getRegistry();
registry.bind("Booking", stub);
System.err.println("Server Ready");
} catch (RemoteException e) {
System.err.println("Server exception: " + e.toString());
e.printStackTrace();
} catch (AlreadyBoundException e) {
System.err.println("Server exception: " + e.toString());
e.printStackTrace();
}
}
public static void main(String[] args) {
Server server = new Server();
}
}
BookingProcess.....(I've left out the private methods that processInput(String input) uses)
public class BookingProcess implements Booking {
private static Journey dublinGalway = new Journey("Dublin to Galway");
private static Journey dublinLimerick = new Journey("Dublin to Limerick");
private static Journey dublinCork = new Journey("Dublin to Cork");
private Journey currentJourney;
private enum State {
INITIAL, JOURNEYS_DISPLAYED, JOURNEY_CHOSEN, ANOTHER_BOOKING_OFFERED, SOLD_OUT;
}
private State currentState = State.INITIAL;
public synchronized String processInput(String input) {
String output = "";
if(currentState == State.INITIAL) {
if(bookedOut()) {
output = "Sorry, there are no seats remaining on any route. Get the bus.";
currentState = State.SOLD_OUT;
}
else {
output = "Please choose a journey to book: " + "1: " + dublinGalway.getDescription() + ", 2: " + dublinLimerick.getDescription() + ", 3: " + dublinCork.getDescription();
currentState = State.JOURNEYS_DISPLAYED;
}
}
else if(currentState == State.JOURNEYS_DISPLAYED) {
output = this.processJourneyChoice(input);
}
else if(currentState == State.JOURNEY_CHOSEN) {
output = "Do you wish to confirm this booking? (y/n)";
if(input.equalsIgnoreCase("y")) {
if(bookingConfirmed()) {
output = "Thank you. Your journey from " + currentJourney.getDescription() + " is confirmed. Hit return to continue.";
//currentState = State.ANOTHER_BOOKING_OFFERED;
}
else {
output = "Sorry, but the last seat on the " + currentJourney.getDescription() + " route has just been booked by another user.";
//currentState = State.ANOTHER_BOOKING_OFFERED;
}
currentState = State.ANOTHER_BOOKING_OFFERED;
}
else if(input.equalsIgnoreCase("n")) {
output = "You have cancelled this booking. Hit return to continue.";
currentState = State.ANOTHER_BOOKING_OFFERED;
}
}
else if(currentState == State.ANOTHER_BOOKING_OFFERED) {
output = "Would you like to make another booking? (y/n)";
if(input.equalsIgnoreCase("y")) {
output = "Hit Return to continue.";
currentState = State.INITIAL;
}
else if(input.equalsIgnoreCase("n")){
output = "Goodbye.";
try {
Thread.currentThread().join(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
currentState = State.INITIAL;
}
}
else if(currentState == State.SOLD_OUT) {
output = "Goodbye.";
}
return output;
}
And finally Client......
public class Client {
public static void main(String[] args) {
Client client = new Client();
client.runClient();
}
public void runClient() {
try {
BufferedReader consoleInput = new BufferedReader(new InputStreamReader(System.in));
Registry registry = LocateRegistry.getRegistry("localhost");
Booking stub = (Booking) registry.lookup("Booking");
String serverResponse = stub.processInput("begin");
System.out.println("Server: " + serverResponse);
while((serverResponse = stub.processInput(consoleInput.readLine())) != null) {
System.out.println(serverResponse);
if(serverResponse.equals("Goodbye.")) {
break;
}
}
} catch (Exception e) {
System.err.println("Client exception " + e.toString());
e.printStackTrace();
}
}
}
As for as RMI server threads, the answer is that it may or may not run in a separate thread. See the documentation here:
http://docs.oracle.com/javase/6/docs/platform/rmi/spec/rmi-arch3.html
3.2 Thread Usage in Remote Method Invocations
A method dispatched by the RMI runtime to a remote object implementation may or may not execute in a separate thread. The RMI runtime makes no guarantees with respect to mapping remote object invocations to threads. Since remote method invocation on the same remote object may execute concurrently, a remote object implementation needs to make sure its implementation is thread-safe.
You can take server side thread dumps and you would see that the RMI TCP Connection threads IDs keep changing, however as #jtahlborn noticed the server side method is synchronized so it would execute serially, not necessarily in a single thread though.
Your server side processInput() method is synchronized, so, yes, the calls will be handled serially. what does that have to do with RMI?
UPDATE:
if you want to have separate currentState and currentJourney values for each client session, then you need to use the RMI remote session pattern, see this answer for details.
I want to read and write(randomly from server to client) on same server socket (java application). My client to server write and read work fine in a loop. At server with response write properly.
But if i am trying to write at server randomly some command. i do not have solution, first of all my question is :
is it possible at server side to write command to client ramdonly on same socket?
if possible, any suggestion or pointer how to do it?
please give me some pointer where I can read the material about this scenario ?
thanks in advance.
public class ContentServerSocket extends ServerSocket {
private final static int PORT = 4444;
protected static boolean XYZGONE = false;
public static Content content;
public ContentServerSocket(xyzService service) throws IOException {
super(PORT);
while (true) {
Log.d(TAG, "Waiting for new request from client(content) ....");
new HandleRequest(accept(), service).start();
}
}
public static void xyzRunAway() {
Log.d(TAG," Content Serv er 1 ");
XYZGONE = true;
}
}
class HandleRequest extends Thread {
private final static String TAG = "ContentServerSocket:Thread for a request:";
private Socket client;
private xyzService service;
private static Context context;
HandleRequest(Socket client, SuggestionService service) {
this.client = client;
this.service = service;
context = xyzService.serviceContext();
}
public void run() {
while (true) {
try {
Log.d(TAG, " Step 1: client: Received request MSG for Check... ");
PrintWriter out = new PrintWriter(client.getOutputStream(),
true);
BufferedReader in = new BufferedReader(new InputStreamReader(
client.getInputStream(), "utf-8"));
String request = "";
String tmpLine = null;
Log.d(TAG, " Step Xyz waiting data from the client ... ");
while ((tmpLine = in.readLine()) != null) {
if (tmpLine.length() > 0) {
request += tmpLine;
//if (tmpLine.toLowerCase().contains("</contentInfo>")) {
if (tmpLine.contains("</contentInfo>")) {
Log.d(TAG, " Server : broke because of </contentInfo>");
break;
}
} else {
Log.d(TAG, " Step NULL : ");
request = "";
}
}
Log.d("Robin", " Step 2: Actual request received from the client : : " + request);
if (request.length() == 0) {
Log.d("Robin",
" client got 0 length request, thread stop!");
throw new Exception();
}
//XMLParser xmlParser = new XMLParser(new ByteArrayInputStream(
// request.getBytes("UTF-8")));
Log.d(TAG, " Step 3 : ");
RequestParser readxmlrequest = new RequestParser(request);
String requestType = readxmlrequest.parsingXmlRequestFromContent();
Log.d(TAG, " Step 4 requestType : " + requestType);
//TODO : need to get the result and pas to the out.println..
//String result = processXML(xmlParser);
String result = responseToContentRequest(readxmlrequest,requestType);//null; //TODO need to complete.
Log.d(TAG, " Step 5 result : "+result);
(((((((((())))))))))";
if (result != null && result.length() > 0) {
//oos.writeObject(result);
Log.d("Robin", " Writing response to socket ... ");
out.println(result + "\n");
out.flush();
Log.d("Robin", " Writing flush completed ");
}
if(ContentServerSocket.XYZGONE) {
Log.d(TAG," XYZGONE >>>>>>>> ");
ContentServerSocket.XYZGONE = false;
String tmp = "<ssr> OK Done .......</ssr>";
out.println(tmp + "\n");
Log.d("Content Server Socket ", "xyz:" + tmp);
out.flush();
}
} catch (IOException ioException) {
Log.d("Robin", " IOException on socket listen: " + ioException);
}
catch (Exception e) {
Log.d("Robin", " outer exception: " + e.toString());
break;
}
finally {
if (client == null || client.isClosed()
|| !client.isConnected()) {
Log.d(" Robin ", " client is null");
break;
}
}
//break;
}
Log.d("Robin", " thread stop... ");
}
So , I fixed it . I just need to maintain two different thread.
1) read.
2)write.
In the above code i just started one more thread for write .
insert the code in Run function of above code.
====================================================
Runnable r1 = new Runnable() {
public void run() {
try {
while (true) {
System.out.println("Hello, world!");
if(ContentServerSocket.XYZGONE) {
Log.d(TAG," XYZGONEY >>>>>>>> ");
ContentServerSocket.XYZGONE = false;
String tmp = "<ssr> OK Done .......</ssr>";
out.println(tmp + "\n");
Log.d("Content Server Socket ", "XYZGONE :" + tmp);
out.flush();
}
Thread.sleep(1000L);
}
} catch (InterruptedException iex) {}
}
};
Thread thr1 = new Thread(r1);
==================================
Then Start the thread in the wile loop of read.
with the following code with a check.
====================================
if(!thr1.isAlive())thr1.start();
Thanks everyone, who respond my question..
Yes it is possible to write data from multiple threads on a server or on a client to an existing socket. However you have to make sure the requests do not overlap, and the receiving side actually knows what is written from who.
If you use a line based protocol you can define each message is a single line. In that case you should synchronize multiple threads in a way that only one is writing parts of that line at any given moment.
Your code is a bit too big to understand where your problem is, sorry.
Maybe this tutorial helps? There are quite many out there:
http://www.javaworld.com/javaworld/jw-12-1996/jw-12-sockets.html