[英]Could not create connection to database server after multiple successful connections
[英]android bluetooth connection fails after 489 successful connections
不幸的是,我的android藍牙有一些問題。 對於我的測試環境,我使用的是帶有Android 4.4.2的Nexus 4。
我的PC上有一個Java應用程序,它使用bluecove作為客戶端進行SPP連接。 該程序正在尋找一個特殊的服務名稱,並與我的Android手機連接。 然后它發送72個字節到我的Android手機,並等待答案。 得到答案時,程序會睡3秒鍾而不是重新開始。
在我的Android手機上,我有一個帶有后台藍牙監聽器的應用程序,它在啟動時啟動。 此應用程序基於BluetoothChat示例演示。 當接收藍牙數據時,我檢查傳入的數據並發回答案。
一切正常。 但是在489藍牙連接之后,Android應用程序在PC-java-app正在進行時失敗並顯示以下錯誤代碼:
getBluetoothService() called with no BluetoothManagerCallback
Shutting down VM
threadid=1: thread exiting with uncaught exception (group=0x41b34ba8)
FATAL EXCEPTION: main
Process: de.tum.lme.diamantum:remote_blue, PID: 21567
java.lang.NullPointerException: FileDescriptor must not be null
at android.os.ParcelFileDescriptor.<init>(ParcelFileDescriptor.java:174)
at android.os.ParcelFileDescriptor$1.createFromParcel(ParcelFileDescriptor.java:905)
at android.os.ParcelFileDescriptor$1.createFromParcel(ParcelFileDescriptor.java:897)
at android.bluetooth.IBluetooth$Stub$Proxy.createSocketChannel(IBluetooth.java:1355)
at android.bluetooth.BluetoothSocket.bindListen(BluetoothSocket.java:349)
at android.bluetooth.BluetoothAdapter.createNewRfcommSocketAndRecord(BluetoothAdapter.java:1055)
at android.bluetooth.BluetoothAdapter.listenUsingRfcommWithServiceRecord(BluetoothAdapter.java:976)
at com.test.btconn.BluetoothHandling$AcceptThread.<init>(BluetoothHandling.java:449)
at com.test.btconn.BluetoothHandling.start(BluetoothHandling.java:216)
at com.test.btconn.BluetoothListenerService.setupBtSockets(BluetoothListenerService.java:330)
at com.test.btconn.BluetoothListenerService.manageBtState(BluetoothListenerService.java:249)
at com.test.btconn.BluetoothListenerService.setBtStateDisconnected(BluetoothListenerService.java:383)
at com.test.btconn.BluetoothListenerService.access$5(BluetoothListenerService.java:378)
at com.test.btconn.BluetoothListenerService$2.handleMessage(BluetoothListenerService.java:421)
因此,應用程序的ParcelFileDescriptor存在問題,該問題突然變為空。 但為什么?
當改變PC-java-app上的暫停時間時,使用各種數據大小來傳輸和使用不同的智能手機時,也會發生上述所有情況。 當使用反射“listenUsingRfcommWithServiceRecord”時,505傳輸后也會發生相同的情況。 使用喚醒鎖也沒有任何改變。
順便說一下,使用BluetoothChat樣本時我也有同樣的行為。
所以,有人提示,會發生什么?
更新:
如果藍牙狀態為3,則每次連接后BluetoothServerSocket都會關閉,BluetoothSocket會關閉。
問題似乎與您設備上的文件描述符限制有關。 沒有為這個問題的報告在這里
在創建藍牙套接字期間, 新的fd是從系統獲取的兩個新FD 。 您似乎沒有正確關閉以前的BT連接,因此在您達到限制之前,已使用的FD數量會穩步增加。
為了避免這種情況,你會至少要調用close()
在你從收到BluetoothServerSocket listenUsingRfcommWithServiceRecord()
完成操作它后調用。 您還應該檢查是否要保留連接到BT連接的其他資源,並在可能的情況下釋放它們。
這里要求的是如何強制關閉BluetoothServerSocket的ParcelFileDescriptor。 小心:它可能會破壞事情!
您必須訪問BluetoothServerSocket的mSocket字段才能訪問底層的BluetoothSocket 。 此BluetoothSocket在字段mPfd中保存ParcelFileDescriptor。 在那你可以調用close()
。 由於兩個字段都不可見,您將不得不使用Reflections :
public void closePFD(BluetoothServerSocket closeMe) throws AllKindOfExceptionsThatYouHaveToHandle
{
Field mSocketFld = closeMe.getClass().getDeclaredField("mSocket");
mSocketFld.setAccessible(true);
BluetoothSocket btsock = (BluetoothSocket)mSocketFld.get(closeMe);
Field mPfdFld = btsock.getClass().getDeclaredField("mPfd");
mPfdFld.setAccessible(true);
ParcelFileDescriptor pfd = (ParcelFileDescriptor)mPfdFld.get(btsock);
pfd.close();
}
這將關閉BluetoothServerSocket 。 如果你想從BTServerSockets接受方法中只關閉BluetoothSocket ,你可以省略獲得mSocket的部分,如jitain sharmas answer所示 。
我對我提出的問題的解決方法是:
private synchronized void clearFileDescriptor(){
try{
Field field = BluetoothSocket.class.getDeclaredField("mPfd");
field.setAccessible(true);
ParcelFileDescriptor mPfd = (ParcelFileDescriptor)field.get(socket);
if(null == mPfd){
return;
}
mPfd.close();
}catch(Exception e){
Log.w(SensorTicker.TAG, "ParcelFileDescriptor could not be cleanly closed.");
}
}
所以上面是我編寫的關閉filedescriptor的方法,以及下面我使用此代碼的方法:每當socket必須關閉時:
private synchronized void cleanClose() {
if (socket != null) {
try {
clearFileDescriptor();
//clearLocalSocket();
socket.close();
}
catch (IOException e) {
Log.w(SensorTicker.TAG, "Socket could not be cleanly closed.");
}
}
}
我也試過我編寫的clearLocalSocket()方法,但沒有用於我的問題。 所以我試圖關閉FileDescriptor。 希望它能幫助你和其他人面對同樣的問題。
這是Android 4.2 - 4.4.4(和4.4w&L預覽版)中的BluetoothSocket.close()錯誤......在內部,它調用mPfd.detachFd(),然后實際上不釋放底層文件描述符。 修復是調用mPfd.close()並設置mPfd = null,這正是Android 5.0現在所做的。
您可以使用此處發布的調用mPfd.close()然后調用平台的BluetoothSocket.close()的其他解決方案來解決此問題,但我發現這對我來說還不夠,可能會發生一些奇怪的事情。 我更進一步,先清理mSocket並設置為null,然后調用mPfd.close()並設置為null,最后調用設置mSocketState所需的BluetoothSocket.close()。
public static void cleanClose(BluetoothSocket btSocket)
{
if(btSocket == null)
return;
if(Build.VERSION.SDK_INT >= 17 && Build.VERSION.SDK_INT <= 20)
{
try { cleanCloseFix(btSocket); }
catch (Exception e)
{
Log.d(sLogName, "Exception during BluetoothSocket close bug fix: " + e.toString());
}
//Go on to call BluetoothSocket.close() too, because our code didn't do quite everything
}
//Call BluetoothSocket.close()
try { btSocket.close(); }
catch (Exception e)
{
Log.d(sLogName, "Exception during BluetoothSocket close: " + e.toString());
}
}
private static void cleanCloseFix(BluetoothSocket btSocket) throws IOException
{
synchronized(btSocket)
{
Field socketField = null;
LocalSocket mSocket = null;
try
{
socketField = btSocket.getClass().getDeclaredField("mSocket");
socketField.setAccessible(true);
mSocket = (LocalSocket)socketField.get(btSocket);
}
catch(Exception e)
{
Log.d(sLogName, "Exception getting mSocket in cleanCloseFix(): " + e.toString());
}
if(mSocket != null)
{
mSocket.shutdownInput();
mSocket.shutdownOutput();
mSocket.close();
mSocket = null;
try { socketField.set(btSocket, mSocket); }
catch(Exception e)
{
Log.d(sLogName, "Exception setting mSocket = null in cleanCloseFix(): " + e.toString());
}
}
Field pfdField = null;
ParcelFileDescriptor mPfd = null;
try
{
pfdField = btSocket.getClass().getDeclaredField("mPfd");
pfdField.setAccessible(true);
mPfd = (ParcelFileDescriptor)pfdField.get(btSocket);
}
catch(Exception e)
{
Log.d(sLogName, "Exception getting mPfd in cleanCloseFix(): " + e.toString());
}
if(mPfd != null)
{
mPfd.close();
mPfd = null;
try { pfdField.set(btSocket, mPfd); }
catch(Exception e)
{
Log.d(sLogName, "Exception setting mPfd = null in cleanCloseFix(): " + e.toString());
}
}
} //synchronized
}
如果您在應用程序中使用藍牙作為服務器,我遇到了與此相同的問題,除了我的問題是當我進行反射時,我在文件描述符mPfd上變為null。 我能夠使用這種方法關閉文件,希望這可以幫助。
我使用ParceFileDescriptor從BluetoothSocket中的LoaclSocket通過id / index獲取文件。 int mfd = 0; 字段socketField = null; LocalSocket mSocket = null;
try
{
socketField = btSocket.getClass().getDeclaredField("mSocket");
socketField.setAccessible(true);
mSocket = (LocalSocket)socketField.get(btSocket);
}
catch(Exception e)
{
Log ( "Exception getting mSocket in cleanCloseFix(): " + e.toString());
}
if(mSocket != null)
{
FileDescriptor fileDescriptor =
mSocket.getFileDescriptor();
String in = fileDescriptor.toString();
//regular expression to get filedescriptor index id
Pattern p = Pattern.compile("\\[(.*?)\\]");
Matcher m = p.matcher(in);
while(m.find()) {
Log ( "File Descriptor " + m.group(1));
mfd = Integer.parseInt(m.group(1));
break;
}
//Shutdown the socket properly
mSocket.shutdownInput();
mSocket.shutdownOutput();
mSocket.close();
mSocket = null;
try { socketField.set(btSocket, mSocket); }
catch(Exception e)
{
Log ("Exception setting mSocket = null in cleanCloseFix(): " + e.toString());
}
//Close the file descriptor when we have it from the Local Socket
try {
ParcelFileDescriptor parcelFileDescriptor = ParcelFileDescriptor.adoptFd(mfd);
if (parcelFileDescriptor != null) {
parcelFileDescriptor.close();
Log ( "File descriptor close succeed : FD = " + mfd);
}
} catch (Exception ex) {
Log ( "File descriptor close exception " + ex.getMessage());
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.