I'm writing a simple tcp stream SMTP server. I wrote following code to check if the client connection is still available. Simply peeking one byte to see if socket input stream is working. But when I set in.mark(x) read ahead limit to 1, it shows error when I attempt to send Header for the second time. When it's set to 2, it doesn't seem to have any problem at all. Why is this?
// check if client disconnected
try {
in.mark(1); // 1 char read ahead limit
if (in.read() == -1) {
System.out.println("CONNECTION CLOSED BY CLIENT!");
return; // end of thread
} else {
in.reset();
}
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException();
}
The error I get is this:
java.io.IOException: Mark invalid
at java.io.BufferedReader.reset(BufferedReader.java:512)
at smtp.server.SocketThread.run(SocketThread.java:59)
The entire code is on my github.
Forget it. Just read and write, and deal with the exceptions as they arise.
At present you are engaged in fortune-telling. Even if you find a method that works to tell you whether the client connection is alive now, it could go down between calling this method and the very next line of code.
The only method that actually works of trying to detect whether a resource is available is to try to use it in the normal way.
Related
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.
I wonder how to handle exceptions correctly within a client server application. My client sends an information to the server(thread) which receives it within its run method.
I have already read something about uncaught exception handling when dealing with exceptions in the run method but want to know if this is the correct way to do it in my case.
I want to catch the exception on the client side.
I have in mind to do the following:
//Server
run(){
try{
...
}
catch(Exception e){
clientoutputstream.write(...); //transmitting the error
}
}
Any other suggestions?
You should put a try { } catch (IOException) around your read() call so you know if the other end has closed the connection. The other thing you might want to do is to put a try { } catch(Throwable) { } around the processing code so you can manually close the socket (Be very careful about catching Throwable) But if you just let the thread die the Socket will be closed when the object is garbage collected or when it times out
I am writing an app for android 4.2, currently debugged on a Samsung s2+.
The app establishes a connection to a server using a Socket, and the server is using a ServerSocket and the establish()-method to get its socket. So far so good. Since I have to make all the networking in android in a new thread, I created a new class extending Thread which communicates with an underlying Activity (for user input) using a BlockingQueue. The threads run method:
public void run() {
Socket s = null;
try {
s = new Socket(info.getIp(), 1337);
} catch (IOException e) {
e.printStackTrace();
}
String code = null;
try {
code = queue.take();
} catch (InterruptedException e1) {
e1.printStackTrace();
}
Log.e("DONE", code);
PrintWriter out = null;
try {
out = new PrintWriter(s.getOutputStream());
} catch (IOException e) {
e.printStackTrace();
}
out.write(code);
out.flush();
}
The connection is up and running, and the logged message "DONE"+code is logged. However, nothing is received on the server side until I force close the app. Is an android thread not able to flush data?
EDIT: If close the socket immediately after writing to it, the text arrives without having to force close the app. Why can't I read the text in the server if the socket is still alive?
try add a newline to the string you sent to server , something like :
out.write(code+"\n");
out.flush();
and as EJP said above put the out.write inside the try / catch
A socket connection only provides the ability to send and receive bytes. As soon as the client sends a byte, the server will receive it. Also, as soon as a client is disconnected, the server will know about it - this is about the extend of what you get from sockets.
The concept of a message does not exist at this level. A message is instead defined by whatever lies above the socket, so most protocols use one or more of three different ways to chunk streams of bytes into "messages"
a special byte or sequence of bytes indicates the end of the message (a new line for example, which seems to have been your case :)
each message starts with x bytes which provide the length of the message (so a simple "05aaaaa02bb" stream of bytes might mean that 2 messages were send - "aaaaa" and "bb"
the entire socket connection lasts for a single message (end of message comes when the connection is closed). This is how HTTP 1.0 works for example.
I have tried writing to the response, because there is no proper disconnect callback:
private boolean write(byte[] output, AsyncContext context) {
try {
OutputStream stream = context.getResponse().getOutputStream();
stream.write(output);
stream.flush();
return true;
} catch (IOException ex) {
//client disconnected
log.error(ex);
removeAsyncContext(context);
return false;
}
}
But this didn't seem to the trick. When the client is disconnected, writing and flushing the buffer did not throw an exception.
The weird thing is, the second time you try to write to the output stream (after the disconnect), the write does throw an exception. It looks like the first time you write/flush it,some internal state is set to error, without notifying.
I have tried on both Jetty 8 and Tomcat 7 and I see the same behavior.
Is there a solution to find out whether the message is received by the client? Am I missing something?
I recognize you are looking for a proper way of detecting disconnects, but for those who don't mind a kludge:
Note: This method periodically sends space characters to the client that must be trimmed before interpreting the results. This is the kludgey part.
Start a thread that has access to the writer/outputstream of the servlet response. This thread sends space characters periodically (I used 1 second intervals) to the client. Wrap in a IOException try/catch block that sets your abort flag.
If the connection is closed, most servlets will throw a flavor of EOFException (which is an IOException) when data cannot be delivered to the client. You are catching this exception and setting your abort flag.
When the abort flag is caught, you have options. You can nuke the executing thread, have all your processing periodically check for the abort flag, push an exception into the executing thread, or do any number of things (not detailed here).
Should the process finish successfully, you will get your results prefixed by a number of spaces. Again, remember to trim these on your client.
In my experience when a client disconnects from a servlet there is an exception referring to a Broken Pipe.
For example: Broken Pipe when writing bytes in ServletOutputStream
I would suggest catching java.net.SocketException and looking at the exception details to verify if it is a broken pipe (as a starting point):
Caused by: ClientAbortException: java.net.SocketException: Broken pipe
at org.apache.catalina.connector.OutputBuffer.realWriteBytes(OutputBuffer.java:358)
at org.apache.tomcat.util.buf.ByteChunk.append(ByteChunk.java:354)
at org.apache.catalina.connector.OutputBuffer.writeBytes(OutputBuffer.java:381)
at org.apache.catalina.connector.OutputBuffer.write(OutputBuffer.java:370)
at org.apache.catalina.connector.CoyoteOutputStream.write(CoyoteOutputStream.java:89)
I want to create simple download accelerator.
How it works
Server wait for incoming connection.
Client connect to server.
Then, server send file size to client and wait for download connection.
Client got file size, then create download thread and these thread are connect to server.
After server got connection from each thread, server will wait for start and end offset file from thread.
Each thread send start and end offset file to server.
After server got offsets, server will send the portion of file to thread.
Each thread will read and write to file. For example, buffer.p01, buffer.p02, buffer.p03
Client merge all file into one file order by sequence. ( Not yet implemented )
I think server side it works correctly but client side it has some problem.
The problem is if I set MAXTHREAD to 1, it works correctly. But if I set more than one, it stuck somewhere forever.
This is server side code..
http://pastebin.com/TEakGB0c
and this is client side code with multithreading
http://pastebin.com/wKhP7DxS
Thanks your.
You have a pretty big obvious problem. ServerSocket's accept method returns a new socket every time. In your server code here
initSocket = servSock.accept();
initSocket is a class member field which means you will over write the old socket and never close it. You should start a new thread to handle this socket and from what I see it looks like you just keep reusing the same socket. That won't work. Look at tutorials on how to open sockets. Sorry I can't help more but there is a lot of things going on here that just won't work. Maybe you can start focusing on part of the code and we can help more.
I agree, it could be a small issue or it could be a big one, some example code would help us aid you, If you try to connect to a server 3 times using the same port you will get an error because you can only have 1 connection per port, the problem could be super simple or very complex, if you edit your post and add your code then we can better help you.
Please close your OutputStream os
Sending u a snippet
public static boolean sendFile() {
int start = Integer.parseInt(startAndEnd[0]) - 1;
int end = Integer.parseInt(startAndEnd[1]) - 1;
int size = (end - start) + 1;
try {
os = initSocket.getOutputStream();
os.write(byteArr, start, size);
os.flush();
System.out.println("Send file to : " + initSocket);
} catch (IOException e) {
System.out.println(e.getLocalizedMessage());
disconnected();
return false;
} finally {
if (os != null) {
try {
os.close();
} catch (IOException ex) {
Logger.getLogger(FileServer.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
return true;
}