2

我有两个通过蓝牙连接的设备。我想将更多字符串从一个设备发送到另一个设备,但方法 read() 无法正常工作(仅当我想读取最后一个字符串时)。

奇怪的是,它适用于:

inStream.read(keyRead);
outStream.write(answer.getBytes(charsetCod));
inStream.read(sizeRead);
inStream.read(messageRead);
inStream.read(timeSent);

但它仅在应用程序执行以下操作时才起作用:

int byteRead = inStream.read(alreadyReceived);

有人可以帮助我理解为什么它不读?(对不起,我的英语不好)

这是代码:

当我从 InputStream 中读取时:

public void run(BluetoothDevice device)  {
    Log.i(TAG, "Sono nel run del ConnectedThread");
    dev_recipient = btAdapter.getName();    // se sto per leggere, il destinatario sono io
    dev_sender = device.getName();

    Log.i(TAG, "il mittente è: " + dev_sender);
    Log.i(TAG, "Il destinatario è " + dev_recipient);
    mac_sender = device.getAddress();
    mac_recipient = btAdapter.getAddress();

    byte[] keyRead = new byte[50];
    byte[] sizeRead = new byte[10];
    byte[] timeSent = new byte[100];
    byte[] alreadyReceived = new byte[500];
    String message;
    String sentTime;

    while (true) {                  // finchè è connesso
        try {
            messDB = new MessagesDatabase(context);
            messDB.getWritableDatabase();

            Log.i(TAG, "Destinatario: Ricevo la chiave del messaggio");
            inStream.read(keyRead);
            String keyS = new String(keyRead);
            int indkeyS = keyS.indexOf("#end", 0);
            String key = keyS.substring(0, indkeyS);
            Log.i(TAG, "Stringa chiave del messaggio: " + key);

            Log.i(TAG, "Controllo se ho già ricevuto il messaggio");

            if(messDB.existsMess(key)){
                Log.i(TAG, "Destinatario: Il messaggio è già stato ricevuto");
                Log.i(TAG, "Destinatario: Informa il mittente di non inviare");
                answer = "NO#end";
                outStream.write(answer.getBytes(charsetCod));
                outStream.flush();
                run(device);

            }
            else {
                Log.i(TAG, "Destinatario: Il messaggio non è stato mai ricevuto");
                Log.i(TAG, "Destinatario: Informa il mittente di inviare");
                answer = "YES#end";
                outStream.write(answer.getBytes(charsetCod));
                outStream.flush();

                Log.i(TAG, "Destinatario: Ricevi la grandezza del messaggio");
                inStream.read(sizeRead);
                String s =  new String(sizeRead);
                int ss = s.indexOf("#end", 0);
                Log.i(TAG, "indice di #end: " + ss);
                String sz = s.substring(0, ss);
                Log.i(TAG, sz);
                int size = Integer.parseInt(sz);
                Log.i(TAG, "La grandezza del messaggio è " + size);
                byte[] messageRead = new byte[size];


                Log.i(TAG, "Destinatario: Ricevi il messaggio");
                inStream.read(messageRead);
                message = new String(messageRead);      // converte i bytes in String
                Log.i(TAG, "Ricevuto messaggio dall'inputStream: " + message);

                Log.i(TAG, "Destinatario: ottengo data e ora di ricezione messaggio");
                long receivedTime = System.currentTimeMillis();
                DateFormat df = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss:SSS");
                Date dt = new Date(receivedTime);
                String receivedTimeString = df.format(dt);
                Log.i(TAG, "Il messaggio è stato ricevuto alle " + receivedTimeString);

                Log.i(TAG, "Destinatario: Ricevo ora e data di invio messaggio");
                inStream.read(timeSent);
                sentTime = new String(timeSent);
                int senInd = sentTime.indexOf("#end", 0);
                String sentTimeSender = sentTime.substring(0, senInd);
                Log.i(TAG, "Il messaggio è stato inviato il: " + sentTimeSender);

                Log.i(TAG, "Destinatario: Ricevo gli already received");
                int byteRead = inStream.read(alreadyReceived);
                Log.i(TAG, "sono stati letti " + byteRead + " byte");
                String ar = new String(alreadyReceived);
                Log.i(TAG, ar);
                int arInd = ar.indexOf("#end", 0);
                String myAr = ar.substring(0, arInd);
                Log.i(TAG, myAr);
                String allReceived = myAr.concat(";mac_recipient");
                Log.i(TAG, "AlreadyReceived: " + allReceived);

                Log.i(TAG, "Destinatario: Informo il mittente che ho ricevuto il messaggio");
                String answOk = "OK#end";
                outStream.write(answOk.getBytes(charsetCod));

                String path = saveMessageAsFile(key, message);

                Log.i(TAG, "Destinatario: Invio l'intent per mostrare all'utente il messaggio ricevuto");
                Intent intent = new Intent(ACTION_MESS_READ);
                intent.putExtra("key_mess", key);
                intent.putExtra("messRead", message);
                intent.putExtra("sender", dev_sender);
                context.sendBroadcast(intent);
                Log.i(TAG, "Intent concluso");

                addMessageToDb(key, message, dev_sender, dev_recipient, receivedTimeString, sentTime, path, allReceived, size);

                read(device);
            }

        }
        catch (IOException e) {
            Log.e(TAG, "Disconnesso!", e);
            connectionLost();
            ManageConnections.this.start();     // riavvia la connessione
            break;
        }
    }   
}

对于写作:

public void write(final String key, final BluetoothDevice device) {
        dev_sender = btAdapter.getName();
        dev_recipient = device.getName();
        mac_sender = btAdapter.getAddress();
        mac_recipient = device.getAddress();

        final byte[] answerClient = new byte[10]; 
        final byte[] ricevuto = new byte[10];

        try {  
            final String keyy = key.concat("#end");
            final byte[] keyWrite = keyy.getBytes(charsetCod);
            outStream.write(keyWrite);        // invia la chiave del messaggio
            outStream.flush();
            Log.i(TAG, "Mittente: ho inviato la chiave del messaggio al destinatario, aspetto la risposta..");
            try {
                inStream.read(answerClient);
                final String answerC = new String(answerClient);
                Log.i(TAG, answerC);
                final int ansInd = answerC.indexOf("#end", 0);
                Log.i(TAG, "indice: " + ansInd);
                answer = answerC.substring(0, ansInd);
                Log.i(TAG, "Mittente: la risposta del dispositivo: " + answer);

                if (answer == "NO") {
                    Log.i(TAG, "Mittente: Il messaggio è già stato ricevuto, non inviare");
                    aggiornaAlreadyReceived(device.getAddress(), key);

                }
                else {
                    Log.i(TAG, "Mittente: Il messaggio non è stato ricevuto, invia..");
                    messDB = new MessagesDatabase(context);
                    messDB.getWritableDatabase();
                    final Messaggio m = messDB.getMessage(key);

                    Log.i(TAG, "Mittente: Invio la grandezza del messaggio");
                    final int size = m.getSize();
                    Log.i(TAG, "La grandezza è " + size);
                    final String sizeString = String.valueOf(size);
                    final String ss = sizeString.concat("#end");
                    Log.i(TAG, ss);
                    final byte[] sizeByte = ss.getBytes(charsetCod);                        
                    outStream.write(sizeByte);
                    outStream.flush();


                    Log.i(TAG, "Mittente: Invio il messaggio");
                    final byte[] message = m.getMessage().getBytes(charsetCod);
                    final long sentTime = System.currentTimeMillis();
                    outStream.write(message);
                    outStream.flush();

                    Log.i(TAG, "Mittente: Invio data e ora in cui il messaggio è stato mandato");                      
                    final DateFormat df = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss:SSS");
                    final Date dt = new Date(sentTime);
                    final String sent = df.format(dt);
                    final String sentime = sent.concat("#end");
                    final byte[] sentTimeByte = sentime.getBytes(charsetCod);                      
                    outStream.write(sentTimeByte);
                    outStream.flush();

                    Log.i(TAG, "Mittente: Invio gli already_received");
                    final String myAlRec = m.getAlreadyReceived();
                    Log.i(TAG, myAlRec);
                    final String myAlreadyRec = myAlRec.concat("#end");
                    Log.i(TAG, myAlreadyRec);
                    final byte[] allReceived = myAlreadyRec.getBytes(charsetCod);
                    outStream.write(allReceived);
                    outStream.flush();

                    Log.i(TAG, "Mittente: Aspetto che il destinatario mi informi dell'arrivo del messaggio");
                    String ric = "";
                    inStream.read(ricevuto);
                    final String ricev = new String(ricevuto);
                    Log.i(TAG, "Il destinatario risponde con " + ricev);
                    final int ricInd = ricev.indexOf("#end", 0);
                    ric = ricev.substring(0, ricInd);
                    Log.i(TAG, ric);
                    if(ric == "OK") {
                        Log.i(TAG, "Mittente: Il destinatario ha ricevuto il messaggio");
                        aggiornaAlreadyReceived(mac_recipient, key);
                    }
                    else Log.i(TAG, "Mittente: Il messaggio non è stato ricevuto");

                    Log.i(TAG, "Mittente: Invio l'intent per informare l'utente che il messaggio è stato inviato");
                    final Intent intent = new Intent(ACTION_MESS_WRITE);
                    intent.putExtra("key_mess", key);
                    intent.putExtra("recipient", dev_recipient);
                    intent.putExtra("ric", ric);
                    context.sendBroadcast(intent);
                    Log.i(TAG, "Mittente: Intent concluso");

                }
            }
            catch (final Exception e) {
                Log.e(TAG, "Errore");
                e.printStackTrace();
            }


        }
        catch (final IOException e) {
            Log.e(TAG, "Eccezione durante la scrittura dell'id del messaggio", e);
            e.printStackTrace();
            final Intent intent = new Intent(ACTION_NO_MESSAGE);
            intent.putExtra("key_mess", key);
            context.sendBroadcast(intent);
        }

    }
4

2 回答 2

4
public class BlueTooth
{
    public String tag = "Bluetooth";
    public static final UUID uuid = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
    public BluetoothAdapter adapter;
    public BluetoothDevice device = null;
    public BluetoothSocket socket = null;

    //public static final char ESC = (char) 27;
    //public static final char CR = (char) 13;
    //public static final char LF = (char) 10;

    public BlueTooth(String MAC)
    {
        this(MAC,null);
    }

    @TargetApi(Build.VERSION_CODES.GINGERBREAD_MR1)
    public BlueTooth(String MAC, byte[] pin)
    {
        try
        {
            adapter = BluetoothAdapter.getDefaultAdapter();
            // wait for enable this is not very correct
            if (!adapter.isEnabled()) {
                adapter.enable();
                SystemClock.sleep(5000);
                if (!adapter.isEnabled()) throw new IOException("Bluetooth is off");
            }

            if (!BluetoothAdapter.checkBluetoothAddress(MAC)) throw new Exception("Err MAC adress (" + MAC + ")");

            device = adapter.getRemoteDevice(MAC);
            // this is only for testing purpouse i dont use this
            if (pin!=null)
                setPin(pin);
            // i have some trouble with my device on different OS                
            if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.HONEYCOMB)
                socket = device.createInsecureRfcommSocketToServiceRecord(uuid);
            else
                socket = device.createRfcommSocketToServiceRecord(uuid);

        }
        catch (Exception e)
        {
            throw new RuntimeException(e);
        }
        finally
        {

        }
    }

    public void setPin(byte[] pin)
    {
        try
        {
            Method setPin = device.getClass().getMethod("setPin", byte[].class);
            setPin.invoke(device, pin);
            Log.i("BlueTooth", "PIN is set: "+new String(pin));
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }

    @Override
    protected void finalize() throws Throwable
    {
        disconnect();
        super.finalize();
    }

    // Android REfs recommend to cancel discover
    public boolean connect()
    {
        try
        {
            while (adapter.isDiscovering())
            {
                adapter.cancelDiscovery();
                Thread.sleep(1000);
            }

            socket.connect();
            return true;
        }
        catch(Exception e)
        {
            throw new RuntimeException(e.getMessage(),e);
        }
    }

    // After write is good(only for shure for next write) to clear buffer with flush    
    public void write(byte[] in) throws Exception
    {
        socket.getOutputStream().write(in, 0, in.length);
        socket.getOutputStream().flush();
    }


    // Wait for incomming data
    // if is something in the buffer start count but max 3sec 
    // 3 sec is defined by my device vendor for reply
    //
    // after it we something on buffer.
    // you must realize the reading is on the fly
    // there for you must wait after read to next data sleep(1mxec)
    // until data are available
    // then return
    public byte[] read() throws Exception
    {

        int treshHold = 0;
        while (socket.getInputStream().available()==0 && treshHold<3000)
        {
            Thread.sleep(1);            
            treshHold++;
        }

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        baos.reset();

        while (socket.getInputStream().available() > 0)
        {            
            baos.write(socket.getInputStream().read());
            Thread.sleep(1);   
        }

        return baos.toByteArray();

    }

    // This is little low
    // after disconnect you must create 
    // new socket
    // so after disconnect you are not able to use connect
    // withous createRFcommSocket
    public void disconnect() throws Exception
    {
        if (socket != null) socket.close();
    }
}
于 2013-01-29T17:50:42.893 回答
0

不能说我完全理解您的代码,但有一些提示可能会有所帮助。

请检查管理连接部分。如你看到的;

您应该使用专用线程进行所有流读取和写入。这很重要,因为read(byte[])write(byte[]) 方法都是阻塞调用read(byte[])将阻塞,直到有 东西可以从流中读取write(byte[])通常不会阻塞,但如果远程设备没有足够快地调用read(byte[])并且中间缓冲区已满,则可以阻塞以进行流控制。因此,您在线程中的主循环应该专门用于从 InputStream 中读取数据。

首先,为了获得更好的设计,您应该使用一个专用线程进行读取,另一个线程用于写入。您应该将形成数据的部分分开,将其写入 OutputStream 并从 InputStream 中读取。

当我开始编写Reader Thread时, InputStream 的read(byte[])方法将阻止执行,直到有所需的字节数。但事实并非如此。我发现它确实会阻塞,直到从流中读取“某些东西”(我之前错过的部分)。


您有一个大小为 500 的字节数组。当您“不能”(在这种情况下)部分读取流时,日志中的条目是什么:

int byteRead = inStream.read(alreadyReceived);
Log.i(TAG, "sono stati" + byteRead + " byte");

我的观点是:考虑你的包裹是;0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09,您通过 OutputStream 写入发送它并刷新。您仍然可能在一次 read() 调用中只获得其中的一部分(甚至 1 字节 -> 0x01),并在下一次 read() 调用中获得其余部分(0x02 和其余部分)。在这种情况下byteRead,将等于 1alreadyReceived[0]并将为 0x01,其他元素将为 0

于 2013-01-29T16:43:05.920 回答