I have an app in java which is playing the rolle of a server .For limiting the number of incoming connections I'm using a ThreadPool server.
But I have a few problems understanding a part of the code:
Here is y code:
protected ExecutorService threadPool =
Executors.newFixedThreadPool(5);
public ThreadPooledServer(BlockingQueue queue,int port) {
this.serverPort = port;
this.queue=queue;
}
while (!isStopped()) {
Socket clientSocket = null;
try {
System.out.println("Serverul asteapta clienti spre conectare la port" +serverPort);
clientSocket = serverSocket.accept();
clientconnection++;
System.out.println("Serverul a acceptat clientul cu numarul:"
+ clientconnection);
} catch (IOException e) {
if (isStopped()) {
System.out.println("Server Stopped.");
return;
}
throw new RuntimeException("Error accepting client connection",
e);
}
WorkerRunnable workerRunnable = new WorkerRunnable(queue,clientSocket);
this.threadPool.execute(workerRunnable);
}
this.threadPool.shutdown();
System.out.println("Server Stopped.");
}
private synchronized boolean isStopped() {
return this.isStopped;
}
public synchronized void stop() {
this.isStopped = true;
try {
this.serverSocket.close();
}
catch (IOException e) {
throw new RuntimeException("Error closing server", e);
}
}
private void openServerSocket() {
try {
InetSocketAddress serverAddr = new InetSocketAddress(SERVERIP,
serverPort);
serverSocket = new ServerSocket();
serverSocket.bind(serverAddr);
} catch (IOException e) {
throw new RuntimeException("Cannot open port", e);
}
}
WHAT I don't understand:
I'm using a ThreadPooledServer which accepts for 5 incoming connections....
The connection with the clients is done in a while() loop.
while (!isStopped()) {
}
isStopped is a boolean variable returned byt this function:
private synchronized boolean isStopped() {
return this.isStopped;
}
which I call as a condition for starting the loop.
This boolean variable is initially set to false.....and is set back to true in the here:
public synchronized void stop() {
this.isStopped = true;
}
When is setup back to true my while() loop ends and then I close up all the workers of my thread pool.
this.threadPool.shutdown();
The problem is that I never call for this function " stop() "
Question: Is the function called automatically when I close my server?????...or I should call for it somewhere????
You need to call it somewhere in your code to stop your server and close those connections. If you don't the system will eventually reclaim its resources as the server will be shutting down.
You should be able to register a shutdown hook in the JVM (which can call stop()) to help with reclaiming those yourself... Good luck!
Related
I would like to create a network application where some devices have to send a packet to the same another device. This device is an Android one. My idea is to broadcast the message to the network so that the device will get it. I have checked on the Internet and I have found that one solution might be the MulticastSocket. I've followed the tutorial from the javadoc and this is quite easy. I did it on my Android phone and on one computer. The problem I have now is the fact that I want this socket to be bound on port 80. Effectively, I get an error, more precisely an EACCES when I try to create the socket. Here is the code of my server :
public class MyServer extends Thread {
private int port;
private boolean isRunning = true;
private MulticastSocket socket;
private InetAddress group;
public MyServer(int port) {
this.port = port;
isRunning = true;
}
public void run() {
socket = null;
try {
socket = new MulticastSocket(80);
group = InetAddress.getByName("coucou");
socket.joinGroup(group);
} catch (IOException e) {
e.printStackTrace();
return;
}
while (isRunning) {
DatagramPacket packet = new DatagramPacket(new byte[1024], 1024);
try {
socket.receive(packet);
Log.i("Server", "Packet received");
MyCipher rec = new MyCipher(Arrays.copyOfRange(packet.getData(), 0, packet.getLength()));
Receiver.getInstance().put(rec);
} catch (IOException e) {
e.printStackTrace();
}
}
socket.close();
}
public void mustStop() {
this.notify();
isRunning = false;
}
}
Does someone have an idea how to fix it ? Furthermore, does someone know if the name of the group must be the ip of the server or might it be a "random" string ?
Thank you !
I am writing an app on Android Studio.
I communicate from an Android device to an arduino board via Bluetooth.
For now everything works but i am starting a new Activity and i need to stop the actual BT connection. so i want to call a stop method.
The problem is that it crash when i call it.
here is the code
public class BtInterface {
private BluetoothDevice device = null;
private BluetoothSocket socket = null;
private InputStream receiveStream = null;
private OutputStream sendStream = null;
String GlobalBuff="";
String Right_Buff="";
private ReceiverThread receiverThread;
Handler handler;
public BtInterface(Handler hstatus, Handler h,String Device_Name) {
Set<BluetoothDevice> setpairedDevices = BluetoothAdapter.getDefaultAdapter().getBondedDevices();
BluetoothDevice[] pairedDevices = (BluetoothDevice[]) setpairedDevices.toArray(new BluetoothDevice[setpairedDevices.size()]);
for(int i=0;i<pairedDevices.length;i++) {
if(pairedDevices[i].getName().contains(Device_Name)) {
device = pairedDevices[i];
try {
socket = device.createRfcommSocketToServiceRecord(UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"));
receiveStream = socket.getInputStream();
sendStream = socket.getOutputStream();
} catch (IOException e) {
e.printStackTrace();
}
break;
}
}
handler = hstatus;
receiverThread = new ReceiverThread(h);
}
public void sendData(String data) {
sendData(data, false);
}
public void sendData(String data, boolean deleteScheduledData) {
try {
sendStream.write(data.getBytes());
sendStream.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
public void connect() {
new Thread() {
#Override public void run() {
try {
socket.connect();
Message msg = handler.obtainMessage();
msg.arg1 = 1;
handler.sendMessage(msg);
receiverThread.start();
} catch (IOException e) {
Log.v("N", "Connection Failed : " + e.getMessage());
e.printStackTrace();
}
}
}.start();
}
public void close() {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
socket=null; //???
}
public BluetoothDevice getDevice() {
return device;
}
private class ReceiverThread extends Thread {
Handler handler;
ReceiverThread(Handler h) {
handler = h;
}
#Override public void run() {
while(true) {
try {
if(receiveStream.available() > 0) {
byte buffer[] = new byte[1000];
int k = receiveStream.read(buffer, 0, 1000);
if(k > 0) {
byte rawdata[] = new byte[k];
for(int i=0;i<k;i++)
rawdata[i] = buffer[i];
String data = new String(rawdata);
GlobalBuff= GlobalBuff+data;
Right_Buff= GlobalBuff.substring(GlobalBuff.length()-1,GlobalBuff.length());
if(Right_Buff.equals("\n")){
Message msg = handler.obtainMessage();
Bundle b = new Bundle();
b.putString("receivedData", GlobalBuff);
msg.setData(b);
handler.sendMessage(msg);
GlobalBuff="";
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
i try some extra code :
receiverThread.interrupt();
receiverThread=null;
if (receiveStream != null) {
try {receiveStream.close();} catch (Exception e) {}
receiveStream = null;
}
if (sendStream != null) {
try {sendStream.close();} catch (Exception e) {}
sendStream = null;
}
before closing but the result is the same , it crash.
The strange behavior is that it didn't crash immediately as it could happen with a type error or else ( i am talking of the behavior in debug mode...)
If anybody got an idea.
Googling this bring me to people with this issue but no solution that works for my case.
Thanks
UPDATE
what i found as a trace when it crash is that :
06-02 07:45:27.369 9025-9133/fr.icservice.sechage A/libc? Fatal signal 11 (SIGSEGV) at 0x00000008 (code=1), thread 9133 (Thread-1436)
I also made a test on a sony Z3 phone under 5.0.2 (compare to my T210 samsung galaxy tab3 under 4.4.2)and it not crash..!
maybe it's a ROM bug?! or a android version problem...
This is a known problem (or bug?) on Android. If you close the Bluetooth socket and then access it later on, some devices will crash with a segmentation fault (like yours). A common workaround is to check socket.isConnected() before or to synchronize the access to close(), write(), read(), ... by setting a flag like closeWasCalled = true and prevent any further calls to methods of this socket in your code after a close() call.
The problem comes with Socket Input/Output. I faced this problem when disconnecting with peer bluetooth device.
Reason :
From code, we are trying to read() , write() from socket object/connection which is closed.
Solution :
Add checking socket.isConnected() before above operations
You can read more about this problem on Stack Overflow question : Here
When another thread calls closeConnection(), the thread doesn't reach
Log.d("Subscriber", "Client thread has ended.");
Why is this? What is the blocking behaviour of a stream that has been closed? I thought trying to write or flush to it would generate an IOException, but it seems the code is still blocking somewhere. Where? I can't find info on what happens when you interrupt() on a write, or what happens when writing to a closed outputstream.
public void closeConnection() {
try {
this.interrupt();
autoCloseOutputStream.close();
} catch (IOException e) {
Log.w("Subscriber", "IOException when closing stream. Buffer might not have been flushed to client.");
}
}
#Override
public void run() {
Log.d("Subscriber","Client thread has started.");
ByteBuffer pgnAndDataBytes=null;
while(true) {
try {
pgnAndDataBytes=fmsByteBufferSubscriberQueue.take();
} catch (InterruptedException e) {
break;
}
Log.d("Subscriber","Still running thread");
try {
autoCloseOutputStream.write(pgnAndDataBytes.array());
autoCloseOutputStream.flush();
} catch (IOException e) {
break;
}
}
Log.d("Subscriber", "Client thread has ended.");
}
The output is as follows:
Still running thread
Still running thread
Still running thread
Close called.
And nothing more. Where is it blocking and why?
Have a volatile boolean shouldClose that you set to true on closeConnect(). Incorporate the boolean into the condition check of the while loop.
boolean done = false;
while(!shouldClose && !done) {
try{
autoCloseOutputStream.write(pgnAndDataBytes.getInt());
} catch(BufferUnderflowException bue) {
final ArrayList<Byte> remainder = new ArrayList<Byte>(3);
while(!shouldClose && !done) {
try {
remainder.add(pgnAndDataBytes.get());
} catch(BufferUnderflowException ex) {
autoCloseOutputStream.write(remainder.toArray(new Byte[remainder.size()]);
done = true;
}
}
}
}
I'm developing an application for Android 4.03. The code of relevance is this:
public void startConnection() {
new Thread(new Runnable() {
#Override
public void run() {
try {
Log.i(LOG_TAG, "Beginning");
_socket = new Socket(_server, _port);
_socket.setSoTimeout(DEFAULT_SOCKET_TIMEOUT);
_writer = new BufferedWriter(new OutputStreamWriter(_socket.getOutputStream()));
_reader = new BufferedReader(new InputStreamReader(_socket.getInputStream()));
_in = new InputThread(_reader, new InputThreadObserver());
_in.start();
Log.i(LOG_TAG, "End");
} catch (UnknownHostException e) {
Log.i(LOG_TAG, "UnknownHostException");
} catch (IOException e) {
Log.i(LOG_TAG, "IOException");
}
}
}).start();
}
The creation of the socket is performed in a new thread, otherwise the execution freezes for few seconds.
If I set the variable _server to an existing host (for example www.google.com) everything goes all right. But if I set the _server variable to an host that does not exist (for example asd.asd) I really expect "UnknownHostException" to be printed in the logger. This does not happen (but the _socket variable is null). It just prints "Beginning" (and not "End"). Any Idea?
EDIT:
The variables are declared like this:
private String _server;
private Socket _socket;
private int _port;
private BufferedWriter _writer;
private BufferedReader _reader;
private InputThread _in;
EDIT:
I'm trying this:
public void startConnection() {
new Thread(new Runnable() {
#Override
public void run() {
try {
Log.i(LOG_TAG, "Beginning");
_socket = new Socket(_server, _port);
if (_socket == null)
Log.i(LOG_TAG, "NULL SOCKET! (test 1)");
} catch (Exception e) {
Log.i(LOG_TAG, "EXCEPTION!");
}
if (_socket == null)
Log.i(LOG_TAG, "NULL SOCKET! (test 2)");
}
}).start();
}
Don't know why but the output is only:
Beginning
EDIT:
After 3 minutes and 13 seconds waiting i finally got:
EXCEPTION!
NULL SOCKET! (test 2)
Is that normal? Shouldn't the UnknownHostException be thrown immediatly?
Looking at the API docs, if _server is a String, then you'll get an UnknownHost exception. If it's any of the other possibilities, you won't.
In particular this signature will create the exception:
Socket(String host,
int port)
throws UnknownHostException,
IOException
I have no idea what fails in this code because I have trouble reading the crash logs. We are not talking about a app-crash but a phone crash probably caused by either a deadlocked thread or a lock-up of some kind. Suggestions are welcomed!
Background:
When I initiate my connection a dialog shows and when I press the Back button the dialog freezes and after awhile the phone crashes...
Code:
This is the thread that handles the connection with the device. I have no issues connecting to a device at all. What I know is that mmSocket.connect() running when I press the back button. Think the problem lies there somewhere...
class ConnectThread extends Thread {
/**
*
*/
private Handler threadhandler;
private BluetoothDevice mmDevice;
private volatile BluetoothSocket mmSocket;
private Message toMain;
// private static final UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
public ConnectThread(Handler threadhandler, BluetoothDevice device) {
this.threadhandler = threadhandler;
this.mmDevice = device;
// Get a BluetoothSocket to connect with the given BluetoothDevice
try {
Method m = mmDevice.getClass().getMethod("createRfcommSocket", new Class[] {int.class});
mmSocket = (BluetoothSocket) m.invoke(mmDevice, 1);
}catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
public void run() {
Looper.prepare();
try {
// Connect the device through the socket. This will block
// until it succeeds or throws an exception
mmSocket.connect();
toMain = threadhandler.obtainMessage();
toMain.arg1 = 1;
threadhandler.sendMessage(toMain);
} catch (SecurityException e) {
Log.e("SecurityExcep", "Oh noes" , e);
toMain = threadhandler.obtainMessage();
toMain.arg1 = 2;
threadhandler.sendMessage(toMain);
Log.w("MESSAGE", e.getMessage());
}catch (IOException e) {
//Bad connection, let's get the hell outta here
try {
Log.e("IOExcep", "Oh noes" , e);
Log.w("MESSAGE", e.getMessage());
mmSocket.close();
toMain = threadhandler.obtainMessage();
toMain.arg1 = 2;
toMain.obj = e.getMessage();
threadhandler.sendMessage(toMain);
return;
} catch (IOException e1) {
Log.e("IOExcep2", "Oh noes" , e);
}
}
try {
mmSocket.close();
} catch (IOException e) {
Log.d("CONNECT_CONSTRUCTOR", "Unable to close the socket", e);
}
toMain = threadhandler.obtainMessage();
toMain.arg1 = 3;
threadhandler.sendMessage(toMain);
Looper.loop();
return;
// Now it should be paired.. only thing to do now is let the user commit to the rest
}
/** Will cancel an in-progress connection, and close the socket */
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) { }
}
}
Next code is a snippet from the dialog creator, the thread is called d:
(...)
case DIALOG_BT_ADDING:
search_dialog = new ProgressDialog(this);
search_dialog.setTitle(R.string.adding);
search_dialog.setMessage(res.getText(R.string.bluetooth_add_accept));
search_dialog.setIndeterminate(true);
search_dialog.setCancelable(true);
search_dialog.setOnCancelListener(new OnCancelListener() {
#Override
public void onCancel(DialogInterface dialog) {
Log.i("THREAD CONNECT", "Is it alive?: " + d.isAlive());
if(d != null && d.isAlive()){
d.cancel();
//d = null;
}
if(d2 != null && d2.isAlive()){
d2.cancel(false);
//d2 = null;
}
search_dialog.dismiss();
showDialog(DIALOG_NEW_DEVICE_FOUND);
}
});
return search_dialog;
(...)
Here is a snippet of the code executing the ConnectThread-class
private void connectBluetooth(boolean nextstage, IOException e1){
if(!nextstage){
showDialog(DIALOG_BT_ADDING);
d = new ConnectThread(threadhandler, selected_car.getDevice());
d.start();
}
else{
if(e1 != null){
d2 = new BluetoothCheckThread(checkthreadhandler,mBluetoothAdapter,
5000, car_bt, after_bt);
d2.start();
search_dialog.dismiss();
}
else{
showDialog(DIALOG_BT_ADDING_FAILED);
}
}
}
Hope you guys can help me!, thanks for any feedback
Okay, you're calling BluetoothSocket.close() from what looks like the UI thread. This is probably causing the "freeze".
When you say the phone "crashes" do you mean it reboots? If so is this a full reboot (screen goes back to what happens when you first turn the phone on) or a runtime restart (phone typically shows some sort of animation, on Nexus devices, its the four-color particle spray)? If its not a reboot, do you mean you just get a dialog allowing you to kill the app?
In either case you may want to get a reference to the Thread that is calling BluetoothSocket.connect() and call Thread.interrupt(). I'm not sure if a BluetoothSocket is interruptible, but let's hope. Then after interrupting, call close(), which probably shouldn't be called on the main thread.
try to use dialog.setOnKeyListener() in that on keyCode_BACK cancel the thread. try this will work.
It looks like you're calling connect and close on BluetoothSocket which is a "no no". It seems to cause a deadlock. See this link for more info.