РФКОММ | Как получить уведомление, когда Клиент отключается, и записать данные клиенту?

Я использую приложение RFCOMM Server на стороне Linux, чтобы любое мобильное приложение могло подключиться к нему и установить связь. Я использовал пример rfcomm-server.c для тестирования и немного изменил его

#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/rfcomm.h>

struct sockaddr_rc loc_addr = { 0 }, rem_addr = { 0 };
char buf[1024] = { 0 };
int s, client, bytes_read, status;
socklen_t opt = sizeof(rem_addr);

void vCreateConnection()
{
    // allocate socket
    s = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);

    // bind socket to port 1 of the first available 
    // local bluetooth adapter
    loc_addr.rc_family = AF_BLUETOOTH;
    loc_addr.rc_bdaddr = *BDADDR_ANY;
    loc_addr.rc_channel = (uint8_t) 1;
    bind(s, (struct sockaddr *)&loc_addr, sizeof(loc_addr));

    // put socket into listening mode
    listen(s, 1);

    // accept one connection
    client = accept(s, (struct sockaddr *)&rem_addr, &opt);
    ba2str( &rem_addr.rc_bdaddr, buf );
    fprintf(stderr, "accepted connection from %s\n", buf);

}

void vCloseConnection()
{
    close(client);
    close(s);
}

int main(int argc, char **argv)
{

    vCreateConnection();
    while(1)
    {
        printf("\r\nClear buffer");
        memset(buf, 0, sizeof(buf));

        // read data from the client
        bytes_read = read(client, buf, sizeof(buf));
        if( bytes_read > 0 ) {
            printf("received [%s]\n", buf);
            //if(status == 0)
            {
                printf("send [%s]\n", buf);
                status = write(s, &buf, 1);
                //status is not making any difference.
                //if(status < 0)
                    //break;
            }
        }
        if(buf[0] == 'q')
        {
            vCloseConnection();
            vCreateConnection();
        }
        else if(buf[0] == 'x')
            break;
    }
    // close connection
    close(client);
    close(s);
    return 0;
}
  1. Здесь я могу подключиться и отправлять данные из Android-приложения BlueTerm. Но когда я отключаюсь от устройства от Android, я не уверен, что мое приложение linux может обнаружить, что клиент отключен, и я могу вернуть его в режим принятия нового подключения, закрыв текущий активный сеанс?
  2. Я также не уверен, что это правильный способ ответить клиенту, эта функция для обратной записи клиента?

status = write(s, &buf, 1);

1 ответ

read(client, buf, sizeof(buf)) возвращает -1, если клиент отключился. Итак, цикл до тех пор, пока bytes_read больше или равно нулю и воссоздает сервер после выхода из цикла.

Я переписал вашу основную функцию, включив цикл while в другой цикл, который выполняется до тех пор, пока "x" не будет получено от устройства Bluetooth.

int recreate_connection=1;
int main(int argc, char **argv)
{
    while(recreate_connection==1)
    {
        vCreateConnection();
        bytes_read=0;
        while(bytes_read >=0)
        {
            printf("\r\nClear buffer");
            memset(buf, 0, sizeof(buf));

            // read data from the client
            bytes_read = read(client, buf, sizeof(buf));
            if( bytes_read > 0 ) {
                printf("received [%s]\n", buf);
                //if(status == 0)
                {
                    printf("send [%s]\n", buf);
                    status = write(s, &buf, 1);
                    //status is not making any difference.
                    //if(status < 0)
                        //break;
                }
            }
            if(buf[0] == 'q')
            {
                vCloseConnection();
                break;          
            }
            else if(buf[0] == 'x')
            {
                recreate_connection=0;
                break;
            }
        }
    }
    // close connection
    close(client);
    close(s);
    return 0;
}

Чтобы добавить к ответу @Avinab Malla, -1 не означает, что узел обязательно отключился. Это важно отметить, потому что, если вы используете неблокирующий сокет, вы всегда получите -1, если нечего читать, с ошибкой (EWOULDBLOCK). В этом случае вы не хотите разрывать петлю. Вы можете найти все системные ошибки Linux здесь: http://www-numi.fnal.gov/offline_software/srt_public_context/WebDocs/Errors/unix_system_errors.html. Чтобы правильно обрабатывать -1 при чтении, я предложу что-то вроде этого:

do {
        memset(comBuffer, 0, sizeof(comBuffer));

        // read data from the client
        bytesRead = read(clientSockDescriptor, comBuffer, sizeof(comBuffer));

        if (bytesRead < 1) {
            if (errno == EWOULDBLOCK) {
                continue;
            }
            else {
            //You can either exit you read loop here or check the error for something specific
            // A peer reset (the client disconneted ) is error: ECONNRESET
                printf("A read error occured %d \n", errno);
                break;
            }
        }
        // Processes your buffer here.....

    } while (clientSockDescriptor != -1 && runComServer); //The while you have your true clause
Другие вопросы по тегам