Android - multithread TCP connection - java

I've been searching for an answer to my problem, but none of the solutions so far have helped me solve it. I'm working on an app that communicates with another device that works as a server. The app sends queries to the server and receives appropriate responses to dynamically create fragments.
In the first implementation the app sent the query and then waited to receive the answer in a single thread. But that solution wasn't satisfactory since the app did not receive any feedback from the server. The server admin said he was receiving the queries, however he hinted that the device was sending the answer back too fast and that the app probably wasn't already listening by the time the answer arrived.
So what I am trying to achieve is create seperate threads: one for listening and one for sending the query. The one that listens would start before we sent anything to the server, to ensure the app does not miss the server response.
Implementing this so far hasn't been succesful. I've tried writing and running seperate Runnable classes and AsyncTasks, but the listener never received an answer and at some points one of the threads didn't even execute. Here is the code for the asynctask listener:
#Override
protected String doInBackground(String... params) {
int bufferLength = 28;
String masterIP = "192.168.1.100";
try {
Log.i("TCPQuery", "Listening for ReActor answers ...");
Socket tcpSocket = new Socket();
SocketAddress socketAddress = new InetSocketAddress(masterIP, 50001);
try {
tcpSocket.connect(socketAddress);
Log.i("TCPQuery", "Is socket connected: " + tcpSocket.isConnected());
} catch (IOException e) {
e.printStackTrace();
}
while(true){
Log.i("TCPQuery", "Listening ...");
try{
Log.i("TCPQuery", "Waiting for ReActor response ...");
byte[] buffer = new byte[bufferLength];
tcpSocket.getInputStream().read(buffer);
Log.i("TCPQuery", "Received message " + Arrays.toString(buffer) + " from ReActor.");
}catch(Exception e){
e.printStackTrace();
Log.e("TCPQuery", "An error occured receiving the message.");
}
}
} catch (Exception e) {
Log.e("TCP", "Error", e);
}
return "";
}
And this is how the tasks are called:
if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.HONEYCOMB) {
listener.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, "");
sender.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, "");
}
else {
listener.execute();
sender.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
How exactly would you approach this problem? If this code is not sufficient I would be glad to post more.

This is because Android's AsyncTask is actually only one thread, no matter how many you create, so if you really want 2 threads running at the same time, I suggest you use standard Java concurrent package tools, not AsyncTask. As explained in the documentation:
AsyncTask is designed to be a helper class around Thread and Handler
and does not constitute a generic threading framework. AsyncTasks
should ideally be used for short operations (a few seconds at the
most.) If you need to keep threads running for long periods of time,
it is highly recommended you use the various APIs provided by the
java.util.concurrent pacakge such as Executor, ThreadPoolExecutor and
FutureTask.

Look this is tcp connection. So you don't need to bother about data lose. This is port to port connection and it never sends end of stream (-1). Perhaps you have to care about read functionality. Because you can not conform all steams are received or not. Tcp read method is a blocking call. If your read buffer size is smaller than available stream size then it block until it can read fully. And you are using android device, perhaps available stream can vary depending upon your device network. So you have 2 options,
1) your buffer size should be dynamic. At first check your available input stream size by using is.available() and create your buf size by this size. If available size is zero then sleep for a certain time to check it is lost its stream availability or not.
2) set your input stream timeout. It really works, because it reads its available stream and wait for the timeout delay, if any stream is not available within the timeout period then it throws timeout exception.
Try to change your code.

Related

Socket connection half dropped - IOException not thrown

i read some of the answers here about this problem, but i wasn't satisfied with them, so i decided to ask it my self. So I know that there are similar questions, but since the answers don't really work for me, i asked myself.
I have an app that lets 2 users connect to each other (one works as a server, the other one as client). They will send files through that socket connection. I am using a Service with 2 threads inside, one to read, another one to send the file that the user chose.
Here is the problem : If a client closes the app by swiping it on the android menu (of the apps that are running), and then the server (the other guy) tries to send him something, in my opinion it should throw an IOException, since the other end of the socket streams is over. But it is not doing that and i don't know why. If i try to send something to someone that left, i want to show a Toast.
Edit: just noticed it always stops at the instruction out.reset();
Do any of you know why that exception is not being thrown?
What could be a possible solution.
PS: It is a lite app, so to send Keep Alive messages wouldn't be a good solution. Also, it already showed the toast that i have one or two times, but then i couldn't replicate that behaviour again.
Here is my code where i wan't that to happen :
ClientHandler tmp = connectedClients.get(key);
ObjectOutputStream out = tmp.getOut();
Socket s = tmp.getSocket();
if(s.isClosed()){
System.out.println("The socket of this client "+key + " is closed!");
}
if(s.isOutputShutdown()){
System.out.println("The output of this client is shutdown !");//only checks this side, the other one is the one that is shutdown
}
System.out.println("changed the culpado to : "+1);
createSendNotification();
File apkToSend;
for(int i=0;i<listOfApps.size();i++){
System.out.println("Item do be sent is : "+i);
HighwayGridViewAppItem tmpItem=listOfApps.get(i);
filePath=tmpItem.getFilePath();
appName=tmpItem.getAppName();
System.out.println("his filepath to send is : "+filePath);
System.out.println("his appname to send is : "+appName);
couldSend=false;
apkToSend=new File(filePath);
if(apkToSend.exists()){//do i reallly need this if?
apkToSendSize=apkToSend.length();
System.out.println("File size: " +apkToSendSize);
try{
out.writeObject(appName +": "+ apkToSendSize);//appName to send to have the name of the file
byte[] buffer = new byte [8192];
BufferedInputStream bis=new BufferedInputStream(new FileInputStream(apkToSend));
int count;
totalToSend =0;
showSendProgress();
while((count=bis.read(buffer))!=-1){
out.write(buffer,0,count);
totalToSend +=count;
out.reset();
System.out.println("ServerComm send thread - already sent this ammount : "+ totalToSend);
}
out.flush();
bis.close();
}
catch ( IOException e){
System.out.println("It is throwing the input output exception");
e.printStackTrace();
connectedClients.remove(key);
if(clients.size()<=1){
h.post(new Runnable() {
#Override
public void run() {
Toast.makeText(context, "No one is in your group.", Toast.LENGTH_SHORT).show();
}
});
i=listOfApps.size()+1;
}else{
System.out.println("Has more than one");
}
}
PS: When i try to send to a "closed" client, it prints a few "ServerComm send thread - already sent this ammount : "+ totalToSend" but then just stops, which is when i think it should throw the exception, but it just stops, and doesn't give any error, the app continues its life, but i NEED to give some input to the user that some problem went down.
Also, I create that Handler in the onCreate method of this service, it is being correctly created (since it is in a Service, it needs different creation) with the main looper.
Thank you guys in advance.
EDIT: Eventually, after almost 4 minutes, it throws a SocketException, but i can't wait that long.
Just because Android disposes of an app does not mean that internally all of your open connections are closed, it is mostly likely you need to detect the Android event and then execute the code that explicitly closes the open socket rather than waiting for Android to take care of it eventually. Otherwise, you will have to wait for the socket to be closed by garbage collection calling the finalizer.
This post here has some details about Android events and the onDestroy method in particular: How to close Android application?
If you require an immediate disconnection detection then you would have to implement your own ping/keep alive mechanism which would normally mean sending packets and acknowledging them continuously to be able to catch an exception more reliably.

Handling Multiple TCP Connections In Java (Server-side)

I'm in the process of writing a messaging program, and I'm running into a spot where I'm having trouble understanding how to pass a socket over to a new thread for handling outbound messages via TCP. I'm currently using UDP packets for messages coming from a client, to the server, which, being UDP, doesn't require very much processing, as it's simply listening for incoming packets, before it de-serializes the objects, and processes them as needed in a separate thread. My problem now is, I'm setting up a client initiated TCP socket for reverse traffic, from the server to the assorted clients that connect. I've done a bit of research, and I already understood that each client should have their own thread for handling outgoing messages, along with another thread simply for accepting the incoming connections. I'm unsure of how to actually achieve this, and I've done some research into the topic.
I've found this: http://docs.oracle.com/javase/tutorial/networking/sockets/clientServer.html
The resource above basically verified my original suspicion that this would have to be handled by threads dedicated to the client. They included psuedo code here, which is representing my listener thread.
while (true) {
accept a connection;
create a thread to deal with the client;
}
I'm a bit of a visual learner, and I have been searching for some type of an example where this is done. I'm unsure of what variable I'd be passing over to the thread that keeps the original connection open, and pushes data back to clients. I'm also having a little bit of trouble grasping whether it even keeps the same socket open, or if a new one needs to be established, which then, makes me believe a firewall could interfere, but I know that won't be the case.
Can somebody explain this for me in detail? If possible, an example would be greatly appreciated!
I'll be likely replying and commenting on responses in about 15-30 minutes from the time this is posted.
What you are doing sounds correct. I typically implement a server like this (simplified version with no tracking of the clients and so on):
#Override
public void run() {
//start listening on the port
try {
serverSocket = new ServerSocket(port);
logger.info("Listening for connections on port " + port);
} catch (IOException e) {
logger.error("Cannot start SocketListener on port " + port + ". Stopping.", e);
return;
}
while (!stopped) {
try {
//wait for connection
Socket newSocket = serverSocket.accept();
ClientThread client = new ClientThread(newSocket);
Thread clientThread = new Thread(client, MEANINGFUL_THREAD_ID);
clientThread.start();
} catch ...
}
}
where serverSocket is a ServerSocket instance variable and stopped is a flag I use to stop the listener thread.
So to answer your questions in the comment, you normally pass the Socket object to each client thread so that that thread can work with the input and output stream and handle closing of the socket and so on. Once you "accept" a socket connection, you do not need to recreate the ServerSocket, you simply call .accept() again to start waiting for a new connection.
In most cases, you will need to keep track of all client threads in your server so that you can stop the server gracefully or do broadcasts for example.

android socket gets stuck after connection

I am trying to make a app that scans all the ip in range for a specific open port (5050) and if it is open write some message on LOG.
heres the code :
public void run(){
for(int i=0;i<256;i++)
{
Log.d("NetworkScanner","attemping to contact 192.168.1."+i);
try {
Socket socket=new Socket(searchIP+i,5050);
possibleClients.add(searchIP);
socket.close();
Log.d("NetworkScanner"," 192.168.1."+i+" YEAAAHHH");
} catch (UnknownHostException e) {
Log.d("NetworkScanner"," 192.168.1."+i+" unavailable");
} catch (IOException e) {
e.printStackTrace();
}
}
}
EDIT: here's a new problem: Even if a host is found online without the port open the scanning process (for loop) is stuck for a long time before moving to next. also scanning each host is taking considerable time!
Phew the final solution was to make a Socket object with default constructor then create the InetAddr object for the host and then use the Connect(InetAddr,timeout) function of the socket api with timeout in milliseconds (approx 300ms) that scans every ip in just 300 ms or less (less than 200 ms may give errors) and multi threading to scan in parallel make it as fast as 5 sec to scan all the IPs in range..
You are breaking out of the loop when no Exception is thrown.
You need to remove break;
To address your new problem:
Of course it's slow. What did you expect? You are trying to establish a connection to each IP in your subnet which takes time. It seems you are only trying figure out what devices are available on the network, so you might be able to decrease the time a little by looking at this answer. He is using the build in isReachable method which accepts a timeout value. It will still take some time, but not that much time.
Remove the "break;"...it stops the iteration.

Java UDP Server, concurrent clients

Is the code below sufficient to accept concurrent UDP transmissions? More specifically, if 2 clients transmit concurrently, will DatagramSocket queue up the transmissions and deliver them one by one as I call receive(), or will only one make it through?
DatagramSocket socket = new DatagramSocket(port, address);
byte[] buffer = new byte[8192];
while(!disconnect){
DatagramPacket p = new DatagramPacket(buffer, buffer.length);
socket.receive(p);
}
There is no queuing by default. The client may retry till timeout or similiar are reach.
UDP is quiet fast but on heavy load you may have clients that cannot connect.
If the packets make it to your networking interface (imagine lost packets on a congested wireless channel) they will passed up and the blocking method socket.receive(p) will be called. If there is a collision of packets on the channel because of two clients transmitting at the same time you will not get any of the two packets. But this is most likely not possible because the access technology of networking interfaces will take care of this, check
CSMA/CA or CSMA/CD
After calling socket.receive(p) you should create a new thread to process the packet itself. That will make sure that the next packet can be received on the socket.
EDIT:
Description of INTEL's TX and RX descriptors
A basic solution would have on thread responsible for handling a number of incoming requests (with your desired limit) and then handing them off to other worker/request handler threads. This basic structure is very much the same with most servers: a main thread responsible for handing off requests to worker threads. When each of these worker threads is finished, the you can update a shared/global counter to let the main thread know that it can establish a new connection. This will require synchronization, but it's a neat and simple abstraction.
Here's the idea:
Server Thread:
// Receive Packet
while (true) {
serverLock.acquire();
try {
if (numberOfRequests < MAX_REQUESTS) {
packet = socket.receive();
numberOfRequests++;
requestThread(packet).run();
} else {
serverMonitor.wait(serverLock);
}
} finally {
serverLock.release();
}
}
Request Thread:
// Handle Packet
serverLock.acquire();
try {
if (numberOfRequests == MAX_REQUESTS){
numberOfRequests--;
serverMonitor.pulse();
}
} finally {
serverLock.release();
}
This is just to give you an idea of what you can start out with. But when you get the hang of it, you'll be able to make optimizations and enhancements to make sure the synchronization is all correct.
One particular enhancement, which also lends itself to limited number of requests, is something called a ThreadPool.

Expanding my Java program to send a alert message to other computers

I've written a java intake program that send an PDF-formatted intake to a shared folder so that other people in the network can read it. However, there is not a way for the other people to know that an intake was sent unless someone tells them, so I want the program to send an alert message to the other computers telling them that an intake has been sent.
Now I've done some research into this and figured that TCP is the way to go since it's reliable. I also know that this is a one-to-many sending going on, so I assume that my Intake program will act as the server an the other computers will be the client, or should it be the other way around?
Now I assume that I have to create a client program that listens to the server and waits for it to send a message.
With that in mind, how do I:
Create a client program that listens for the message continuously until the program is closed. I assume that I'll be using "while (true)" and sleep. If so, how long do I put the program to sleep?
Make it as part of Windows service so that can load up when Windows start.
On the server end, how do I:
Send messages to more than one computer, since TCP is not capable of multicasting or broadcasting. I assume an array/vector will play a part here.
Oh, this is a one-way communication. The client doesn't have to respond back to the server.
First of all, UDP is quite reliable (in fact, as reliable as the IP protocol itself). TCP simply ensures that the data was received which involved quite a lot of magic in the back end. Unless you absolutely need to be sure that other machines got the message, you could do it with UDP. Mind that I'm not saying “Don't use TCP”, I just want to make it straight that you should take UDP into consideration as well.
Anyway, yes, you can create a simple listening program. Here is an example of a client in Java that reads messages from the server. It overrides the run method of a Thread class:
public void run() {
try {
String messageFromServer = reader.readLine();
while (messageFromServer != null) {
// Do things with messageFromServer here
// processor.processFromServer(messageFromServer);
messageFromServer = reader.readLine(); // Blocks the loop, waits for message
}
}
catch (IOException e) {
// Handle your exception
}
}
Amongst other things, my thread was set up as such:
public CommunicationThread(String hostname, int port, int timeout) throws IOException, SocketTimeoutException {
InetSocketAddress address = new InetSocketAddress(hostname, port);
socket = new Socket();
socket.connect(address, 2000); // 2000ms time out
// You can use the writer to write messages back out to the server
writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
}
Now, regards to server-side you can do something as follows:
Write a program to allow clients to contact, given that they know your address.
Accept the connections, and store the sockets in a list.
When you need to send out a message, traverse the list and send the data to everyone on it.
You can start listening on your server with
this.socket = new ServerSocket(port);
You could (or even should(?)) make it threaded so that you can accept clients while serving others. You can accept new clients with:
socket.accept(); // Blocks, waiting for someone to connect, returns open socket
Feel free to pass that to a whole new class which can deal with BufferedWriter (and maybe even BufferedReader if you want to read from clients as well). That class is where you would implement things such as writeToClient(message)
Consider the situation where you have a ClientConnection class that has writeToClient(String s) method and (Server server, Socket socket) and initialized ArrayList conList.
Here is how you would follow:
In a separate thread in Server, accept connections with
ClientConnection con = new ClientConnection(this, socket.accept());
conList.add(con);
Then, when you want to write to clients:
for (ClientConnection c : conList) {
c.writeToClient("I'm sending you a message!");
}
I hope you get a vague idea of what you need to do. Read the Socket documentation, it's very useful. Also, as always with threaded applications, make sure you aren't doing things such as modifying a list while traversing it and avoid race conditions.
Good luck!

Categories