While loop not continuing - socket - java

Okay, so I'm creating a rather simple java application, which will eventually turn into an online 2-player texas hold'em game. Right now, I'm trying to send some simple messages over network to make sure the basic functionality is working. I am however stuck.
I've got two methods in a class. One for the serverside (or really a hybrid between a client and a server), and one for the clientside. They connect together fine. As I made this, I noticed that when I connected, they both spammed their default messages (right now being "CLIENT: Started" and "SERVER: Started" back and forth to eachother. I figured this was because the string containing that information was never emptied, and so they never knew when to stop transmitting it. I then made sure that after sending the message, that variable was nulled, and a check was made to see if it was null before sending.
Here's where it went wrong though! After doing that, they won't send more than one message at all. They send their respective welcome messages, but anything I try to transmit after that is ignored. It's almost like if the while-loop for the server/client stops.
So, I have two public variable declared in the class. These contain any message the server or client wishes to send.
public static String serverCommand = null;
public static String clientCommand = null;
They are null by default, but changed during runtime in the GUI-part.
The server loop looks like this:
while(true)
{
if((receive = receiveStream.readLine()) != null)
{
System.out.println(receive);
}
if(serverCommand != null)
{
printer.println(serverCommand);
printer.flush();
Network.serverCommand = null;
}
}
And the client while loop like this:
while(true)
{
if(Network.clientCommand != null)
{
printer.println(clientCommand);
printer.flush();
Network.clientCommand = null;
}
if((receive = receiveStream.readLine()) != null)
{
System.out.println(receive);
}
}
However, as mentioned - after Network.clientCommand is set to null the first time around, it never again sends any messages, even though Network.clientCommand changes due to user input during runtime.
I'll post two links to the complete sourcecode of the client/server-part of this below, as they're a bit too big to paste here.
LINK: http://hastebin.com/oqotirufic.java
Does anyone here have any idea what's happening, and how should I think when trying to fix/get around it? I'll add that my experience with both Java and network programming is very limited.
EDIT
I'll add the part of the GUI which acccesses/changes the variables.
http://hastebin.com/upadayuwug.java

Of course after Network.clientCommand is null, nothing more is sent — that's what you told it to do:
if((receive = receiveStream.readLine()) != null)
{
System.out.println(receive);
}
According to the JavaDoc, readLine() returns
A String containing the contents of the line, not including any line-termination characters, or null if the end of the stream has been reached
Not "null if there's a pause in transmission". If it hasn't yet seen a full line, or the end of the stream (socket disconnection), well, then it's not done yet. It waits until it gets the full line of input before it goes to the next line of your code.
But how do you know if you should wait for a message to come in, or send out the next one? You can't. You can't depend on when or if anything will arrive from the other side.
What happens when both sides have nothing to send? They both start waiting to receive. What happens when one side gets something new to send? Well, once it receives something, it'll send it. But that never happens!
What you can do, is call readLine() in a separate thread. See the JavaDocs for Thread and the Java Tutorial Lesson "Concurrency". And if you're using Swing for your GUI, also see the Java Tutorial Lesson "Concurrency in Swing".

Related

Issue with readLine() method

I am building a Chat system, where I need wait to get the User input (Sender) as well as to display the reply message (from receiver) at the same time.
So I am using a while loop for receiving and sending the messages:
while((text = inFromUser.readLine()) != null) //Msg from Sender
{
while((data_from_server=inFromServer.readLine()) != null) //Msg from receiver
{
System.out.println("Displaying Output=" + data_from_server);
System.out.println(data_from_server);
}
System.out.println("Getting Input=" + text);
outToserver.writeBytes(text + "\n");
}
My Problem is the client may send inputs again and again ,whereas the receiver may/may not send the reply back. But according to my logic, it's always expecting a input from the receiver and Vice Versa. Please suggest to fix this problem.
You're going to need more than one thread. Think about it - you have to wait until the user enters some data, and when that happens, display it immediately. You also have to wait until the server gives you some data, and display that immediately.
You can't wait for both at once; if you did, nothing would be displayed until both the user and the server had entered a line. You can't wait for one, then the other; if you did, the client couldn't read what they wrote until the server sent a message, or vice versa.
You need to wait for both at the same time, but running side-by-side. You want to perform an action as soon as either of them return something. This means you need to run a second thread. One thread waits for the user, and one thread waits for the server.

Java - Client recieving blank messages from Server, but only over network

I was unsure whether this issue is to do with the network, but I'm trying to get a simple server to send messages to multiple clients. It works fine when testing on my own computer, but over the network to a different computer has issues.
The client connects to the server fine, the first message sent to the client SHOULD be 'Server : Hello, World!', but a blank string comes through. Then the second string is always read as it should be, and all the rest usually come out as blank strings. The server sends info via a PrintStream, using autoflush.
Below is the part of the Client program which reads input. I believe if anything, there is an issue here, but I'm not sure what since I'm a little new to sockets and networking things. The server sends a line of text each 500 milliseconds, counting up to each client. I've tried changing this number to something higher but the client still doesn't receive the correct messages. The client should receive the messages and print them to the screen, replying with the replies seen below at 5,10,15 and 20.
try {
socket.setSoTimeout(10);
String line;
while((line = input.readLine())!=null){
if (!line.equals("")){
// Replies
if (output != null) {
if (line.endsWith(" 20")){
output.println("Reached 20!");
}else if (line.endsWith(" 15")){
output.println("Reached 15!");
}else if (line.endsWith(" 10")){
output.println("Reached 10!");
}else if (line.endsWith(" 5")){
output.println("Reached 5!");
}
}
messages.add(line);
if (messages.size() >= 8){
messages.remove(0);
}
}else{
messages.add("EMPTY STRING!!");
if (messages.size() >= 8){
messages.remove(0);
}
}
}
} catch (SocketTimeoutException e){
// Timed out
} catch (Exception e) {
System.err.println("Connection lost");
break;
}
(Quick Edit: Should probably mention this is in a while loop inside the run method since I implemented Runnable on my class.)
When using input.readLine(), should I be checking something before to make sure it doesn't come out as just empty strings? Is it because of the timeout I have put on it?
Thanks in advance, and I should also mention I'm new to stackoverflow, If I'm doing anything wrong please say! :)
Okay, Well. Turns out it was to do with the timeout being too small. I put it up to a whole second and now it prints out fine. Thanks anyway people :)

A reliable way to read socket data

The application that I am working on has two parts. The server part runs on a Linux machine. The client part, an Android application, queries the server and gets necessary response. Both the parts are written in Java, use socket-based communication, and transfer textual data.
Right after sending the request, here is how the client receives the response:
public static String ReadAvailableTextFromSocket(BufferedReader input) throws IOException {
if (input.ready() == false) {
return null;
}
StringBuilder retVal = new StringBuilder();
while(input.ready()) {
char ch = (char) input.read();
retVal.append(ch);
}
return retVal.toString();
}
However, this doesn't seem to be that reliable. The input is not always ready because of server response time or transmission delays.
Looks like input.ready() is not the right way to wait for getting data.
I am wondering if there is a better way to accomplish this. Perhaps there is some standard practice that I could use.
Perhaps you should use Threads. Keep a listener thread in a while(true) loop that reads more data as it comes in, and simply buffers the data in a data structure (let's say a queue) shared with the main thread. That way, the main thread could simply dequeue data as needed. If the queue is empty, it can infer that no new data was received.
Edit: see this multithreaded chat server/client code as an example.
Here is how I solved this problem. As I am responsible for writing both, the client side as well as the server side, when a request comes to the server, the first line of information I send as the response is the number of bytes the client can expect. This way, the client first waits to read a line. Once the line is read, the client now knows how many bytes of data to expect from the server.
Hope this helps others.
Regards,Peter

How JMS work in Java?

How does async JMS work? I've below sample code:
public class JmsAdapter implements MessageListener, ExceptionListener
{
private ConnectionFactory connFactory = null;
private Connection conn = null;
private Session session = null;
public void receiveMessages()
{
try
{
this.session = this.conn.createSession(true, Session.SESSION_TRANSACTED);
this.conn.setExceptionListener(this);
Destination destination = this.session.createQueue("SOME_QUEUE_NAME");
this.consumer = this.session.createConsumer(destination);
this.consumer.setMessageListener(this);
this.conn.start();
}
catch (JMSException e)
{
//Handle JMS Exceptions Here
}
}
#Override
public void onMessage(Message message)
{
try
{
//Do Message Processing Here
//Message sucessfully processed... Go ahead and commit the transaction.
this.session.commit();
}
catch(SomeApplicationException e)
{
//Message processing failed.
//Do whatever you need to do here for the exception.
//NOTE: You may need to check the redelivery count of this message first
//and just commit it after it fails a predefined number of times (Make sure you
//store it somewhere if you don't want to lose it). This way you're process isn't
//handling the same failed message over and over again.
this.session.rollback()
}
}
}
But I'm new to Java & JMS. I'll probably consume messages in onMessage method. But I don't know how does it work exactly.
Do I need to add main method in JmsAdapter class? After adding main method, do I need to create a jar & then run the jar as "java -jar abc.jar"?
Any help is much appreciated.
UPDATE: What I want to know is that if I add main method, should I simply call receiveMessages() in main? And then after running, will the listener keep on running? And if there are messages, will it retrieve automatically in onMessage method?
Also, if the listener is continuously listening, doesn't it take CPU??? In case of threads, when we create a thread & put it in sleep, the CPU utilization is zero, how doe it work in case of listener?
Note: I've only Tomcat server & I'll not be using any jms server. I'm not sure if listener needs any specific jms server such as JBoss? But in any case, please assume that I'll not be having anything except tomcat.
Thanks!
You need to learn to walk before you start trying to run.
Read / do a tutorial on Java programming. This should explain (among other things) how to compile and run a Java program from the command line.
Read / do a tutorial on JMS.
Read the Oracle material on how to create an executable JAR file.
Figure out what it is you are trying to do ... and design your application.
Looking at what you've shown and told us:
You could add a main method to that class, but to make an executable JAR file, you've got to create your JAR file with a manifest entry that specifies the name of the class with the main method.
There's a lot more that you have to do before that code will work:
add code to (at least) log the exceptions that you are catching
add code to process the messages
add code to initialize the connection factory and connection objects
And like I said above, you probably need some kind of design ... so that you don't end up with everything in a "kitchen sink" class.
if I add main method, should I simply call receiveMessages() in main?
That is one approach. But like I said, you really need to design your application.
And then after running, will the listener keep on running?
It is not entirely clear. It should keep running as long as the main thread is alive, but it is not immediately obvious what happens when your main method returns. (It depends on whether the JMS threads are created as daemon threads, and that's not specified.)
And if there are messages, will it retrieve automatically in onMessage method?
It would appear that each message is retrieved (read from the socket) before your onMessage method is called.
Also, if the listener is continuously listening, doesn't it take CPU???
Not if it is implemented properly.
In case of threads, when we create a thread & put it in sleep, the CPU utilization is zero, how doe it work in case of listener?
At a certain level, a listener thread will make a system call that waits for data to arrive on a network socket. I don't know how it is exactly implemented, but this could be as simple as an read() call on the network socket's InoutStream. No CPU is used by a thread while it waits in a blocking system call.
This link looks like a pretty good place with examples using Oracle AQ. There's an examples section that tells you how to setup the examples and run them. Hopefully this can help.
Link to Oracle Advanced Queueing

Issues receiving in RXTX

I've been using RXTX for about a year now, without too many problems. I just started a new program to interact with a new piece of hardware, so I reused the connect() method I've used on my other projects, but I have a weird problem I've never seen before.
The Problem
The device works fine, because when I connect with HyperTerminal, I send things and receive what I expect, and Serial Port Monitor(SPM) reflects this.
However, when I run the simple HyperTerminal-clone I wrote to diagnose the problem I'm having with my main app, bytes are sent, according to SPM, but nothing is received, and my SerialPortEventListener never fires. Even when I check for available data in the main loop, reader.ready() returns false. If I ignore this check, then I get an exception, details below.
Relevant section of connect() method
// Configure and open port
port = (SerialPort) CommPortIdentifier.getPortIdentifier(name)
.open(owner,1000)
port.setSerialPortParams(baud, databits, stopbits, parity);
port.setFlowControlMode(fc_mode);
final BufferedReader br = new BufferedReader(
new InputStreamReader(
port.getInputStream(),
"US-ASCII"));
// Add listener to print received characters to screen
port.addEventListener(new SerialPortEventListener(){
public void serialEvent(SerialPortEvent ev) {
try {
System.out.println("Received: "+br.readLine());
} catch (IOException e) { e.printStackTrace(); }
}
});
port.notifyOnDataAvailable();
Exception
java.io.IOException: Underlying input stream returned zero bytes
at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:268)
at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:306)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:158)
at java.io.InputStreamReader.read(InputStreamReader.java:167)
at java.io.BufferedReader.fill(BufferedReader.java:136)
at java.io.BufferedReader.read(BufferedReader.java:157)
at <my code>
The big question (again)
I think I've eliminated all possible hardware problems, so what could be wrong with my code, or the RXTX library?
Edit: something interesting
When I open HyperTerminal after sending a bunch of commands from java that should have gotten responses, all of the responses appear immediately, as if they had been put in the buffer somewhere, but unavailable.
Edit 2: Tried something new, same results
I ran the code example found here, with the same results. No data came in, but when I switched to a new program, it came all at once.
Edit 3
The hardware is fine, and even a different computer has the same problem. I am not using any sort of USB adapter.
I've started using PortMon, too, and it's giving me some interesting results. HyperTerminal and RXTX are not using the same settings, and RXTX always polls the port, unlike HyperTerminal, but I still can't see what settings would affect this. As soon as I can isolate the configuration from the constant polling, I'll post my PortMon logs.
Edit 4
Is it possible that some sort of Windows update in the last 3 months could have caused this? It has screwed up one of my MATLAB mex-based programs once.
Edit 5
I've also noticed some things that are different between HyperTerminal, RXTX, and a separate program I found that communicates with the device (but doesn't do what I want, which is why I'm rolling my own program)
HyperTerminal - set to no flow control, but Serial Port Monitor's RTS and DTR indicators are green
Other program - not sure what settings it thinks it's using, but only SPM's RTS indicator is green
RXTX - no matter what flow control I set, only SPM's CTS and DTR indicators are on.
From Serial Port Monitor's help files (paraphrased):
the indicators display the state of the serial control lines
RTS - Request To Send
CTS - Clear To Send
DTR - Data Terminal Ready
OK, sorry it's taken me so long to come back to this question. Here's how I got things working.
Note: This method will NOT work for everyone, please read below before copy/pasting into your own code
public void connect(CommPortIdentifier portId) throws Failure {
if (portId == null)
throw new Failure("No port set");
try { port = (SerialPort) portId.open(getClass().getName(), 10000); }
catch (PortInUseException e) {
throw new Failure("Port in use by " + e.currentOwner,e); }
try {
port.setSerialPortParams(9600, SerialPort.DATABITS_8,
SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);
port.setFlowControlMode(SerialPort.FLOWCONTROL_RTSCTS_IN
| SerialPort.FLOWCONTROL_RTSCTS_OUT);
} catch (UnsupportedCommOperationException e) { throw new Failure(e); }
port.setRTS(true);
// More setup
}
So, in my case, the problem was that my particular device requires RTS flow control. Other devices may require different things (CTS, XON/XOFF), so check that device's manual. By default, RXTX disables all flow control mechanisms (unlike Hypertrm or other programs). Enabling each one is a two-step process.
Once you have a SerialPort object, call the setFlowControlMode() method, and bitwise-OR ('|') the necessary SerialPort.FLOWCONTROL_ constants
Set the appropriate flow control to true or false (like I did with port.setRTS(true))
For the others with similar problems, if this doesn't work, I suggest
Using a serial port monitoring program like Serial Port Monitor and/or PortMon (both Windows) to see what is actually going on.
Emailing the RXTX developers at rxtx#qbang.org (they are very helpful)
There is a simpler solution to this problem. This is what I did:
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String line;
while (keepRunning) {
try {
while ((br.ready()) && (line = br.readLine()) != null) {
....
}
If you check that the buffer "is ready" before you read it there should be no problem.
Ok, I do realize this thread is extremely old, but none of these solutions worked for me. I had the same problem and I tried everything to fix it, to no avail. Then I did some research on what causes the problem, and, when not dealing with Serial Communication, it happens at the end of a file. So, I figured I needed to add an ending to whatever is being received by the Java Application, specifically, a line return (\n). And sure enough, it fixed the problem for me! Hopefully this helps someone new, as I'm not expecting this to help anyone already on this thread...
(might be too simple, but might as well start somewhere...)
Is the port in use? Rather than:
port = (SerialPort) CommPortIdentifier.getPortIdentifier(name)
.open(owner,1000)
what about:
CommPortIdentifier portIdentifier;
try {
portIdentifier = CommPortIdentifier.getPortIdentifier(name);
} catch (NoSuchPortException nspe) {
// handle?
}
if (portIdentifier.isCurrentlyOwned()) {
// handle?
}
port = portIdentifier.open(owner, 1000);
if (!(port instanceof SerialPort)) {
// handle?
}
Are you swallowing any exceptions?
I tried RXTX a few months ago and ran into similar problems. I suggest two things:
Create a virtual comport using com0com. Enable trace logging. Compare the logs for when you use Hyperterminal versus when you run your own program. The difference will highlight what you are doing wrong.
In my humble opinion, RXTX's design is flawed and its implementation is quite buggy (take a look at its source-code, what a mess!). I've published an alternative library at http://kenai.com/projects/jperipheral with the following caveats: It's Windows-only and there are no pre-built binaries. Both of these will change in the near future. If you are interested in trying it out send me an email using http://desktopbeautifier.com/Main/contactus and I'll send you a pre-built version.
If anyone is still getting java.io.IOException: Underlying input stream returned zero bytes after you've read your characters using br.readline() for RXTX (even when you are checking first to see if br.readline() == null), just do this simple fix with a try/catch:
String line;
while (true){
try{
line = br.readLine();
}catch(IOException e){
System.out.println("No more characters received");
break;
}
//Print the line read
if (line.length() != 0)
System.out.println(line);
}
I've done some searching and it appears that this is the best/easiest way to get around this problem.
EDIT : I take that back. I tried this and still ended up having some problems. I'd recommend working with the raw InputStream directly, and implementing your own read/readLine method using InputStream.read(). That worked for me.

Categories

Resources