Как заставить NSOutputStream немедленно отправлять или сбрасывать пакеты - PullRequest
1 голос
/ 30 июня 2011

У меня проблема с задержкой при подключении к Bluetooth-аксессуару с помощью External Accessory Framework. При отправке данных я получаю следующий пользовательский вывод в консоли:

if( [stream hasSpaceAvailable] )
{
   NSLog( @"Space avail" );
}
else {
    NSLog(@"No space");
}
while( [stream hasSpaceAvailable] && ( [_outputBuffer length] > 0 ) )
{
    /* write as many bytes as possible */
    NSInteger written = [stream write:[_outputBuffer bytes] maxLength:[_outputBuffer length]];
    NSLog( @"wrote %i out of %i bytes to the stream", written, [_outputBuffer length] );
if( written == -1 )
    {
        /* error, bad */
        Log( @"Error writing bytes" );
        break;
    }
    else if( written > 0 )
    {
        /* remove the bytes from the buffer that were written */
        Log( @"erasing %i bytes", written );
        [_outputBuffer replaceBytesInRange:NSMakeRange( 0, written ) withBytes:nil length:0 ];
    }
}

Это приводит к следующему выводу, где буфером немедленной упаковки является полезная нагрузка.

immediate pack buffer-> 040040008
Space avail
wrote 10 out of 10 bytes to the stream
immediate pack buffer-> 040010005
No space
immediate pack buffer-> 030040007
No space
wrote 20 out of 20 bytes to the stream
immediate pack buffer-> 030010004
No space
immediate pack buffer-> 040000004
Space avail
wrote 20 out of 20 bytes to the stream
immediate pack buffer-> 030000003
Space avail
wrote 10 out of 10 bytes to the stream
immediate pack buffer-> 040040008
Space avail
wrote 10 out of 10 bytes to the stream

Обратите внимание, что на нем постоянно записывается «без пробела», что означает, что метод hasSpaceAvailable возвращает false и вынуждает буферизовать данные до тех пор, пока он не вернет true.

1) Мне нужно знать, почему это происходит? Это ждет Ack от оборудования BT? Если да, то как вы снимаете эту блокировку?

2) Как вы делаете это, чтобы он отправлял немедленно, и мы в основном передаем данные в режиме реального времени без буферизации?

3) Есть ли скрытый метод API, который отключит эту блокировку?

Это реальная проблема, поскольку при отправке данных на устройство не может быть никаких задержек / задержек, их необходимо отправить немедленно, чтобы оборудование синхронизировалось с командами iPhone. Пожалуйста, помогите.

Ответы [ 3 ]

2 голосов
/ 30 июня 2011

То, что вы запрашиваете, невозможно с большинством аппаратного обеспечения (которое заканчивает отправку текущего пакета перед запуском следующего), и невозможно с обычной парадигмой «потока» (которая требует, чтобы данные принимались по порядку, поэтому с ограниченной шириной полосы частот).

Также физически невозможно иметь нулевую задержку, если источник и пункт назначения не совпадают.

Фактическая проблема заключается в том, что базовый поток ставит в очередь только один пакет за раз, даже если длина пакета составляет всего 10 байтов. Я не знаю почему; возможно, потому что он задуман как очень простой протокол.

Обычный способ справиться с такой очередью - зарегистрироваться для соответствующих обратных вызовов делегата и отправить столько данных, сколько вы можете, когда у потока есть свободное место, вместо ожидания следующей попытки отправки данных (которая появляется быть тем, что ты делаешь).

0 голосов
/ 30 июля 2014

У меня та же проблема, но в другом сценарии.

Сценарий : приложение для iPhone может связываться с PED при первом подключении. Но когда батарея PED умирает или выключается, а затем включается, приложение не может связываться с PED, несмотря на активный сеанс и действительный выходной поток. Вывод steam говорит, что у него нет шанса написать что-либо.

Решение : Когда PED переключается, приложение получает уведомление, и в этот момент я заставляю приложение завершить EASession и создать его снова, когда PED получает соединение. Не уверен, что это лучшее решение. Пожалуйста, предложите другое решение, если оно есть.

0 голосов
/ 08 июля 2013

Проблема в том, что функция делегата HandleEvent представляет собой асинхронный вызов. Поэтому каждый раз, когда она не попадает в делегат. То, что вы можете сделать, это иметь сразу несколько команд в массиве, открыть сеанс, вызвать функцию writeData. Что здесь происходит, когда вызывается запись данных, вам не нужно вызывать функцию HandleEvent каждая команда. Увеличьте счетчик в функции writeData для счетчика элементов массива, пока count == arrayItems, Делегат не ударил ..

Таким образом, все команды из списка отправляются одна за другой.

...