Can't detect the socket is disconnected [duplicate] - java

This question already has answers here:
JAVA : Handling socket disconnection
(4 answers)
Closed 5 years ago.
Hi this is my code for sending data through a socket to another device connected to the network
try {
PrintWriter printWriter = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true);
printWriter.print(data);
Log.d("error", printWriter.checkError() + "");
printWriter.flush();
} catch (IOException e) {
Log.d("socket","is disconnected");
e.printStackTrace();
}
the problem is printWriter.checkError() is always returning false and the IOException never happens. for disconnecting socket I'm turning device off and trying to send data again. even reading from InputStream doesn't help
private class SocketHandler extends AsyncTask<Void, byte[], Void> {
InputStream in;
#Override
protected void onPreExecute() {
try {
in = socket.getInputStream();
} catch (IOException e) {
e.printStackTrace();
}
super.onPreExecute();
}
#Override
protected Void doInBackground(Void... voids) {
byte[] content = new byte[2048];
if (in != null) {
while (true) {
try {
if (in.available() > 0) {
int n = in.read(content);
if (n == -1) {
break;
}
publishProgress(new byte[][]{Arrays.copyOfRange(content, 0, n)});
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
return null;
}
#Override
protected void onProgressUpdate(byte[]... values) {
String data = new String(values[0]);
super.onProgressUpdate(values);
}
#Override
protected void onPostExecute(Void aVoid) {
Log.d("socket", "is disconnected");
}
}
read never returns -1 so I can detect the socket is disconnected. What can I do?
edit: It's not duplicate of JAVA : Handling socket disconnection because I did everything mentioned there

I had the same problem. I used a timer to send connection check command every second in both side and in that timer I checked the last time that I received this connection check command and if it's over for example 10 seconds, then I decided that the socket is disconnected
tOut = new Timer();
tOut.schedule(new TimerTask() {
#Override
public void run() {
long dif = System.currentTimeMillis() - lastCCReceivedTime;
if (dif > 1000 * 10) {
// socket is disconnected
return;
}
try {
out.println("Connection check");
} catch (Exception e) {
if (out != null)
out.close();
// socket is disconnected
}
}
}, 1000, 1000);
Save the last time that the command was received
while ((msg = in.readLine()) != null) {
lastCCReceivedTime = System.currentTimeMillis();
//Message received
}

if (in.available() > 0) {
You never call read() unless there is data available to be read without blocking.
int n = in.read(content);
if (n == -1) {
break;
Unreachable.
}
And here if available() was zero you do nothing except spin mindlessly smoking the CPU.
Cure: remove the available() test. It isn't doing anything useful, and it is preventing you from detecting end of stream.

Related

Send messages to Handler from other activity

I Have a code that connects to a bluetooth device, opens a bluetooth socket that communicates with a running thread which operates functions running in main activity.
I would like to move all the connecting sequence to another activity, and then operate the thread from the main one as done now. The problem is they are all connected.
I would like to have the option of sending a message between these activities(meaning remaining the socket operating from the other activity), i.e this message:
mHandler.obtainMessage(CONNECTING_STATUS, 1, -1, name)
.sendToTarget();
because it is impossible to pass handler between activities I don't know how/if possible to do so.
What is the best way of doing such a thing?
added part of the code.
Thanks.
mHandler = new Handler(){
public void handleMessage(android.os.Message msg){
if(msg.what == MESSAGE_READ){
String readMessage = null;
try {
readMessage = new String((byte[]) msg.obj, "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
RxMessage = readMessage.split(" ");
if (sH.isStringInCorrectOrder(RxMessage,Weight))
populateListView(RxMessage);
mReadBuffer.setText(readMessage);
}
if(msg.what == CONNECTING_STATUS){
if(msg.arg1 == 1)
mBluetoothStatus.setText("Connected to Device: " + (String)(msg.obj));
else
mBluetoothStatus.setText("Connection Failed");
}
}
};
private void connectBT (){
mBluetoothStatus.setText("Connecting...");
// Get the device MAC address, which is the last 17 chars in the View
final String address = "98:D3:31:30:39:75";
final String name = "HC-06";
// Spawn a new thread to avoid blocking the GUI one
new Thread()
{
public void run() {
boolean fail = false;
BluetoothDevice device = mBTAdapter.getRemoteDevice(address);
try {
mBTSocket = createBluetoothSocket(device);
} catch (IOException e) {
fail = true;
Toast.makeText(getBaseContext(), "Socket creation failed", Toast.LENGTH_SHORT).show();
}
// Establish the Bluetooth socket connection.
try {
mBTSocket.connect();
} catch (IOException e) {
try {
fail = true;
mBTSocket.close();
mHandler.obtainMessage(CONNECTING_STATUS, -1, -1)
.sendToTarget();
} catch (IOException e2) {
//insert code to deal with this
Toast.makeText(getBaseContext(), "Socket creation failed", Toast.LENGTH_SHORT).show();
}
}
if(fail == false) {
mConnectedThread = new ConnectedThread(mBTSocket);
mConnectedThread.start();
mHandler.obtainMessage(CONNECTING_STATUS, 1, -1, name)
.sendToTarget();
}
}
}.start();
}
private class ConnectedThread extends Thread {
private final BluetoothSocket mmSocket;
private final InputStream mmInStream;
private final OutputStream mmOutStream;
public ConnectedThread(BluetoothSocket socket) {
mmSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
// Get the input and output streams, using temp objects because
// member streams are final
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) { }
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
public void run() {
byte[] buffer = new byte[1024]; // buffer store for the stream
int bytes; // bytes returned from read()
// Keep listening to the InputStream until an exception occurs
while (true) {
try {
// Read from the InputStream
bytes = mmInStream.available();
if(bytes != 0) {
SystemClock.sleep(100); //pause and wait for rest of data. Adjust this depending on your sending speed.
bytes = mmInStream.available(); // how many bytes are ready to be read?
bytes = mmInStream.read(buffer, 0, bytes); // record how many bytes we actually read
mHandler.obtainMessage(MESSAGE_READ, bytes, -1, buffer)
.sendToTarget(); // Send the obtained bytes to the UI activity
}
} catch (IOException e) {
e.printStackTrace();
break;
}
}
}
/* Call this from the main activity to send data to the remote device */
public void write(String input) {
byte[] bytes = input.getBytes(); //converts entered String into bytes
try {
mmOutStream.write(bytes);
} catch (IOException e) { }
}
/* Call this from the main activity to shutdown the connection */
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) { }
}
}
Just declare mHandler as static and you can access it from all other activities. This will create a small temporary memory leak, but don't worry about it.

Android socket implementation with AsyncTask force close

I'm facing with an issue when try to send 'signal' to my AsyncTask class to stop execution and close socket connection. In doInBackground method I setting up socket connection, sending first payload packet and waiting for incoming packets:
mRunning = true;
try {
byte[] data = null;
mSocket = mTlsSocketFactory.createSocket(mTlsSocketFactory.getServerAddress(), mTlsSocketFactory.getServerPort());
LogHelper.printLogMsg("INFO socket created");
out = new DataOutputStream(mSocket.getOutputStream());
out.flush();
inStream = new DataInputStream(mSocket.getInputStream());
//send authenticate payload
requestSendPayload(authenticatePayload, params);
while (mRunning) {
int type = inStream.readInt();
type = Integer.reverseBytes(type);
mResID = type;
int length = inStream.readInt();
length = Integer.reverseBytes(length);
if (length > 0) {
data = new byte[length];
inStream.readFully(data);
publishProgress(data);
}
data = null;
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (out != null) out.close();
if (inStream != null) inStream.close();
if (mSocket != null) mSocket.close();
} catch (IOException e) {
e.fillInStackTrace();
}
}
When I receive packet that I want, I should close connection. I have a public method inside AsyncTask class:
public void close() {
mRunning = false;
}
But the problem is that 'while' block never ends and doInBackground never finished.
There is a lot of posts with similar problem but I tried to call cancel(true) on my AsyncTask but with no result - doInBackground never finished. My question is how to send 'signal' to doInBackground method so that my while loop be able to finish?
I can rewrite closeMethod to something like this:
new Thread(new Runnable() {
#Override
public void run() {
try {
if (out != null) out.close();
if (inStream != null) inStream.close();
if (mSocket != null) mSocket.close();
} catch (IOException e) {
e.fillInStackTrace();
}
}
}).start();
And after that, I catch exception when try to read: DataInputStream.readInt() and then doInBackground will end. But I'm not sure if this is the correct solution.
You should implement OnCancelled in your async task method
#Override
protected void onCancelled() {
mRunning = false;
}
after that you just call
mySocketAsyncTaskObject.cancel(false);
Another option would be to remove your mRunning property and OnCancelled override and just check for IsCancelled()
while (!IsCancelled()) {
int type = inStream.readInt();
type = Integer.reverseBytes(type);
mResID = type;
int length = inStream.readInt();
length = Integer.reverseBytes(length);
if (length > 0) {
data = new byte[length];
inStream.readFully(data);
publishProgress(data);
}
data = null;
}
As a personal note, i want to add, that it is good practice to use Service class for incapsulation your Socket functionality and use plain Thread object not AsyncTask

InputStream is not working properly

I am a beginner in android. I am trying to work on Sockets. But my InputStream is not reading the data as expected. It is getting out of the method after j = inputStream.read(arrayOfByte, 0, i); Please help me.
public void readinputstreamforid(final String ip, final int port){
AsyncTask asyncTask = new AsyncTask() {
#Override
protected Object doInBackground(Object[] objects) {
try {
socket=new Socket(ip,port);
} catch (IOException e) {
e.printStackTrace();
}
final byte[] arrayOfByte = new byte[10000];
InputStream inputStream = null;
try {
inputStream = socket.getInputStream();
} catch (IOException e) {
e.printStackTrace();
}
while (socket.isConnected()) {
int j = 0;
int i = arrayOfByte.length;
try {
j = inputStream.read(arrayOfByte, 0, i);
if (j == -1)
throw new IOException("not working");
if (j == 0)
continue;
} catch (IOException e) {
e.printStackTrace();
}
final String strData = new String(arrayOfByte, 0, j).replace("\r", "").replace("\n", "");
Log.d("hello","recieved: "+strData);
}
try {
IOUtils.write("!##\n",socket.getOutputStream());
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
};
asyncTask.execute();
}
If an error happens, you are logging it, but then you continue with the code, where more errors can then happen. When an error happens, STOP looping and exit the function. InputStream.read() returns -1 when the end of the stream is reached. For a socket, that means when the connection is closed. That is not really an error condition, so you don't need to throw an exception. Just break the loop. You can wrap the InputStream inside of a BufferedReader so you can use its readLine() method instead of reading bytes manually.
Also, you are trying to write to the socket's OutputStream after the socket has already disconnected. That will never work.
Try something more like this:
public void readinputstreamforid(final String ip, final int port){
AsyncTask asyncTask = new AsyncTask() {
#Override
protected Object doInBackground(Object[] objects) {
try {
socket = new Socket(ip, port);
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream(), StandardCharsets.UTF_8));
OutputDataStream out = socket.getOutputStream();
do {
String data = in.readLine();
if (data == null)
break;
Log.d("hello", data);
IOUtils.write("!##\n", out, StandardCharsets.UTF_8);
}
while (true);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
};
asyncTask.execute();
}

Socket's input stream still gets data after I closed the other side socket

Socket's methods do not appear to function in the way their names or documentation suggest. For example. I create a client socket to connect a remote serversocket. When the connection establishes, the serversocket.accept() method returns a corresponding socket which to getinputstream from the client socket. But the problem is, if I close the client socket, the socket on the server still returns false for the isClosed() method; and, more absurdly, the Socket's InputStream on the server starts to continuously return value and no longer blocks when the client socket has closed and sending no output to the server. Below is my code:
Client code:
public class MainActivity extends AppCompatActivity {
private Button startButton, stopButton;
public byte[] buffer;
public Socket socket;
public Socket tempSocket;
private int port = 50005;
InetSocketAddress address;
private int r_port = 50006;
AudioRecord recorder;
AudioTrack audioTrack;
private int sampleRate = 16000; // 44100 for music
private int channelConfig = AudioFormat.CHANNEL_IN_MONO;
private int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
int minBufSize = AudioRecord.getMinBufferSize(sampleRate, channelConfig, audioFormat);
public static boolean s_status = true;
public static boolean r_status = true;
Thread r_Thread;
Thread s_Thread;
private boolean isPlay = true;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
startButton = (Button) findViewById(R.id.start_button);
startButton.setOnTouchListener(talkListener);
if (socket == null) {
socket = new Socket();
address = new InetSocketAddress("192.168.0.2", port);
try {
socket.setReuseAddress(true);
System.out.println("connecting-");
} catch (IOException e) {
e.printStackTrace();
}
}
}
private final View.OnTouchListener talkListener = new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
startButton.setBackgroundColor(Color.parseColor("#0670c0"));
try {
startStreamings();
} catch (Exception e) {
e.printStackTrace();
}
return true; // if you want to handle the touch event
case MotionEvent.ACTION_UP:
startButton.setBackgroundColor(Color.parseColor("#353535"));
try {
s_status = false;
} catch (Exception e) {
e.printStackTrace();
return true; // if you want to handle the touch event
}
}
return false;
}
};
public void startStreamings(){
s_status=true;
buffer = new byte[minBufSize];
s_Thread = new Thread(new Runnable() {
#Override
public void run() {
if (socket == null) {
try {
socket = new Socket();
socket.setReuseAddress(true);
} catch (IOException e) {
e.printStackTrace();
}
}
if (!socket.isConnected()) {
try {
socket.connect(address);
System.out.println("create new connection in startStreaming");
} catch (IOException e) {
e.printStackTrace();
}
}
recorder = new AudioRecord(MediaRecorder.AudioSource.MIC, sampleRate, channelConfig, audioFormat, minBufSize * 10);
try {
if (s_status == true) {
recorder.startRecording();
}
} catch (IllegalStateException e) {
e.printStackTrace();
return;
}
OutputStream os = null;
while (s_status == true) {
//reading data from MIC into buffer
recorder.read(buffer, 0, buffer.length);
try {
os = socket.getOutputStream();
os.write(buffer, 0, minBufSize);
} catch (Exception e) {
e.printStackTrace();
s_status = false;
}
//System.out.println("streaming out: " + buffer.length + "fff" + c++);
}
if (recorder != null) {
recorder.stop();
recorder.release();
recorder = null;
}
}
});
s_Thread.start();
}
}
Server code:
public TcpServerSocket(){
}
public static void main(String args[]) throws Exception {
ServerSocket serverSocket = new ServerSocket(port);
sockets = new ArrayList<Socket>();
while(isListenning){
Socket socket = serverSocket.accept();
isMatched = false;
for(int i =0;i<sockets.size();i++){
Socket preSocket = sockets.get(i);
if(preSocket.getInetAddress().equals(socket.getInetAddress())){
sockets.remove(preSocket);
sockets.add(socket);
isMatched = true;
}
}
if(!isMatched){
sockets.add(socket);
socket.setKeepAlive(false);
new Thread(new TcpServerSocket(socket)).start();
System.out.println("new Connection");
}
}
serverSocket.close();
}
#Override
public void run() {
byte[] receiveData = new byte[1280];
byte[] emptyData = new byte[1280];
InputStream baiss = null;
OutputStream os;
while (isRunning){
try {
baiss = csocket.getInputStream();
if(csocket.isClosed()||!csocket.isConnected()){
isRunning = false;
sockets.remove(csocket);
System.out.println("socket closed!");
}
int numOfBytes = baiss.read(receiveData);
if(numOfBytes==-1){
isRunning=false;
sockets.remove(csocket);
csocket.close();
System.out.println("socket closed!");
}
} catch (IOException e) {
sockets.remove(csocket);
System.out.println("socket closed!");
e.printStackTrace();
}
int socketsLen = sockets.size();
for(int i = 0;i<socketsLen;i++){
Socket client = sockets.get(i);
if(!client.getInetAddress().equals(csocket.getInetAddress())){
try {
os = client.getOutputStream();
os.write(receiveData,0,1280);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}else if(!client.equals(csocket)){
csocket = client;
System.out.println("switched!");
}
}
System.out.println(csocket.getInetAddress().toString()+"fff"+socketsLen);
}
try {
baiss.close();
csocket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Can you guys give me any suggestions to close the client socket perfectly so I won't keep getting input after I close the client? Any help is much appreciated!
socket.getInputStream() still get data after I closed the other side socket
That could be because there was still data in transit that hadn't been read yet. Closing a connection doesn't abort pending data transfers. But as it turns out, it doesn't get data at all. There is simply a bug in your code.
I am really upset with socket in recent days.
I suggest you get over being upset and adopt a rational attitude towards your chosen profession.
I find socket's methods just do not function in the way their names or documentations suggest.
Let's see.
For example. I create a client socket to connect a remote serversocket. When the connection establishes,the serversocket.accept() method returns a corresponding socket which to getinputstream from the client socket. But the problem is, if I close the client socket, the socket on the server still returns true for the isClosed() method
No it doesn't. It returns false. The server's socket is still open. The client's socket is closed, and so is the connection, but isClosed() tells you about the state of the socket it is called on, not anything else, and specifically not the connection.
and more absurd, the socket.getInputStream() on the server starts to continuously return value and no longer blocks when the client socket has closed and sending no outputstream to the server.
Only if there was data in flight before the peer closed. Otherwise it is due to a bug in your code, and here it is:
//reading data from MIC into buffer
recorder.read(buffer, 0, buffer.length);
read() returns -1 at end of stream, and you are ignoring it. That's why you get a continous loop. The correct way to write this code is as follows:
int count = recorder.read(buffer, 0, buffer.length);
if (count == -1) {
recorder.close();
socket.close();
break;
}
try {
os = socket.getOutputStream();
os.write(buffer, 0, count);
You have a similar problem with your client code. You just don't seem to care about end of stream:
baiss = csocket.getInputStream();
if(csocket.isClosed()||!csocket.isConnected()){
isRunning = false;
sockets.remove(csocket);
System.out.println("socket closed!");
}
baiss.read(receiveData);
// ...
os = client.getOutputStream();
os.write(receiveData,0,1280);
The correct way to write this is as follows:
baiss = csocket.getInputStream();
int count = baiss.read(receiveData);
if(count == -1){
isRunning = false;
sockets.remove(csocket);
System.out.println("socket closed!");
}
// ...
os = client.getOutputStream();
os.write(receiveData, 0, count);
Can you guys give me any suggestions to close the client socket perfectly so I won't keep getting input after I close the client?
You are closing it perfectly. The problem is that you aren't detecting it correctly at the other end.

BufferedReader , readLine operates at half

Hello i try to read a number undetermined of lines(between 1 and 150, each lines is vontaines in a packet, and a packet contains 1 number and 1 text) with my java app(when the connexion between the client ans the server is established) but it seems its work at half. I receive only between 2 and 3 lines, can somebody can help me ?
class test implements Runnable {
#Override
public void run() {
try {
while(true){
DataInputStream reader = new DataInputStream(socket.getInputStream());
BufferedReader inFromClient = new BufferedReader(new InputStreamReader(socket.getInputStream()));
int tailleMessage = reader.readUnsignedShort();
if (reader.available() < tailleMessage ){
return;
}
while (( messagep = inFromClient.readLine()) != null){
tailleMessage = reader.readUnsignedShort();
final String azrty = messagep;
if(!azrty.isEmpty()){
mHandler.post(new Runnable() {
#Override
public void run() {
Chat.TextChat.append("\n"+azrty);
}
});
}
}
}
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
catch (Exception e) {
e.printStackTrace();
Log.d("erreur",e.toString());
}
}
}
You can't use both a BufferedReader and another input stream at the same time on a Socket. The buffer will 'steal' data from the input stream. You need to redesign your protocol accordingly. Possibly you should use writeUTF()/readUTF() to send the strings, instead of sending them as lines. Or is sibyl you should be using ObjectInput/OutputStreams.

Categories

Resources