为什么在蓝牙连接()时会出现“java.io.IOException: read failed, socket might closed or timeout, read ret: -1”错误?

3
我正在手机上运行Android 7.0,使用Android Studio 2.3.3 build #AI-162.4069837 June 6, 2017和JDK 1.8.0_144。连接树莓派Zero W时,出现错误"java.io.IOException: read failed, socket might closed or timeout, read ret: -1"。当我下载并运行Android程序"BlueTerminal"时,该程序可以成功连接和传输数据。然而,这个程序失败了。以下是Android代码。
package com.terryneckar.sprinkon;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.Context;
import android.content.SharedPreferences;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;

import java.io.IOException;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.UUID;

import static com.terryneckar.sprinkon.R.string.preference_file_key;

public class BluetoothSetup extends AppCompatActivity
{
  private static final int REQUEST_ENABLE_BT = 1;
  BluetoothAdapter btAdapter;
  String bluetoothName = "";
  Spinner spinner;
  private static final UUID MY_UUID = UUID.fromString("0000110E-0000-1000-8000-00805F9B34FB");

  @Override

  protected void onCreate(Bundle savedInstanceState)  
  {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_bluetooth_setup);
    Button saveButton = (Button) findViewById(R.id.id_savebtn);
    Button connectButton = (Button) findViewById(R.id.id_connectbtn);

    String ssid = getConfigData("SSID");
    String password = getConfigData("Password");
    String timezone = getConfigData("Timezone");
    bluetoothName = getConfigData("BluetoothName");

    TextView myTextView1 = (TextView)findViewById(R.id.id_ssid);
    myTextView1.setText(ssid);

    TextView myTextView2 = (TextView)findViewById(R.id.id_password);
    myTextView2.setText(password);

    TextView myTextView3 = (TextView)findViewById(R.id.id_timezone);
    myTextView3.setText(timezone);

    // Fill the spinner with a list of all of the bluetooth devices available.
    List<String> bluetoothDevices = new ArrayList<String>();

    btAdapter = BluetoothAdapter.getDefaultAdapter();
    Set<BluetoothDevice> pairedDevices = btAdapter.getBondedDevices();

    for (BluetoothDevice device : pairedDevices)
      bluetoothDevices.add(device.getName());

    ArrayAdapter<String> adapter = new ArrayAdapter<String>(getApplicationContext(), android.R.layout.simple_spinner_item, bluetoothDevices);

    adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);

    spinner = (Spinner) findViewById(R.id.id_bluetoothDevices);
    spinner.setAdapter(adapter);

    // Set the spinner to the value that was saved in the configuration.
    if (!bluetoothName.equals(null))
    {
      int spinnerPosition = adapter.getPosition(bluetoothName);
      spinner.setSelection(spinnerPosition);
    }

    saveButton.setOnClickListener(
      new Button.OnClickListener()
      {        
        public void onClick(View v)        
        {
          String ssid = "";
          String password = "";
          String timezone = "";

          EditText editText = (EditText) findViewById(R.id.id_ssid);
          ssid = editText.getText().toString();
          editText = (EditText) findViewById(R.id.id_password);
          password = editText.getText().toString();
          editText = (EditText) findViewById(R.id.id_timezone);
          bluetoothName = spinner.getSelectedItem().toString();

          timezone = editText.getText().toString();

          writeToFile("SSID", ssid);
          writeToFile("Password", password);
          writeToFile("Timezone", timezone);
          writeToFile("BluetoothName", bluetoothName);

          Toast.makeText(getApplicationContext(), "Save was successful.", Toast.LENGTH_LONG).show();
        }
      });


    connectButton.setOnClickListener(
      new Button.OnClickListener()
      {        
        public void onClick(View v)        
        {
          String ssid = "";
          String password = "";
          String timezone = "";
          BluetoothDevice device = null;
          BluetoothSocket mSocket = null;

          EditText editText = (EditText) findViewById(R.id.id_ssid);
          ssid = editText.getText().toString();
          editText = (EditText) findViewById(R.id.id_password);
          password = editText.getText().toString();
          editText = (EditText) findViewById(R.id.id_timezone);
          bluetoothName = spinner.getSelectedItem().toString();
          timezone = editText.getText().toString();

          device = GetBluetoothDevice(btAdapter, bluetoothName);

          if(device.getBondState()==device.BOND_BONDED)
          {
            try
            {
              mSocket = device.createInsecureRfcommSocketToServiceRecord(MY_UUID);
              //mSocket = device.createRfcommSocketToServiceRecord(MY_UUID);
            }
            catch (IOException e1)
            {
              // TODO Auto-generated catch block
              //Log.d(TAG,"socket not created");
              e1.printStackTrace();
            }
            try
            {
              mSocket.connect();
                Toast.makeText(getApplicationContext(), "Connect was successful.", Toast.LENGTH_SHORT).show();
            }
            catch(IOException e)
            {
              Log.e("SprinKon TAG", "STACKTRACE");
              Log.e("SprinKon TAG", Log.getStackTraceString(e));
              try
              {
                mSocket.close();
                Toast.makeText(getApplicationContext(), "Cannot connect. \n" + e.getMessage(), Toast.LENGTH_LONG).show();
              }
              catch (IOException e1)
              {
              }
            }
          }
        }
      });
  }


  private void writeToFile(String data, String key)  
  {
    Context context = BluetoothSetup.this;
    SharedPreferences sharedPref = context.getSharedPreferences("SprinKonConfig", Context.MODE_PRIVATE);
    SharedPreferences.Editor editor = sharedPref.edit();
    editor.putString(data, key);
    editor.commit();
  }

  private String getConfigData(String key)  
  {
    Context context = BluetoothSetup.this;
    SharedPreferences sharedPref = context.getSharedPreferences("SprinKonConfig", Context.MODE_PRIVATE);
    String data = sharedPref.getString(key, "DEFAULT");
    return data;
  }

  private BluetoothDevice GetBluetoothDevice(BluetoothAdapter adapter, String deviceName)  
  {
    Set<BluetoothDevice> devices = adapter.getBondedDevices();
    BluetoothDevice result = null;

    if (devices != null)
    {
      for (BluetoothDevice device : devices)
      {
        if (deviceName.equals(device.getName()))
        {
          result = device;
          break;
        }
      }

    }
    return result;
  }
}

当我运行“BlueTerminal”程序时,它似乎比这个程序需要更长的时间来建立连接。可能是因为连接超时了。如果是这样,是否有办法增加超时值,就像可以在互联网连接上做的那样?我不明白为什么Android代码要在connect()、readInt()和readAll()上做所有操作,而不只是提供一个可用的connect()。C++程序正在等待accept(),但它从未发生过。
以下是堆栈跟踪:
java.io.IOException: read failed, socket might closed or timeout, read ret: -1
android.bluetooth.BluetoothSocket.readAll(BluetoothSocket.java:907)
android.bluetooth.BluetoothSocket.readInt(BluetoothSocket.java:919)
android.bluetooth.BluetoothSocket.connect(BluetoothSocket.java:536)
com.terryneckar.sprinkon.BluetoothSetup$2.onClick(BluetoothSetup.java:153)
android.view.View.performClick(View.java:6207)
android.widget.TextView.performClick(TextView.java:11094)
android.view.View$PerformClick.run(View.java:23639)
android.os.Handler.handleCallback(Handler.java:751)
android.os.Handler.dispatchMessage(Handler.java:95)
android.os.Looper.loop(Looper.java:154)
android.app.ActivityThread.main(ActivityThread.java:6688)
java.lang.reflect.Method.invoke(Native Method)
com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1468)
com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1358)

这里是我要连接的C++程序。
char buf[1024] = {0};   
int bluetoothSocket, client, bytes_read;         
struct sockaddr_rc loc_addr = {0};
struct sockaddr_rc client_addr = {0};

socklen_t opt = sizeof(client_addr);    

bdaddr_t my_bdaddr_any = {0, 0, 0, 0, 0, 0};        

bluetoothSocket = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);     

loc_addr.rc_family = AF_BLUETOOTH;
loc_addr.rc_bdaddr = (bdaddr_t)my_bdaddr_any;               
loc_addr.rc_channel = (uint8_t) 1;

int ret = -1;

if ((ret = bind(bluetoothSocket, (struct sockaddr *)&loc_addr, sizeof(loc_addr))) == -1)     
{
  printf("Bluetooth bind failed. ERRNO=%d\n", errno);
  char *errorMessage = strerror_r(errno, buf, 1024);
  printf("%s\n", errorMessage);
  return 0;
}

ret = -1;

if((ret = listen(bluetoothSocket, 1)) == -1)
{
  printf("Bluetooth listen failed. ERRNO=%d\n", errno);
  char *errorMessage = strerror_r(errno, buf, 1024);
  printf("%s\n", errorMessage);
  return 0;
}


printf("Waiting for new client to connect.\n");

client = accept(bluetoothSocket, (struct sockaddr *)&client_addr, &opt);

if (client == -1)
{
  printf("Bluetooth connect failed.\n");
  close(client);
  return;
}

printf("Bluetooth connection made.\n");

ba2str(&client_addr.rc_bdaddr, buf);
fprintf(stderr, "accepted connection from %s\n", buf);
memset(buf, 0, sizeof(buf));

            // read data from the client
bytes_read = read(client, buf, sizeof(buf));

if (bytes_read > 0) 
{
    printf("Bluetooth bytes received [%s]\n", buf);
}

close(client);
close(bluetoothSocket);
return 0;       

我已经将手机关机并重新开机,但这并没有解决问题。 我删除了所有配对设备,但还是没有帮助。
1个回答

4
问题出在 UUID 上。当我将代码从以下内容更改为时:
MY_UUID = UUID.fromString("0000110E-0000-1000-8000-00805F9B34FB");

to

MY_UUID = device.getUuids()[0].getUuid();

它运作正常。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接