I try to overcome a user disconnection detection on the server side using read timeout.
This is part of my code:
try {
socket.setSoTimeout(3000);
in = new DataInputStream(socket.getInputStream());
out = new DataOutputStream(socket.getOutputStream());
usr = new User(in.readUTF());
usr.connectUser();
int i=0;
while(true){
try{
i = in.readInt();
}
catch(SocketTimeoutException e){
System.Out.Println("Timeout");
// user connected, no data received
}
catch(EOFException e){
System.Out.Println("Disconnected");
// user disconnected
}
}
}
catch(Exception e){
// other exceptions
}
the code works fine except the "user disconnected" issue.
i want to catch the timeout exception and just continue waiting for data
but only if the client still connected.
why i never get other exception than SocketTimeoutException?
shouldn't i get IOException while in.readInt() can't use the socket because client disconnected?
is there any other simple way to detect user disconnection?
i mean as unwanted disconnection, like user had suddenly wifi shutdown etc...
thanks,
Lioz.
If the client didn't write anything within the timeout period, you get a SocketTimeoutException. If he disconnected instead of writing anything, you get an EOFException. Catch them separately. If you didn't get an EOFException, he didn't disconnect.
Related
I am experiencing problems when using a UDP datagram packet, in the program I bind a UDP port and listen messages on it. This normally works fine, but if the port remains idle for a long time, the program automatically terminates the UDP socket. Unfortunately, the log file is huge and it is difficult to find the exception. Please help me find a way to keep the UDP port alive forever. Thanks in advance.
Here is my code:
socket = new DatagramSocket(port);
setBindSocket(true);
socket.setSoTimeout(60000);
while(isBindSocket()) {
try {
byte[] buffur = new byte[512];
DatagramPacket inputPacket = new DatagramPacket(buffur, buffur.length);
inputPacket.setLength(buffur.length);
socket.receive(inputPacket);
byte [] bString = inputPacket.getData();
String hString = new String(bString);
} catch (SocketTimeoutException ste) {
} catch (Exception e) {
e.printStackTrace();
}
}
The following statement changes the socket's behavior when receiving - if no datagram arrives in 60 seconds, a SocketTimeoutException is thrown.
socket.setSoTimeout(60000);
Maybe I have misunderstood your question.
You're going to have to find that exception. Unless you set a read timeout, the read method will block forever.
I can set up client Socket to send request to server (sendData() method) and read the received message (readData() method) correctly, but I only received message each time I send the request to server by using MOBILE_REQUEST string, through these codes:
#Override
protected Boolean doInBackground(String... params) {
try {
mSocket = new Socket(
// PC Ip is 192.168.1.199
// It is the other device, Not be local host : 127.0.0.1
Pas.pas.getPcIP(), 17001);
DataOutputStream mDos = new DataOutputStream(mSocket.getOutputStream());
String RESPONSE = null;
String MOBILE_BLOCK = "MobileBlock#";
// Converting collected data in byte array into String.
RESPONSE = sendData(mDos, MOBILE_BLOCK);
/**
* The result response from PC app in here
*/
// Log : response - #WindowsResp#192.168.1.199#
Log.i("", "response '" + RESPONSE + "'");
}
} catch (SocketTimeoutException e) {
IS_SOCKET_TIME_OUT = true;
e.printStackTrace();
} catch (ConnectException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
sendData() method - Client send the request to server and wait to get response data - String data.
private String sendData(DataOutputStream mDos, String MOBILE_REQUEST) {
try {
// Log : MOBILE_REQUEST.getBytes() - [B#82f10f8
mDos.write(MOBILE_REQUEST.getBytes());
// todo I should set this sleep, bcs TCP has delay time,
// so i need set the delay time for client should receive data
// otherwise, sometimes I did not receive anything
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// Log : #WindowsResp#192.168.1.199#
return new String(readData(mSocket));
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
readData() method - Read data after received from server.
public static byte[] readData(Socket mSocket) {
/* Since data are accepted as byte, all of them will be collected in the
following byte array which initialised with accepted data length. */
DataInputStream mDis = null;
try {
mDis = new DataInputStream(mSocket.getInputStream());
// Log : mDis.available() - 23
byte[] data = new byte[mDis.available()];
// Collecting data into byte array
for (int i = 0; i < data.length; i++)
data[i] = mDis.readByte();
// Log : data - [B#30c044a4
return data;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
What I want is every time server send to my socket client the message by clicking button, the socket client should receive it. But in above codes, it's not.
Please help me how to set up socket client always listen from server?
p/s : Or do I need set up ServerSocket? If use ServerSocket I cannot use same port, right? Because when I open ServerSocket for listen first (ex. at port 17001), I can not use client socket to send request via port 17001 because that port is already used.
UPDATED
The way server (PC app - laptop device) send to client (Mobile device - Android) is via Socket TCP, through these steps :
1 - Client (Android device) set up TCP socket connection to Server (PC app) (this connection never closed until exit app in onDestroy() method).
2 - Client send request to server, ex. MOBILE_REQUEST = "MobileID#MobileIP#"
3 - Server received the request from client, It replied to client via Socket connection, actually client received data correctly. ex. "WindowsRep#WindowsIP"
This way not work for me, even socket TCP connection not closed, and getInputStream() not shut down yet. In this case :
Server send string data to client via Socket connection, client received data correctly.
What I want is every time "Server send string data to client via Socket connection, client received data correctly". But in my case, client only receive data after sent request to server.
C# Server
Server socket
IPEndPoint ipe = new IPEndPoint("192.168.1.199", 17001);
svSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
svSocket.Bind(ipe);
Server Send data
string data_send = "#WBroad#" + "192.168.1.199" + "#";
byte[] byteData = Encoding.UTF8.GetBytes(data_send);
c.ClientSocket.Send(byteData);
As you haven't posted the sending code it is impossible to tell why you're not receiving data, but here is a quick critique of what you have posted:
// mSocket.setReuseAddress(true);
You've commmented this out, but it would be pointless to call this method now. You would have to construct the socket as new Socket(), with no parameters, then call this method, then call connect(). And as you aren't providing a source port or IP address to be re-used, it would still be pointless.
byte[] data = new byte[mDis.available()];
This is a complete misuse of available(). It does not provide a message length. See the Javadoc. There is no reason to believe that whatever data has arrived at this point, if any, is a complete message, or only one message. If you want messages you won't get any help from TCP: you will have to implement them yourself. As your protocol appears to be text-based I suggest you just use lines and readLine(), with BufferedReader and BufferedWriter instead of the DataInput/OutputStreams. And construct those once for the life of the socket, not once per application message, otherwise you will lose data.
// Collecting data into byte array
for (int i = 0; i < data.length; i++)
data[i] = mDis.readByte();
The huge problem with this is that it won't block, because, most of the time, available() will be zero, so this method will do nothing except return an empty byte[] array.
In any case this is entirely equivalent to mDis.readFully(data);, only several times less efficient, but you shouldn't be doing this anyway: see above.
return data;
} catch (IOException e) {
e.printStackTrace();
}
return null;
This is poor practice. You should let the IOException be thrown by this method and let the caller deal with it.
mDos.write(MOBILE_REQUEST.getBytes());
See above. This should include a line terminator, a length-word prefix, or some other way of delimiting the message.
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
This sleep is literally a complete and utter waste of time. And space. Remove it. Sleeping in networking code is just cargo-cult programming.
return new String(readData(mSocket));
This will throw a NullPointerException if readData() returns null, which it does if there was an IOException, which is another reason to let that method propagate that exception instead of catching it internally and returning null.
private boolean splitData(int mobile_send_request_case, String DATA) {
This method is entirely irrelevant to the problem and should not have been posted.
Or do I need set up ServerSocket?
No. Why do you think that?
If use ServerSocket I cannot use same port, right?
Wrong.
Because when I open ServerSocket for listen first (ex. at port 17001), I can not use client socket to send request via port 17001 because that port is already used.
Wrong again. It isn't.
As I said above, it's impossible to help you further when you don't post all the relevant code, but there's enough wrong with this already that you really need to start again.
I have TCP server-client application. It works but sometime something happens. Client connects to server but server says he doesn't accepted him.
Server side code:
while(!stopped){
try {
AcceptClient();
} catch(SocketTimeoutException ex){
continue;
} catch (IOException ex) {
System.err.println("AppServer: Client cannot be accepted.\n"+ex.getMessage()+"\n");
break;
}
...
private void AcceptClient() throws IOException {
clientSocket = serverSocket.accept();
clientSocket.setSoTimeout(200);
out = new ObjectOutputStream(clientSocket.getOutputStream());
in = new ObjectInputStream(clientSocket.getInputStream());
System.out.println("Accepted connection from "+clientSocket.getInetAddress());
}
Client side code:
try {
socket = new Socket(IPAddress, serverPort);
socket.setSoTimeout(5000);
out = new ObjectOutputStream(socket.getOutputStream());
in = new ObjectInputStream(socket.getInputStream());
} catch (IOException e1) {
sendSystemMessage("DISCONNECTED");
sendSystemMessage(e1.getMessage());
return;
}
sendSystemMessage("CONNECTED");
If client connects the message:
Accepted connection from ... appears. But sometimes it doesn't appear
even if client sends message "CONNECTED"
Server is still runing the loop trying to get client and it is catching socketTimeoutException. Client is connected, sends message and waits for response.
I suspect a missing 'flush' inside your client's 'sendSystemMessage()'.
Unfortunately the constructor of ObjectInputStream attempts to read a header from the underlying stream (which is not very intuitive IMHO). So if the client fails to flush the data - the server may remain stuck on the line "in = new ObjectInputStream(socket.getInputStream())"...
As a side note it's usually better for a server to launch a thread per incoming client, but that's just a side remark (plus it obviously depends on requirements).
I found the problem. The communication on my net is too slow so it timeouts in getting inputstream. The solution has two parts. Flushing outputstream before getting inputstream. And set socket timout after streams are initialized.
serverside:
clientSocket = serverSocket.accept();
out = new ObjectOutputStream(clientSocket.getOutputStream());
out.flush()
in = new ObjectInputStream(clientSocket.getInputStream());
clientSocket.setSoTimeout(200);
In my server located in a android device , if the number number of clients exceeds a specific number then the server close the socket. But in my client(other android device) i get a force close. How can i handle it gracefully?
Here is the connect part on my client:
serverIpAddress = serverIp.getText().toString();
if (!serverIpAddress.equals(""))
{
try
{
InetAddress serverAddr = InetAddress.getByName(serverIpAddress);
SocketAddress sockaddr = new InetSocketAddress(serverAddr, 5000);
nsocket = new Socket();
nsocket.connect(sockaddr);
}catch(Exception e){
Log.i("Connect", "Connection Error");
}
if (nsocket.isConnected()){
score.setText("Your score is " + sc);
serverIp.setVisibility(View.GONE);
connectPhones.setVisibility(View.GONE);
enterIP.setVisibility(View.GONE);
Log.i("Connect", "Socket created, streams assigned");
Log.i("Connect", "Waiting for inital data..." + nsocket.isConnected());
receiveMsg();
}
Keep checking the socket connection is still open or not using isClosed() within an infinite loop, when server closes its connection, the isClosed() gets true, and then display a message or toast giving your desired reason to the user.
Sounds like whatever you are using to read the socket is a blocking read, and throws an exception when the socket closes and it is stuck at that read. Make sure that read is in a try block, and use the catch/finally to gracefully exit whatever you are doing at that moment.
I have a problem where there is no IOException thrown when a Telnet client disconnects.
I used the server code from the following source:
http://java.sun.com/developer/onlineTraining/Programming/BasicJava2/Code/SocketThrdServer.java
From the given code, the server should terminate and display "Read Fail" when the client close. But it's not happening for Telnet or Putty (RAW connection). On the contrary, it works when I used the example Client given, it works perfectly.
I've also tried modifying the code so that readLine() doesn't block the I/O always, but using a timeout. However, it doesn't seem that it helped in detecting whether the Client has been disconnected.
while (true) {
try {
client.setSoTimeout(1000);
line = in.readLine();
// Send data back to client
out.println(line);
textArea.append(line);
} catch (SocketTimeoutException ex) {
if(client.isClosed()) {
System.out.println("Client disconnected");
System.exit(-1);
}
} catch (Exception e) {
e.printStackTrace();
System.out.println("Read failed");
System.exit(-1);
}
}
Is there something missing from using Telnet or Raw Connection?
Edit: In addition to that, when I run 2 Clients, and then I close the first client, there would be no exception thrown from BufferedReader...
If it's a graceful shutdown, there should be no IO Exception.
in.readLine(); should return null in that case, a case your code should handle.