Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Сети > Bluetooth в Windows


Автор: juvf 22.9.2016, 10:14
Как взаимодействовать с БТ из винды? Начал использовать "Windows Sockets Support for Bluetooth" но чото лыжи не едут. Делаю следующий алгоритм с winsock

Код

Код

socket();
connect();
send(sock, array, 8, 0);
shutdown(sock, SD_SEND);
recv();


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

если без остановки выполнить.... то send() возвращает 8, shutdown() возвращает 0, recv() возвращает 0. Удаленное устройство видит подключение, но не получает ни одного байта. если между этими функциями понаставить пауз секундных, то код выполняется без остановки нормально... уходит запрос и возвращается ответ. Почему без пауз не работает? Если из-за неблокирующего сокета, то как сокет сделать блокирующим?

ps Может вместо этой API есть более годные либы для работы с bluetooth под винды?

Автор: feodorv 22.9.2016, 10:45
Цитата(juvf @  22.9.2016,  10:14 Найти цитируемый пост)
recv() возвращает 0

С неблокирующими сокетами данные же нужно подождать, пока придут. Если просто вызвать recv(), то система заглянет в буфер приёма, увидит, что он пуст, и вернёт 0. Всё правильно. А ждать данные в винде можно через WSAEVENT/WSAWaitForMultipleEvents или через select.

Автор: juvf 22.9.2016, 11:05
да у меня даже отправки нет.... send(sock, array, 8, 0); видать помещает данные в буфер передачи и сразу вызвращается.... а следом идет shutdown(sock, SD_SEND); Удаленное устройство по БТ не получает ни одного байта.

 
Цитата

 А ждать данные в винде можно через ... select.
 
Я пробовал через селект..... не получилось. Есть пример работы с скоетами через селект?

Автор: feodorv 22.9.2016, 13:15
Цитата(juvf @  22.9.2016,  11:05 Найти цитируемый пост)
видать помещает данные в буфер передачи и сразу вызвращается.... 

Да.

Цитата(juvf @  22.9.2016,  11:05 Найти цитируемый пост)
а следом идет shutdown(sock, SD_SEND);

Оно не должно помешать:
Цитата
If the how parameter is SD_SEND, subsequent calls to the send function are disallowed. For TCP sockets, a FIN will be sent after all data is sent and acknowledged by the receiver.


Цитата(juvf @  22.9.2016,  11:05 Найти цитируемый пост)
Удаленное устройство по БТ не получает ни одного байта.

Это не понятно. Это точно установлено? А в случае с блокируемыми сокетами всё было в порядке?

Цитата(juvf @  22.9.2016,  11:05 Найти цитируемый пост)
Есть пример работы с скоетами через селект? 

Внятного примера у меня не нашлось, давно работаю через события (чего и Вам желаю). Отличия от юниксовского подхода есть (в основном в области обработки ошибок), но мало. В инете примеры https://forum.antichat.ru/threads/124863/.

Автор: juvf 22.9.2016, 14:03
Цитата

Это не понятно. Это точно установлено? А в случае с блокируемыми сокетами всё было в порядке?
 У меня не было случая с блокируемым сокетом, у меня были случай с паузами между командами. Да, было всё в порядке.

Цитата

Оно не должно помешать:
Цитата

If the how parameter is SD_SEND, subsequent calls to the send function are disallowed. For TCP sockets, a FIN will be sent after all data is sent and acknowledged by the receiver.

 Ну это неизвестно. Для TCP сокета это не мешает. Для БТ сокета чото не работает.

Добавлено через 9 минут и 49 секунд
Цитата

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

Автор: feodorv 23.9.2016, 12:58
Цитата(juvf @  22.9.2016,  14:03 Найти цитируемый пост)
В API винды такого метода нет.

http://icourse.cuc.edu.cn/networkprogramming/resources/Books/Windows%20Socket%202_Specs/WinSocketAPIv22c.pdf в инете "Windows Sockets 2 Application Programming Interface" и узнаете, чего есть в виндах, чего нету  smile  Например, про ioctlsocket(FIONBIO). И что сокет после создания тоже блокирующий. 


Цитата(juvf @  22.9.2016,  14:03 Найти цитируемый пост)
 У меня не было случая с блокируемым сокетом, у меня были случай с паузами между командами. Да, было всё в порядке.

Тогда я ничего не понимаю))) Как у Вас всё это работало на неблокирующих сокетах без селекта или событий?


Цитата(juvf @  22.9.2016,  14:03 Найти цитируемый пост)
для винды для блютуза не могу найти

Тут, увы, мне сказать нечего. С блютусом не работал, опыта нет.

Автор: juvf 23.9.2016, 13:43
Цитата

узнаете, чего есть в виндах, чего нету  smile  Например, про ioctlsocket(FIONBIO).
я это знаю.... эти знания не помогают. 

Цитата

socket();
connect();
u_long iMode=0;
ioctlsocket(sock,FIONBIO,&iMode);
send(sock, array, 8, 0);
shutdown(sock, SD_SEND);
recv();
не помогает.

Цитата

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

Код

socket();
connect();
pause_ms(3000);
send(sock, array, 8, 0);
pause_ms(3000);
shutdown(sock, SD_SEND);
pause_ms(3000);
recv();
из чего я делаю вывод что сокет при создании не блокирующий. хотя эти выводы тоже не верны... т.к. сокет может заблокировался на 10 мс, а блютузу надо больше времени. кстати... как указать сокету сколько времени сокет должен находиться в блокированном состоянии?

ps хотя если сокет вывалится по таймауту, то send или recv тернёт WSAETIMEDOUT, но этого не происходит.

Автор: feodorv 25.9.2016, 13:18
Цитата(juvf @  23.9.2016,  13:43 Найти цитируемый пост)
зато такой код работает

Честно говоря, не знаю в чём дело. Возможно, в параметрах открытия сокета, ведь их Вы не привели.


Цитата(juvf @  22.9.2016,  14:03 Найти цитируемый пост)
для винды для блютуза не могу найти

Первые ссылки по двум ключевым словам "bluetooth" и "socket" дают искомый результат. Например, http://www.winsocketdotnetworkprogramming.com/winsock2programming/winsock2advancedotherprotocol4p.html. http://www.winsocketdotnetworkprogramming.com/winsock2programming/winsock2advancedotherprotocol4j.html, как получить адрес.

Автор: juvf 25.9.2016, 13:22
Цитата

Честно говоря, не знаю в чём дело. Возможно, в параметрах открытия сокета, ведь их Вы не привели.



Код

#pragma comment(lib, "ws2_32.lib")

DEFINE_GUID(SerialPortServiceClass_UUID,0x00001101,0x0000,0x1000,0x80,0x00,0x00,0x80,0x5F,0x9B,0x34,0xFB);

bool Bloutooth::setConnect(QString &error, const QString &teremName)
{
    WSADATA wsa;
    if( WSAStartup(MAKEWORD(2,2), &wsa) !=0)
        return false;


    sock = socket(AF_BTH, SOCK_STREAM, BTHPROTO_RFCOMM);
    if (sock == INVALID_SOCKET)
    {
        //        //Ошибка
        WSACleanup();
        return false;
    }

    u_long iMode = 0;
    int iResult;
    iResult = ioctlsocket(sock, FIONBIO, &iMode);

    SOCKADDR_BTH sab = {0};
    sab.addressFamily  = AF_BTH;
    sab.btAddr = 0X0007800cfae7;
    sab.serviceClassId = SerialPortServiceClass_UUID;
    sab.port = 1;

    if(  ::connect(sock, (struct sockaddr *)&sab, sizeof(SOCKADDR_BTH)) == SOCKET_ERROR)
    {
        iResult = WSAGetLastError();
        error = qt_error_string(WSAGetLastError());//QString("Error open socket. Code of error: %1 \n%2").arg(iResult).arg(getLastErrorAsString());
        closesocket(sock);
        WSACleanup();
        return false;
    }
    isConnected = true;

    return true;
}


за ссылки спасибо!

Добавлено через 3 минуты и 57 секунд
и до кучи передача и прием

Код

QString Bloutooth::readVersion()
{
    QString replay("");
    char array[100] = {0x80, 8, 0xff, 0x7f, 2, 0x27};
    if(isConnected)
    {
        array[2] = this->getAddress();
        Checksum::addCrc16((unsigned char*)array, 6);
        int iResult;
            iResult = ::send(sock, array, 8, 0);
            if (iResult == SOCKET_ERROR)
            {
                qt_error_string(WSAGetLastError());

                return getLastErrorAsString();
            }


            iResult = shutdown(sock, SD_SEND);

           iResult = ::recv(sock, array, 100, 0);
            if(iResult >= 8)
            {
                array[iResult - 2] = 0;
                replay = QString(&array[6]);
                return replay;
            }
            else if(iResult == 0)
                replay = "Connection closed";
            else
                replay = getLastErrorAsString();
        }
    }
    return replay;
}


Добавлено через 12 минут и 2 секунды
ps забегая вперёд..... вот работая с обычным компортом или с бинарным ТСП сокетом я обмен осуществлял так

-открытие компорта
-отправка запроса
-ожидание ответа
-обработка ответа
-отправка запроса
-приме и отбработка ответа
.....
....
-закрытие порта

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

Автор: feodorv 30.9.2016, 06:53
Прошу прощения за долгое молчание smile 

http://www.winsocketdotnetworkprogramming.com/winsock2programming/winsock2advancedotherprotocol4o.html можно найти такую фразу: 
Цитата

Bluetooth uses the shutdown() function to disconnect from the remote radio. Bluetooth does not have protocol-level support for the same graceful closes or half-closes that TCP/IP provides.
Так что не понятно, насколько этот shutdown() нужен, хотя его суют во все примеры (может, и не зря). Я бы попробовал без него.


Цитата(juvf @  25.9.2016,  13:22 Найти цитируемый пост)
как с блютузом и сокетами в этом случае? получается так
-открытие сокета блютуза
-отправка запроса
-закрытие передачи (шатдаун сенд)
-ожидание ответа
-обработка ответа
-... а дальше? можно сразу посылать новый запрос? там был сделан шатдаунд сенд. как после этого делать передачу? или после приема надо сделать шатдаунт приема и делать передачу? или надо открыть и закрыть сокет? 

Всё зависит от того, как на той стороне работает сервер. Если он способен только на один запрос-ответ, то придется каждый раз открывать новое соединение, а затем его закрывать. Если же сервер может обрабатывать множественные запросы, то, конечно, можно обойтись одним сокетом.


Очень надеюсь, что у Вас что-нибудь разрешилось за это время smile 

Автор: juvf 30.9.2016, 07:07
Цитата

Очень надеюсь, что у Вас что-нибудь разрешилось за это время
Спасибо за поддержку.... Нет, не разрешилось. Собираюсь писать в поддержку msdn. Пока работаю с БТ через виртуальный компорт. Но хотелось бы как то напрямую передавать/читать данные. Если что получиться, то отпишусь

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)