为什么我在蓝牙 connect() 上收到“java.io.IOException: read failed, socket might close or timeout, read ret: -1”?

问题描述 投票:0回答:1

我在手机上运行 Android 7.0、Android Studio 2.3.3 build #AI-162.4069837 June 6, 2017 和 JDK 1.8.0_144。连接到 Raspberry Pi Zero W 时,出现错误“java.io.IOException:读取失败,套接字可能关闭或超时,读取 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() 上执行 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;       

我确实关闭并打开了手机电源,但这没有帮助。 我删除了所有配对的设备,没有帮助。

java android c++ bluetooth
1个回答
4
投票

问题出在UUID。当我更改代码时:

MY_UUID = UUID.fromString("0000110E-0000-1000-8000-00805F9B34FB");

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

它起作用了。

© www.soinside.com 2019 - 2024. All rights reserved.