简体   繁体   English

通过蓝牙从作为客户端的PC向作为服务器的移动设备发送字符串

[英]Sending a string via Bluetooth from a PC as client to a mobile as server

I need help by transferring a string from a PC to an Android mobile device via Bluetooth. 我需要通过蓝牙将字符串从PC传输到Android移动设备来获得帮助。 The Android mobile device should act as a server and displays the string message on the screen of the device. Android移动设备应充当服务器并在设备屏幕上显示字符串消息。 The PC which is the client should send the string to the mobile device. 作为客户端的PC应该将字符串发送到移动设备。

I want the server react on the extracted string (transferred via Bluetooth). 我希望服务器对提取的字符串做出反应(通过蓝牙传输)。 That means that on one side the server always has to listen for new strings to arrive, but on the other side still has to be able to react on these messages (eg navigate from one menu to another). 这意味着在一侧服务器总是必须监听新的字符串到达​​,但另一方面仍然必须能够对这些消息作出反应(例如,从一个菜单导航到另一个菜单)。

I tried it by using BlueCove (2.1.1) as BluetoothStack (for which I add the jar from BlueCove as a library to both projects) in combination with an example for a server-client communication that I found here . 我尝试使用BlueCove(2.1.1)作为BluetoothStack(我将BlueCove中的jar作为库添加到两个项目中)并结合我在此处找到的服务器 - 客户端通信示例。

Updates: 更新:

Updated code from server thanks to user_CC using a RFComm connection for the server: 由于user_CC使用服务器的RFComm连接,服务器更新了代码:

public class RFCommServer extends Thread{

//based on java.util.UUID
private static UUID MY_UUID = UUID.fromString("446118f0-8b1e-11e2-9e96-0800200c9a66");

// The local server socket
private BluetoothServerSocket mmServerSocket;

// based on android.bluetooth.BluetoothAdapter
private BluetoothAdapter mAdapter;
private BluetoothDevice remoteDevice;

private Activity activity;

public RFCommServer(Activity activity) {
    this.activity = activity;
}

public void run() {
    BluetoothSocket socket = null;
    mAdapter = BluetoothAdapter.getDefaultAdapter();        

    // Listen to the server socket if we're not connected
    while (true) {

        try {
            // Create a new listening server socket
            Log.d(this.getName(), ".....Initializing RFCOMM SERVER....");

            // MY_UUID is the UUID you want to use for communication
            mmServerSocket = mAdapter.listenUsingRfcommWithServiceRecord("MyService", MY_UUID);
            //mmServerSocket = mAdapter.listenUsingInsecureRfcommWithServiceRecord(NAME, MY_UUID); // you can also try using In Secure connection...

            // This is a blocking call and will only return on a
            // successful connection or an exception
            socket = mmServerSocket.accept();

        } catch (Exception e) {

        }

        try {
            Log.d(this.getName(), "Closing Server Socket.....");
            mmServerSocket.close();

            InputStream tmpIn = null;
            OutputStream tmpOut = null;

            // Get the BluetoothSocket input and output streams

            tmpIn = socket.getInputStream();
            tmpOut = socket.getOutputStream();

            DataInputStream mmInStream = new DataInputStream(tmpIn);
            DataOutputStream mmOutStream = new DataOutputStream(tmpOut);

            // here you can use the Input Stream to take the string from the client whoever is connecting
            //similarly use the output stream to send the data to the client

            RelativeLayout layout = (RelativeLayout) activity.findViewById(R.id.relativeLayout_Layout);
            TextView text = (TextView) layout.findViewById(R.id.textView_Text);

            text.setText(mmInStream.toString());
        } catch (Exception e) {
            //catch your exception here
        }
    }
}

Code of the SPP Client from here : 从SPP客户端的代码在这里

/**
* A simple SPP client that connects with an SPP server
*/
public class SampleSPPClient implements DiscoveryListener{

//object used for waiting
private static Object lock=new Object();

//vector containing the devices discovered
private static Vector vecDevices=new Vector();

private static String connectionURL=null;

public static void main(String[] args) throws IOException {

    SampleSPPClient client=new SampleSPPClient();

    //display local device address and name
    LocalDevice localDevice = LocalDevice.getLocalDevice();
    System.out.println("Address: "+localDevice.getBluetoothAddress());
    System.out.println("Name: "+localDevice.getFriendlyName());

    //find devices
    DiscoveryAgent agent = localDevice.getDiscoveryAgent();

    System.out.println("Starting device inquiry...");
    agent.startInquiry(DiscoveryAgent.GIAC, client);

    try {
        synchronized(lock){
            lock.wait();
        }
    }
    catch (InterruptedException e) {
        e.printStackTrace();
    }


    System.out.println("Device Inquiry Completed. ");

    //print all devices in vecDevices
    int deviceCount=vecDevices.size();

    if(deviceCount <= 0){
        System.out.println("No Devices Found .");
        System.exit(0);
    }
    else{
        //print bluetooth device addresses and names in the format [ No. address (name) ]
        System.out.println("Bluetooth Devices: ");
        for (int i = 0; i <deviceCount; i++) {
            RemoteDevice remoteDevice=(RemoteDevice)vecDevices.elementAt(i);
            System.out.println((i+1)+". "+remoteDevice.getBluetoothAddress()+" ("+remoteDevice.getFriendlyName(true)+")");
        }
    }

    System.out.print("Choose Device index: ");
    BufferedReader bReader=new BufferedReader(new InputStreamReader(System.in));

    String chosenIndex=bReader.readLine();
    int index=Integer.parseInt(chosenIndex.trim());

    //check for spp service
    RemoteDevice remoteDevice=(RemoteDevice)vecDevices.elementAt(index-1);
    UUID[] uuidSet = new UUID[1];
    uuidSet[0]=new UUID("446118f08b1e11e29e960800200c9a66", false);

    System.out.println("\nSearching for service...");
    agent.searchServices(null,uuidSet,remoteDevice,client);

    try {
        synchronized(lock){
            lock.wait();
        }
    }
    catch (InterruptedException e) {
        e.printStackTrace();
    }

    if(connectionURL==null){
        System.out.println("Device does not support Simple SPP Service.");
        System.exit(0);
    }

    //connect to the server and send a line of text
    StreamConnection streamConnection=(StreamConnection)Connector.open(connectionURL);

    //send string
    OutputStream outStream=streamConnection.openOutputStream();
    PrintWriter pWriter=new PrintWriter(new OutputStreamWriter(outStream));
    pWriter.write("Test String from SPP Client\r\n");
    pWriter.flush();


    //read response
    InputStream inStream=streamConnection.openInputStream();
    BufferedReader bReader2=new BufferedReader(new InputStreamReader(inStream));
    String lineRead=bReader2.readLine();
    System.out.println(lineRead);


}//main

//methods of DiscoveryListener
public void deviceDiscovered(RemoteDevice btDevice, DeviceClass cod) {
    //add the device to the vector
    if(!vecDevices.contains(btDevice)){
        vecDevices.addElement(btDevice);
    }
}

//implement this method since services are not being discovered
public void servicesDiscovered(int transID, ServiceRecord[] servRecord) {
    if(servRecord!=null && servRecord.length>0){
        connectionURL=servRecord[0].getConnectionURL(0,false);
    }
    synchronized(lock){
        lock.notify();
    }
}

//implement this method since services are not being discovered
public void serviceSearchCompleted(int transID, int respCode) {
    synchronized(lock){
        lock.notify();
    }
}


public void inquiryCompleted(int discType) {
    synchronized(lock){
        lock.notify();
    }

}//end method

}

For testing I use a Galaxy Nexus (GT-I9250) with the latest Android API. 为了测试,我使用Galaxy Nexus(GT-I9250)和最新的Android API。

Thanks to user_CC , the client and server now runs without an exception. 由于user_CC ,客户端和服务器现在无异常地运行。 But sadly the client is not able to connect to the server (see the screenshot below). 但遗憾的是客户端无法连接到服务器(请参阅下面的屏幕截图)。 It is because the connectionURL is never set (thus it jumps in here if(connectionURL==null) by default. 这是因为connectionURL永远不会被设置(因此默认情况下它会跳转到if(connectionURL==null)

How can I change the client code, so that I actually can connect it with the server? 如何更改客户端代码,以便我实际上可以将其与服务器连接? I need a proper connectionURL in the following line: 我需要在以下行中使用正确的connectionURL

StreamConnection streamConnection=(StreamConnection)Connector.open(connectionURL)

So far I only found out that I somehow need to get the ServiceRecord , sadly this is also not described in the example code from here . 到目前为止,我只发现我需要得到ServiceRecord ,遗憾的是, 这里的示例代码中也没有描述。

在此输入图像描述

You will need to use the RFComm APIS to make the communication work I have managed to define a class which is a Thread and will be acting as a server and listening for client connections. 您需要使用RFComm APIS来完成我已经设法的通信工作,以定义一个类,该类是一个线程,并将充当服务器并侦听客户端连接。 I have also placed some comments for you to understand. 我还提出了一些意见供你理解。

    private class AcceptThread extends Thread {
    // The local server socket
    private BluetoothServerSocket mmServerSocket;

    public AcceptThread() {
    }

    public void run() {         
        BluetoothSocket socket = null;

                    BluetoothAdapter mAdapter = BluetoothAdapter.getDefaultAdapter();

        // Listen to the server socket if we're not connected
        while (true) {

            try {
                // Create a new listening server socket
                Log.d(TAG, ".....Initializing RFCOMM SERVER....");

                // MY_UUID is the UUID you want to use for communication
                mmServerSocket = mAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);                    
                //mmServerSocket = mAdapter.listenUsingInsecureRfcommWithServiceRecord(NAME, MY_UUID);  you can also try using In Secure connection...

                // This is a blocking call and will only return on a
                // successful connection or an exception                    
                socket = mmServerSocket.accept();                   

            } catch (Exception e) {

            }

            try {
                Log.d(TAG, "Closing Server Socket.....";                    
                mmServerSocket.close();



                InputStream tmpIn = null;
                OutputStream tmpOut = null;

                // Get the BluetoothSocket input and output streams

                tmpIn = socket.getInputStream();
                tmpOut = socket.getOutputStream();


                mmInStream = new DataInputStream(tmpIn);
                mmOutStream = new DataOutputStream(tmpOut); 

                // here you can use the Input Stream to take the string from the client whoever is connecting
                //similarly use the output stream to send the data to the client
            } catch (Exception e) {
                //catch your exception here
            }

        }
    }

}

I hope this helps 我希望这有帮助

For your another question: 对于你的另一个问题:

Declaring javax.bluetooth.UUID on Client side (PC) UUID class should be from javax.bluetooth.UUID 在客户端(PC)UUID类上声明javax.bluetooth.UUID应该来自javax.bluetooth.UUID

   uuidSet2[0] = new UUID("446118f08b1e11e29e960800200c9a66", false);

Declaring java.util.UUID at Server Side (Android) 在服务器端声明java.util.UUID(Android)

    UUID MY_UUID = UUID.fromString("446118f0-8b1e-11e2-9e96-0800200c9a66");

I'm not a Java developer but I've had a similar issue with Mono for Android (c#) 我不是Java开发人员,但我在使用Mono for Android时遇到了类似的问题(c#)

The UUID for SPP should be "00001101-0000-1000-8000-00805F9B34FB" SPP的UUID应为"00001101-0000-1000-8000-00805F9B34FB"
This is a well known UID to identify a Bluetooth SPP adapter. 这是用于识别蓝牙SPP适配器的众所周知的UID。

In my c# code that looks like 在我看来的c#代码中

private static UUID MY_UUID = UUID.FromString("00001101-0000-1000-8000-00805F9B34FB");

I'm guessing you can update your Java code to something like: 我猜你可以将你的Java代码更新为:

new UUID("00001101-0000-1000-8000-00805F9B34FB", true);

Although I'm not sure what parameters that function accepts, so you may have to check that. 虽然我不确定函数接受哪些参数,但您可能需要检查它。

I was using the Android device as a client, but the information may be of use to you, 我使用Android设备作为客户端,但这些信息对您有用,
so I'll include my c# code here which I originally translated from Java samples, 所以我将在这里包含我最初从Java样本翻译的c#代码,
so you should be able to translate it back: 所以你应该能够将它翻译回来:

btAdapter = BluetoothAdapter.DefaultAdapter;

btAdapter.CancelDiscovery(); //Always call CancelDiscovery before doing anything
remoteDevice = btAdapter.GetRemoteDevice(Settings["deviceaddress"].ToString());

socket = remoteDevice.CreateRfcommSocketToServiceRecord(MY_UUID);
socket.Connect();

Basically I get the default adapter, cancel any running discovery operations and then create a socket to the other device. 基本上我得到默认适配器,取消任何正在运行的发现操作,然后创建一个到另一个设备的套接字。 In your case you'll want to listen instead of connecting, but just for your information. 在你的情况下,你会想听,而不是连接,但只是为了你的信息。

I hope it helps, sorry I could not give you more Java specific information. 我希望它有所帮助,抱歉,我无法向您提供更多Java特定信息。

'Update:' Just found a little sample in Java that more or less follows the same method as what I'm using: Problems with connecting bluetooth SPP in android? '更新:'刚刚在Java中发现了一个小样本,它或多或少遵循与我正在使用的方法相同的方法: 在android中连接蓝牙SPP的问题?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM