I'm setting up a USB accessory connection between my Android phone and another device. Just sending bytes back and forth for now to test. I get some definite communication going at first, but it always ends up dying with Java.io.IOException: write failed: EBADF (Bad file number)" after a second or so. Sometimes the reading stays alive but the writing dies; others both die.
I'm not doing anything super fancy, reading and writing just like the Google documentation:
Initial connection (inside a broadcast receiver, I know this part works at least initially):
if (action.equals(ACTION_USB_PERMISSION))
{
ParcelFileDescriptor pfd = manager.openAccessory(accessory);
if (pfd != null) {
FileDescriptor fd = pfd.getFileDescriptor();
mIn = new FileInputStream(fd);
mOut = new FileOutputStream(fd);
}
}
Reading:
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
byte[] buf = new byte[BUF_SIZE];
while (true)
{
try {
int recvd = mIn.read(buf);
if (recvd > 0) {
byte[] b = new byte[recvd];
System.arraycopy(buf, 0, b, 0, recvd);
//Parse message
}
}
catch (IOException e) {
Log.e("read error", "failed to read from stream");
e.printStackTrace();
}
}
}
});
thread.start();
Writing:
synchronized(mWriteLock) {
if (mOut !=null && byteArray.length>0) {
try {
//mOut.flush();
mOut.write(byteArray, 0, byteArray.length);
}
catch (IOException e) {
Log.e("error", "error writing");
e.printStackTrace();
return false;
}
}
else {
Log.e(TAG, "Can't send data, serial stream is null");
return false;
}
}
Error stacktrace:
java.io.IOException: write failed: EBADF (Bad file number)
W/System.err(14028): at libcore.io.IoBridge.write(IoBridge.java:452)
W/System.err(14028): at java.io.FileOutputStream.write(FileOutputStream.java:187)
W/System.err(14028): at com.my.android.transport.MyUSBService$5.send(MyUSBService.java:468)
W/System.err(14028): at com.my.android.transport.MyUSBService$3.onReceive(MyUSBService.java:164)
W/System.err(14028): at android.app.LoadedApk$ReceiverDispatcher$Args.run(LoadedApk.java:781)
W/System.err(14028): at android.os.Handler.handleCallback(Handler.java:608)
W/System.err(14028): at android.os.Handler.dispatchMessage(Handler.java:92)
W/System.err(14028): at android.os.Looper.loop(Looper.java:156)
W/System.err(14028): at android.app.ActivityThread.main(ActivityThread.java:5045)
W/System.err(14028): at java.lang.reflect.Method.invokeNative(Native Method)
W/System.err(14028): at java.lang.reflect.Method.invoke(Method.java:511)
W/System.err(14028): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
W/System.err(14028): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
W/System.err(14028): at dalvik.system.NativeStart.main(Native Method)
W/System.err(14028): Caused by: libcore.io.ErrnoException: write failed: EBADF (Bad file number)
W/System.err(14028): at libcore.io.Posix.writeBytes(Native Method)
W/System.err(14028): at libcore.io.Posix.write(Posix.java:178)
W/System.err(14028): at libcore.io.BlockGuardOs.write(BlockGuardOs.java:191)
W/System.err(14028): at libcore.io.IoBridge.write(IoBridge.java:447)
W/System.err(14028): ... 13 more
I have logging all over the place and thus I know it's not anything too obvious, such as another permission request being received (and thus the file streams being reinitialized mid-read). The streams aren't closing either, because I never have that happen anywhere in my code (for now). I'm not getting any detached or attached events either (I log that if it happens). Nothing seems too out of the ordinary; it just dies.
I thought maybe it was a concurrency issue, so I played with locks and sleeps, nothing worked that I tried. I don't think it's a throughput issue either because it still happens when I sleep every read (on both ends), and read one single packet at a time (super slow bitrate). Is there a chance the buffer is being overrun on the other end somehow? How would I go about clearing this? I do have access to the other end's code, it is an Android device as well, using Host mode. In case that it matters, I can post that code too - standard bulk transfers.
Does the phone just have lackluster support for Android Accessory Mode? I've tried two phones and they both fail similarly, so I doubt it's that.
I'm wondering what causes this error in general when writing or reading from USB on Android?
I got same problem in my code, and I found that it happens because FileDescriptor object was GCed.
I fixed this issue by adding ParcelFileDescriptor field in Activity(or Service).
I checked your first code snippet and the code you based on, and latter has ParcelFileDescriptor field in Thread.
I think if you edit your code like below, it works well.
ParcelFileDescriptor mPfd;
...
if (action.equals(ACTION_USB_PERMISSION))
{
mPfd = manager.openAccessory(accessory);
if (mPfd != null) {
FileDescriptor fd = mPfd.getFileDescriptor();
mIn = new FileInputStream(fd);
mOut = new FileOutputStream(fd);
}
}
It ended up being a threading issue. I needed to more properly segregate even writing as well, instead of just reading.
I ended up using this code as a basis.
OK, a few things I noticed that just seemed different from what I do for Open Accessory Mode, which I followed the documentation for USB accessory mostly, so it should be very similar, is that your mIn.read(buf); should be mIn.read(buf, 0, 64); as far as I know.
Also, you should declare in your class declarations thread myThread;. Then within your BroadcastReceiver after creating the new FileInput/OutputStream, have myThread = new thread(myHandler, myInputStream); followed my myThread.start();.
Now I noticed that you are communicating directly with the UI from your thread. You should use a handler instead that the thread will communicate to and then that will communicate back to your UI, at least from what I had read.
Here is an example of my handler and thread:
final Handler mHandler = new Handler() {
#Override
public void handleMessage(Message msg){
}
};
private class USB_Thread extends Thread {
Handler thisHandler;
FileInputStream thisInputStream;
USB_Thread(Handler handler, FileInputStream instream){
thisHandler = handler;
thisInputStream = instream;
}
#Override
public void run(){
while(true) {
try{
if((thisInputStream != null) && (dataReceived == false)) {
Message msg = thisHandler.obtainMessage();
int bytesRead = thisInputStream.read(USB_Data_In, 0, 63);
if (bytesRead > 0){
dataReceived = true;
thisHandler.sendMessage(msg);
}
}
}
catch(IOException e){
}
}
}
}
Also, there are some demo open accessory application here. They may help with your understanding of accessory mode.
And also there are known issues with an application not receiving the BroadcastReceiver for ACTION_USB_ACCESSORY/DEVICE_ATTACHED programmatically. It will only receive it via the manifest file. You can find more on this here and here.
I actually didn't test putting the dataReceived variable in the handler and only recently changed that part of my code. I tested it and it didn't work, so trying to remember what it was I had read, I think it was not about variables communicating within the threads, but trying to use something like .setText(). I have updated my code to include the dataReceived=true in the thread. The handler would then be used for updating items on the UI, such as TextViews, etc.
Thread
FileDescriptor fd = mFileDescriptor.getFileDescriptor();
mInputStream = new FileInputStream(fd);
mOutputStream = new FileOutputStream(fd);
usbThread = new USB_Thread(mHandler, mInputStream);
usbThread.start();
Related
In my client I receive via ZeroMQ a lot of input, which needs to be constantly updated. My server is written in python, but that should not matter. So this is what I do in my MainActivity:
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
/********************************NETWORK********************************/
new NetworkCall().execute("");
}
private class NetworkCall extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... params) {
while (true) {
try {
ZMQ.Context context = ZMQ.context(1);
// Connect to server
ZMQ.Socket requester = context.socket(ZMQ.REQ);
String address = "tcp://xxx.xx.xx.xx";
int port = 5000;
requester.connect(address + ":" + port);
// Initialize poll set
ZMQ.Poller poller = new ZMQ.Poller(1);
poller.register(requester, ZMQ.Poller.POLLIN);
requester.send("COORDINATES");
//while (true) {
String data;
poller.poll();
data = requester.recvStr();
System.out.println(data);
if (data == null) {
try {
sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
} requester.close();
} catch (IllegalStateException ise) {
ise.printStackTrace();
}
}
}
#Override
protected void onPostExecute(String result) {
}
#Override
protected void onPreExecute() {
}
#Override
protected void onProgressUpdate(Void... values) {
}
}
}
After executing this code on my device, I'll get like 5-9 input data strings, which I receive from the server, but then the following exception appears:
E/AndroidRuntime: FATAL EXCEPTION: AsyncTask #2
Process: com.example.viktoria.gazefocus, PID: 31339
java.lang.RuntimeException: An error occurred while executing doInBackground()
at android.os.AsyncTask$3.done(AsyncTask.java:353)
at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:383)
at java.util.concurrent.FutureTask.setException(FutureTask.java:252)
at java.util.concurrent.FutureTask.run(FutureTask.java:271)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:245)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
at java.lang.Thread.run(Thread.java:764)
Caused by: com.example.viktoria.gazefocus.zmq.ZError$IOException: java.io.IOException: Too many open files
at com.example.viktoria.gazefocus.zmq.Signaler.makeFdPair(Signaler.java:94)
at com.example.viktoria.gazefocus.zmq.Signaler.<init>(Signaler.java:50)
at com.example.viktoria.gazefocus.zmq.Mailbox.<init>(Mailbox.java:51)
at com.example.viktoria.gazefocus.zmq.Ctx.<init>(Ctx.java:128)
at com.example.viktoria.gazefocus.zmq.ZMQ.zmq_ctx_new(ZMQ.java:244)
at com.example.viktoria.gazefocus.zmq.ZMQ.zmqInit(ZMQ.java:277)
at org.zeromq.ZMQ$Context.<init>(ZMQ.java:269)
at org.zeromq.ZMQ.context(ZMQ.java:254)
at com.example.viktoria.gazefocus.MainActivity$NetworkCall.doInBackground(MainActivity.java:73)
at com.example.viktoria.gazefocus.MainActivity$NetworkCall.doInBackground(MainActivity.java:67)
at android.os.AsyncTask$2.call(AsyncTask.java:333)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:245)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
at java.lang.Thread.run(Thread.java:764)
Caused by: java.io.IOException: Too many open files
at sun.nio.ch.IOUtil.makePipe(Native Method)
at sun.nio.ch.PipeImpl.<init>(PipeImpl.java:42)
at sun.nio.ch.SelectorProviderImpl.openPipe(SelectorProviderImpl.java:50)
at java.nio.channels.Pipe.open(Pipe.java:155)
at com.example.viktoria.gazefocus.zmq.Signaler.makeFdPair(Signaler.java:91)
at com.example.viktoria.gazefocus.zmq.Signaler.<init>(Signaler.java:50)
at com.example.viktoria.gazefocus.zmq.Mailbox.<init>(Mailbox.java:51)
at com.example.viktoria.gazefocus.zmq.Ctx.<init>(Ctx.java:128)
at com.example.viktoria.gazefocus.zmq.ZMQ.zmq_ctx_new(ZMQ.java:244)
at com.example.viktoria.gazefocus.zmq.ZMQ.zmqInit(ZMQ.java:277)
at org.zeromq.ZMQ$Context.<init>(ZMQ.java:269)
at org.zeromq.ZMQ.context(ZMQ.java:254)
at com.example.viktoria.gazefocus.MainActivity$NetworkCall.doInBackground(MainActivity.java:73)
at com.example.viktoria.gazefocus.MainActivity$NetworkCall.doInBackground(MainActivity.java:67)
at android.os.AsyncTask$2.call(AsyncTask.java:333)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:245)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
at java.lang.Thread.run(Thread.java:764)
Apparently too many files are open. After research (I'm using Ubuntu 16.04) I changed the ulimit with ulimit -n 10000. Still this exception will happen. Sometimes I get more input data, sometimes less. Also if I set something like Executor executor = Executors.newFixedThreadPool(5); into the onCreate() method, nothing will change.
How to overcome this issue?
Thanks for reading!
You have a leak because you're not closing / ending / freeing something. I think that the context has to be terminated: context.term() after you close the requester...
Well, in distributed-system design, the infrastructure for signalling / messaging setup costs are not negligible. Some use-cases are more foregiving, some less.
Getting always a new Context() instance per each method-call and throwing it right away soon after by a clean-up call to it's .term()*-method is for sure better than having a hung-app or a frozen device, yet it is far from a fair design, respecting the process latencies and an "ecology"-of-resources.
Better first setup a semi-persistent infrastructure of resources ( each Context()-instance is typically a very expensive toy to instantiate ( API 4.2+ as of 2018-Q1 ), not so sharp for the Socket()-instances, but similar to the Poller() and all it's internal-AccessPoint(s) registration-hooks, yet the principle may extend on 'em too ).
Early re-factoring of the code will help not to extend the case with using expensive resources as a "consumable disposable".
The section:
while (true) {
try {
ZMQ.Context context = ZMQ.context(1);
// Connect to server
ZMQ.Socket requester = context.socket( ZMQ.REQ );
String address = "tcp://xxx.xx.xx.xx";
int port = 5000;
requester.connect( address + ":" + port );
...
}
...
}
is exactly a resources-devastating anti-pattern, altogether with repetitive latencies and even risks of remote-hangups and remote-rejections and similar issues.
I have a Service class that communicates with my another process, let's say process_A, by local socket.
My Service class is as follows:
public class MyService extends Service {
private LocalSocket localSock;
private LocalSocketAddress localSockAddr;
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent.getAction().equals(START_SERVICE_ACTION)) {
localSock = new LocalSocket();
localSockAddr = new LocalSocketAddress(LOCAL_SOCK_ADDR, LocalSocketAddress.Namespace.ABSTRACT);
try {
localSock.connect(localSockAddr);
} catch (IOException e) {
// Ignore
}
if (localSock.isConnected()) {
new LocalSockInitTask().execute(localSock);
}
} else if (intent.getAction().equals(STOP_SERVICE_ACTION)) {
new LocalSockTermTask().execute(localSock);
}
}
}
The behaviour should be as follows:
When my service is being started by user, the service uses LocalSocket.connect() to connect with process_A. Once connected successfully, the service executes an AsyncTask to send an INIT message to process_A and wait for an INIT message from process_A.
When my service is being stopped by user, the service executes another AsyncTask to send a TERM message to process_A and wait for a TERM message from process_A.
LocalSockInitTask.java:
public class LocalSockInitTask extends AsyncTask<LocalSocket, Void, Boolean> {
#Override
protected Boolean doInBackground(LocalSocket... params) {
LocalSocket localSock = params[0];
FileChannel inChannel;
FileChannel outChannel;
ByteBuffer sendBuf, recvBuf;
byte[] bytes;
String result, recvMsg;
int attempt;
try {
inChannel = new FileInputStream(localSock.getFileDescriptor()).getChannel();
outChannel = new FileOutputStream(localSock.getFileDescriptor()).getChannel();
// Send INIT Message
sendBuf = ByteBuffer.wrap(MSG_INIT.getBytes());
outChannel.write(sendBuf);
// Wait for INIT Message
recvBuf = ByteBuffer.allocate(BUFFER_SIZE);
attempt = 0;
while (inChannel.read(recvBuf) < 0) {
attempt++;
if(attempt == 5)
return false;
Thread.sleep(1000);
}
recvBuf.flip();
bytes = new byte[recvBuf.remaining()];
recvBuf.get(bytes);
result = new String(bytes);
if(!result.equals(MSG_INIT))
return false;
inChannel.close();
outChannel.close();
return true;
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
return false;
}
}
LocalSockTermTask.java is nearly doing the same as LocalSockInitTask.java, the major difference is just the message being send and receive is "MSG_TERM".
The Init task is doing perfectly, both write and read are successful. However, when executing the second AsyncTask (which is LocalSockTermTask), seems both write and read are unsuccessful. I've done some testing on this line:
inChannel.read(recvBuf);
In the first AsyncTask execution (LocalSockInitTask), if nothing can be read, this method will immediately return -1 and that's why I set a while loop and count the attempt.
In the second AsyncTask execution (LocalSockTermTask), if nothing can be read, this method will be blocked, and this makes my while loop and attempt count become useless. This cause the AsyncTask never complete. Also, My process_A is waiting for "MSG_TERM" to terminate, and it remains running, that's why I think outChannel.write(sendBuf) also failed in Term task.
Currently I am passing the LocalSocket object to both AsyncTask and create a pair of in/out FileChannel in the AsyncTask. I've also tried to create a pair of in/out FileChannel in the service and pass the two FileChannel to AsyncTask, but still facing the same problem.
Any help is greatly appreciated!
OK, I just found out that this is my careless mistake. The problem is solved.
My another process handles the TERM message incorrectly, so it just simply ignore the TERM message sent by my AsyncTask, and therefore it continues to run and wait for messages.
Since it ignores the TERM message, it won't send back a TERM message to my AsyncTask, and this cause the inChannel.read(recvBuf) has nothing to read.
The blocking behavior of inChannel.read(recvBuf) is absolutely normal, returning -1 should be the case that I use BufferedReader before I changed to use FileChannel.
I'm experiencing a very puzzling error writing a thread-pooled TCP server on Android. Basically, my code is structured as follows:
Standard server loop (blocking call to socket.accept() in a loop within its own thread), calling a handler upon an incoming connection:
socket = mServerSocket.accept();
myHandler.onIncomingConnection(socket);
The handler offloads all further processing of the incoming connection(s) to a thread pool:
public class X {
private final ExecutorService receiveThreadPool = Executors.newSingleThreadExecutor();
[...]
private final ConnectionHandler mHandler = new MyServer.ServerHandler() {
#Override
public void onIncomingConnection(final Socket socket) {
MLog.vv(TAG, "Socket status: " + (socket.isBound() ? "bound" : "unbound") + ", "
+ (socket.isConnected() ? "connected" : "unconnected") + ", "
+ (socket.isClosed() ? "closed" : "not closed") + ", "
+ (socket.isInputShutdown() ? "input shutdown" : "input not shut down") + ".");
// Process result
receiveThreadPool.execute(new Runnable() {
#Override
public void run() {
MLog.vv(TAG, "Socket status: " +
(socket.isBound() ? "bound" : "unbound") + ... ); // same code as above
BufferedOutputStream out = null;
try {
out = new BufferedOutputStream(socket.getOutputStream());
out.write(HELLO_MESSAGE);
out.flush();
[rest omitted...]
} catch (IOException e) {
[...]
} finally {
[close resources...]
}
}
Note, that the socket is defined as final in the handler method's signature, making it accessible from within the anonymous inner Runnable class. However, the first write out.write(HELLO_MESSAGE); to the output stream fails due to a closed socket exception. logcat output:
02-16 17:49:26.383 14000-14057/mypackage:remote V/ManagementServer﹕ Incoming connection from /192.168.8.33:47764
02-16 17:49:26.383 14000-14057/mypackage:remote V/ManagementServer﹕ Socket status: bound, connected, not closed, input not shut down.
02-16 17:49:26.393 14000-14077/mypackage:remote V/ManagementServer﹕ Socket status: bound, unconnected, closed, input not shut down.
02-16 17:49:26.398 14000-14077/mypackage:remote E/ManagementServer﹕ Error communicating with client:
java.net.SocketException: Socket is closed
at java.net.Socket.checkOpenAndCreate(Socket.java:665)
at java.net.Socket.getInputStream(Socket.java:359)
at net.semeion.tusynctest.network.ManagementServer$1$1.run(ManagementServer.java:79)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
at java.lang.Thread.run(Thread.java:818)
As shown in the log output, somehow the socket changes its status from connected to unconnected/closed right after offloading the Runnable into the thread pool. If I just remove the ThreadPool.execute lines, everything works as expected. I have also tried to create my own static Runnable class within the outer class X, passing the socket as a parameter to the Runnable's constructor. However, this triggers the same problem.
Am I missing something here? In theory, this should work like a charm; but somehow it seems, that upon starting the thread and terminating the handler's incomingConnection method, something happens to the socket instance.
Further facts:
It's not the client's fault either - to the client, it looks like the server closed the socket. And as said, commenting out the thread pool on the server side fixes the problem.)
You may notice the ":remote" in the logcat output - the server thread is created from within a background service that itself runs in a separate process.
At the moment, I'm employing a SingleThreadExecutor for the pool, just for testing. The type of executor should make no difference IMHO.
I tried to use the socket's OutputStream directly (unbuffered), which has not made a difference. The log statements show that the socket itself changes its status.
If I initialise the BufferedOutputstream in the handler right before executing the thread, this yields a strange "bad file number" SocketException at the out.flush(); line (possibly this is an IPC problem?!):
java.net.SocketException: sendto failed: EBADF (Bad file number)
at libcore.io.IoBridge.maybeThrowAfterSendto(IoBridge.java:546)
at libcore.io.IoBridge.sendto(IoBridge.java:515)
at java.net.PlainSocketImpl.write(PlainSocketImpl.java:504)
at java.net.PlainSocketImpl.access$100(PlainSocketImpl.java:37)
at java.net.PlainSocketImpl$PlainSocketOutputStream.write(PlainSocketImpl.java:266)
at java.io.BufferedOutputStream.flushInternal(BufferedOutputStream.java:185)
at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:85)
at net.semeion.tusynctest.network.ManagementServer$1$1.run(ManagementServer.java:88)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
at java.lang.Thread.run(Thread.java:818)
Caused by: android.system.ErrnoException: sendto failed: EBADF (Bad file number)
at libcore.io.Posix.sendtoBytes(Native Method)
at libcore.io.Posix.sendto(Posix.java:206)
at libcore.io.BlockGuardOs.sendto(BlockGuardOs.java:278)
at libcore.io.IoBridge.sendto(IoBridge.java:513)
Thanks for any hints :)
I've found the problem now. Embarrassingly, I've overlooked the most obvious source for trouble, the server loop in my Server class:
new Thread(new Runnable() {
#Override
public void run() {
while (mReceiving) {
Socket recSocket = null;
try {
recSocket = mServerSocket.accept();
// Process connection
mTcpServerHandler.onIncomingConnection(recSocket);
} catch (IOException e) {
// ...
} finally {
if (recSocket != null) {
try {
recSocket.close();
} catch (IOException e) {
// log, ignore...
}
}
}
}
}
}).start();
So, in case the handler offloads the processing to a new thread, the method returns immediately, and the finally block of the server loop closes the socket (which was intended originally, but doesn't fit the thread pool approach). Too obvious, sorry for bothering :)
I'm trying to build a little Bluetooth-Android-App for a project in school.
I'm quite new to Android (got my phone since 2 days). I'm experimenting since 2 weeks with android programming on my laptop. Installed a VirtualBox with Android x86 (eeepc) so I can use the BluetoothAdapter of the laptop. Emulator doesn't support Bluetooth and is quite slow. That's about the project...
The problem/question:
A Bluetoothconnection has 2 devices - a connecting and a listening one. The listening device has a BluetoothServerSocket, that loops accept() method until accept() returns a BluetoothSocket.
In my case the accept() method doesn't return so I get stuck and the app freezes with blackscreen asking mit to stop the app or just to wait. When I pass a timeout to accept() --> accept(10000) I get an IOException after the timeout.
listening device:
private class AcceptThread extends Thread {
private BluetoothSocket tSocket;
private BluetoothServerSocket bss = null;
public void run() {
try {
Log.d(TAG, "erzeuge ServerSocket");
bss = BluetoothAdapter.getDefaultAdapter().listenUsingInsecureRfcommWithServiceRecord("BluetoothChatInsecure", MainActivity.BT_UUID);
Log.d(TAG, "ServerSocket OK");
} catch (IOException e) {
e.printStackTrace();
Log.e(TAG, "Fehler Serversocket");
}
while (true) {
Log.d(TAG, "Versuche zu akzeptieren");
try {
Log.d(TAG, "Akzeptieren Anfang");
tSocket = bss.accept(10000);
//this line is never reached
Log.d(TAG, "Akzeptieren Ende");
if (tSocket != null){
//Hier wollen wir hin!
Log.d(TAG, "Verbindung akzeptiert");
ConnectedThread conThread = new ConnectedThread(tSocket);
conThread.run();
bss.close();
break;
} else {
Log.e(TAG, "Fehler, keine Verbindung");
}
} catch (IOException e) {
Log.e(TAG, "IOException währent accept-loop");
//this exception is triggered every 10 sec, when the accept(10000) times out
e.printStackTrace();
}
}
Log.i(TAG, "Acceptthread hat fertig");
}
}
connecting device:
try {
socket = device.createInsecureRfcommSocketToServiceRecord(MainActivity.BT_UUID);
outstr = socket.getOutputStream();
instr = socket.getInputStream();
ois = new ObjectInputStream(instr);
oos = new ObjectOutputStream(outstr);
} catch (IOException e) {
e.printStackTrace();
}
I've read a lot of threads on stackoverflow and some other forums about this topic, but I didn't got a solution for the problem.
Sorry about my English, but I am not a native speaker.
Thanks for any help!
EDIT:
I forgot to write, that I test the app with 2 devices. My laptop does accept-loop, while I use my phone and try to connect.
This is just the normal behavior: accept() will "wait" (block) until a connection has been made from another device. Then it returns the socket representing that connection for further data transfer.
As you have seen, the timeout is signalled via an IOException. The contract of accept() is that it never returns null but always a valid socket, or fails with an exception thrown.
Therefore, thejh is right in saying that you should have a dedicated thread which waits for connections in accept().
When accept() returns a new socket, you may want to spawn another thread to handle further communication over that socket, while the accept() thread loops to wait for the next connection.
N.b.: You cannot shut down a thread blocked in IO (as in accept()) via Thread.interrupt(), but you have to close the ServerSocket from another thread to cause an IOException to 'wake up' the blocked thread.
I've been facing this problem for a couple of days. Finally, I realized why:
I was creating the Thread that accepts incoming connections in the server twice. Thus, the ServerSocket was being created to times, although only the second time the accept() method was called.
This leads to server not accepting any connection!!
It seems that you didn't call socket.connect() from client side in the shown codes.
Today I continued work on project. I got IOException after failing connect() from connecting device.
Now I managed the devices to have a socket, after pairing them before running the app.
EDIT: accept() returns a socket now, but it isn't connected when asking with isConnected().
Socket of the connecting device is connected.
I've been playing around with my Java client app. Behaviour is very similar to this post (and others):
java.net.SocketException: Software caused connection abort: recv failed
As yet I've not found the answer - hence this post. I have a idea what is wrong but I'm not sure what to do about it.
The protocol is simple - read some data in, send back an ACK and repeat (until terminted).
I've been looking at what is going on with WireShark, and is seems the TCP window is filling up. I'm performing a flush() on the DataOutputStream (For the ACKs) but doesn't change the fact at after a while I get this exception (I can see on WireShark that there is always a window problem right before the Java exception).
So how to I make sure in Java that my TCP windows/buffers are clear (Which I think is the root cause of the problem?) seems to be no flush on the DataInputStream. Make be wonder that whilst I might be reading it the TCP stack is filling up.
Many Thanks
Mark
I've attached the basic code calls below:
public void connectToServer()
{
//Create socket connection
try
{
if (lSocket == null)
{
lSocket = new Socket("localhost", 7651);
lSocket.setSoTimeout(0);
lInDataStream = new DataInputStream(lSocket.getInputStream());
lOutDataStream = new DataOutputStream(lSocket.getOutputStream());
}
}
catch (UnknownHostException e)
{
System.out.println("Unknown host: localhost");
}
catch (IOException e)
{
System.out.println("No I/O");
}
}
public void readSocket() throws IOException
{
//Receive data from ROS SerialtoNetwork server
if (lSocket != null)
{
lInDataStream.readInt();
lInDataStream.readFully(cbuf);
lOutDataStream.writeBytes("Ack");
lOutDataStream.flush();
//String lstr = new String(cbuf);
//System.out.print(lstr);
//System.out.println("");
}
}
public String getDataBuffer()
{
String lstr = new String(cbuf);
return lstr;
}
This indicates persistent network errors. There are several (repetitive) MSDN article on this error, e.g. this one.