How to stop a method until I get the response in java? - java

I have written a simple TCP Server program that receives data from the client. My main() method looks like this:
Acceptor acceptor = Acceptor.open(new InetSocketAddress(port));
Session session = acceptor.accept(); //accepts connection from client and returns session object
FIXSession transport = session.getTransport();
String str = transport.receive(); // receives data from client
doWork(str); // do the remaining process.
In the above code, I am trying to receive the data from client using "transport.receive()" method. If suppose client takes some time to send the data, meanwhile my main program is going to the next step "doWork(str);" and the result is null. How can I make the main() thread to wait until I receive data from the Client. In future I may run the doWork(str) method in other thread. So I need to make the doWork(str) thread to wait until I get the data from the Client. Is there any way to do?

Quoting the OP:
Even though it returns the number of bytes, if the bytes received less than 0 then it has to wait until the received bytes are greater than 0
So, the straight forward way to turn this into a blocking call:
int numBytes = transport.receive();
while (numBytes == 0) {
Thread.sleep(SOME_TIME);
numBytes = transport.receive();
}
for example. If you want code to wait; then write code that waits. But of course, that still doesn't answer how to actually receive a message. As the idea is that you need a MessageListener to actually receive messages.

Related

Slow tcp connection causes my app to stall

I have found a class that handles TCP connections and I am using it to communicate with a gaming service. All was working fine until I realized that my application was stalling if the connection speed was slower. I have a thread polling let's say every 30 seconds.
I got the TCPClient class I use from this thread Java TCP sending first message, then infinite wait
This service requires 2 steps to verify a request. You first send a hash and you receive and acknowledge. Then you send the the actual request and you receive the response.
public byte[] getResponse(byte[] hash, byte[] request) throws Exception{
if(client == null || client.socket.isClosed() || !client.socket.isConnected()
|| client.socket.isInputShutdown() || client.socket.isOutputShutdown(){
client = new TCPClient(this.host, this.port);
}
client.SendToServer(hash);
byte[] ack = client.ReceiveFromServer();
if(checkAck(ack, getAckForRequest(request))){
client.SendToServer(request);
byte[] response = client.ReceiveFromServer();
return response;
}
}
My code looks something like this. I simplified it a bit to make it more readable.
I am using this function inside a try/catch block and when it throws an exception I store the request in a MySQL database.
Is there a way to avoid blocking my main thread if the connection is slow and do the same stuff?
Is there a way to avoid blocking my main thread if the connection is slow and do the same stuff?
Yes. One can call setSoTimeout() on a Socket.
The Oracle documentation:
https://docs.oracle.com/javase/8/docs/api/java/net/Socket.html#setSoTimeout-int-
Enable/disable SO_TIMEOUT with the specified timeout, in milliseconds. With this option set to a non-zero timeout, a read() call on the InputStream associated with this Socket will block for only this amount of time. If the timeout expires, a java.net.SocketTimeoutException is raised, though the Socket is still valid. The option must be enabled prior to entering the blocking operation to have effect. The timeout must be > 0. A timeout of zero is interpreted as an infinite timeout.
If you just want to close the connection and give up it works well. If you want to resume the action later you have to keep track of the bytes already read which means just having more threads is usually an easier option.

How to read the data from datastream

Please help me out on how to read the stream of data in java. My requirement is to make the telnet connection to the router. This part is accomplished. From the router, Have to connect to the xxx remote machine using its ip address and port number through telnet. While making this connection, i am getting some response. But while reading, the program control stops at read() method of InputStream class. Here are the code snippet which i am using to read the stream of data.
buff = new byte[4*1024];
ret_read = 0;
do
{
ret_read = in.read(buff); // Program control gets hanged here. Once all the data are read...
if(ret_read > 0)
{
System.out.println(new String(buff,0,ret_read));
}
}while(ret_read > 0);
What is happening is the read is blocking and waiting for more data to be sent on the stream, it will continue to do that until the stream is closed or more data is sent.
You need to either use a non-blocking read, put a timeout on the read, or close the stream server side after it finishes sending the data.

Sending data through sockets in java

I am currently working on a one server many clients system. I am trying to get it so the server can send out one command, through a PrintWriter, that will go through to all of the clients connected on that socket. However in practice the command only goes through to one client. All of the clients are created on one socket, and all use the same Scanner. Is what I am trying to do possible?
Some code(incase it helps)
Creation of the socket:
serverSocketRefresh = new ServerSocket(PORTREFRESH);
refresh = serverSocketRefresh.accept();
Creation of the Print Writer and the Scanner:
networkOutputRefresh = new PrintWriter(refresh.getOutputStream(), true);
networkInput = new Scanner(refresh.getInputStream());
Ceation of the clients:
do
{
// Wait for client...
client = serverSocket.accept();
System.out.println("\nNew client accepted.\n");
handler = new ClientHandler(client,networkOutputRefresh, itemArray, bidderArray);
handler.start();
} while (true);
The command im trying to transmit to all of the clients:
public static void updatePrice()
{
networkOutputRefresh.println("1");
}
I am not sure if I correctly understand your code but it seems you are using a single reference of client. And your client reference will be holding the last client reference and hence the printwrite is writing only for that client. Ideally if you want to publish something to all the clients then you should have a collection of client references.Whenever you get an accept on the server socket, add the new client reference to your collection. And whenever you have to publish to all the clients just iterate over your client collection and publish using their associated printwriters.
Why not just use a BufferedReader and BufferedWriter, and make a new one each time you accept a client?
Edit: Or, if that '1' is the only thing you will ever send over that socket, just send it over the socket directly, as a byte. I believe the method is something like socket.write(new byte[] { 1 }, 0, 1), and to read on the other end, socket.read(buffer, 0, 1), where buffer is a byte array of length 1.

Sending and receiving an acknowledgement using Datagram UDP

I'm new to socket programming and programming a Java UDP simple client-server application. I'm writing a time/date server client. The client can ask the server for the time and date and it waits for a response. Also, every minute, the server updates all clients with the current time. The client needs to
be able to initiate contact with the server and wait for a message back
listen for periodic updates from the server
How can I do this using a single DatagramSocket?
I was thinking of creating two threads: one that listens and one that writes. The problem is that in the case that the client initiates contact with the server, it needs to wait to receive an acknowledgement from the server. So, the writing thread also needs to listen for packets from the server sometimes. But in this case, I have two threads listening and the wrong thread will get the acknowledgement.
Is there a way to specify which thread gets the input? Or is there some other way to solve this problem?
I've been searching for this answer but unable to find it. The closest I've found is Java sockets: can you send from one thread and receive on another?
If there is just one writer thread then it could send the request and go into a wait loop. The listener thread would then get the response, add it to a shared variable (maybe an AtomicReference), and then notify the writer that response has been received.
// both write and listener threads will need to share this
private final AtomicReference<Response> responseRef =
new AtomicReference<Response>();
...
// writer-thread
writeRequest(request);
synchronize (responseRef) {
while (responseRef.get() == null) {
// maybe put a timeout here
responseRef.wait();
}
}
processResponse(response);
...
// listener-thread
Response response = readResponse();
synchronize (responseRef) {
responseRef.set(response);
responseRef.notify();
}
If you have multiple writers or multiple requests being sent at the same time then it gets more complicated. You'll need to send some sort of unique id with each request and return it in the response. Then the response thread can match up the request with the response. You'd need a ConcurrentHashMap or other shared collection so that the responder can match up the particular request, add the response, and notify the appropriate waiting thread.

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

Categories

Resources