我在手机上运行 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;
我确实关闭并打开了手机电源,但这没有帮助。 我删除了所有配对的设备,没有帮助。
问题出在UUID。当我更改代码时:
MY_UUID = UUID.fromString("0000110E-0000-1000-8000-00805F9B34FB");
到
MY_UUID = device.getUuids()[0].getUuid();
它起作用了。