2

Bluetooth経由で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から読み取る必要があります。

リーダースレッドのコーディングを開始すると、 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書き込みを介して送信し、フラッシュしました。1回のread()呼び出しでその一部(1バイト-> 0x01でも)を取得し、次のread()呼び出しで残り(0x02と残り)を取得する場合があります。この場合byteRead、1に等しく、alreadyReceived[0]0x01になり、他の要素は0になります。

于 2013-01-29T16:43:05.920 に答える