Как сделать flush bluetooth-сокета в C (Linux)?

    Вчера столкнулась с тем, что написанная мною серверная программа (Fedora 10, C), общающаяся с моим же мобильным клиентом (Symbian 9.1, Mobile Python for Series 60) стала давать сбой при пересылке файла.

    _____________________________________________________
    P.S.: Жаль, что никто не откликнулся советом… Впрочем, уже сама разобралась. Оказывается, стоит контролировать значение, возвращаемое функцией write() — реально может отправляться меньше байт, чем пыталась переслать программа. Пытаясь отправить массив байт, стоит проверять, сколько байт реально отправилось — и упорно досылать неотправленное.
    _____________________________________________________

    До вчерашнего дня сбоев не было. При этом отладочная печать серверной программы показывает, что файл отправлен полностью. Отладочная печать клиентского приложения говорит, что файл считан не полностью. Код клиента и сервера не менялся, софт на компе и телефоне я не обновляла, новый не устанавливала.

    Другие файлы прекрасно отправляются этими же программами с сервера на телефон и обратно. Проблема лишь с новой версией отправляемого jar-файла — с 20К он вырос до 38К. Смотрела код пересылаемого файла, чтобы понять, не обрывается ли передача на байте вроде FF — нет, в этом месте вполне рядовая последовательность байтов: ...00 60 39 00 00… (39 — последний переданный байт).

    Подозреваю, что проблема — в буферизации вывода в сокет: сервер отправил не всю информацию, а клиент ждет, когда весь объем информации будет передан. Хотя странно, что при постоянном ежедневном использовании сервера и клиента эта ошибка проявилась первый раз. Но способа сделать flush сокету я пока не нашла (fflush(bt->socketClient) дает ошибку сегментирования — и, как я понимаю, для сокета, созданного описанным ниже способом, неприменим).

    Вот код, который создает сокет и пытается отправить чеез него файл:
    struct BT_SDESC {
      unsigned char channel;
      unsigned int uuid;
      char *serviceName;
      char *serviceDescription;
      char *serviceProvider;
      void *session;
      int hciID;
    };
    
    // Bluetooth server
    struct BT_SRV {
      struct BT_SDESC *sd;
      int socketClient;
      int socketServer;
    };
    
    ...
    
    struct BT_SDESC *btBuildSDesc(int channel) {
      struct BT_SDESC *sd;
      sd=(struct BT_SDESC *)malloc(sizeof(struct BT_SDESC));
      if (!sd) {
        return NULL;
      }
      memset(sd,0,sizeof(struct BT_SDESC));
      sd->channel = channel;
      sd->uuid = 0xAFFF; /* TODO: check what is this value */
      if( !(sd->serviceName = strdup("TeleComp: W-Shell"))
        || !(sd->serviceDescription = strdup("User Shell for Wearable Computer"))
        || !(sd->serviceProvider = strdup("kiborgov.net"))
        ) {
        btDestroySDesc(sd);
        return NULL;
      }
      return sd;
    }
    
    int btSDescribe(struct BT_SDESC *sd) {
      uint32_t serviceUuidInt[]={0,0,0,sd->uuid};
      uuid_t serviceUuid, rootUuid, l2capUuid, rfcommUuid;
      sdp_record_t *record=sdp_record_alloc();
      sdp_session_t *session=NULL;
      sdp_list_t *rootList=NULL, *svClassID=NULL, *profilesList=NULL, *l2capList=NULL, *protocolList=NULL, *rfcommList=NULL, *accessProtocolList=NULL;
      sdp_profile_desc_t profile;
      sdp_data_t *channel=NULL;
      int ret=-2;
    
      /* Set general service ID */
      sdp_uuid128_create(&serviceUuid, &serviceUuidInt);
      sdp_set_service_id(record, serviceUuid);
    
      /* Public service record */
      sdp_uuid16_create(&rootUuid, PUBLIC_BROWSE_GROUP);
      rootList = sdp_list_append(0, &rootUuid);
      sdp_set_browse_groups(record, rootList);
    
      /* Set port attributes */
      sdp_uuid16_create(&rootUuid, SERIAL_PORT_SVCLASS_ID);
      svClassID = sdp_list_append(0, &rootUuid);
      sdp_set_service_classes(record, svClassID);
    
      sdp_uuid16_create(&profile.uuid, SERIAL_PORT_PROFILE_ID);
      profile.version = 0x100;
      profilesList = sdp_list_append(0, &profile);
      sdp_set_profile_descs(record, profilesList);
    
      /* Set l2cap info */
      sdp_uuid16_create(&l2capUuid, L2CAP_UUID);
      l2capList = sdp_list_append(0, &l2capUuid);
      protocolList = sdp_list_append(0, l2capList);
    
      /* Set rfcomm info */
      sdp_uuid16_create(&rfcommUuid, RFCOMM_UUID);
      channel = sdp_data_alloc(SDP_UINT8, &(sd->channel));
      rfcommList = sdp_list_append(0, &rfcommUuid);
      sdp_list_append(rfcommList, channel);
      sdp_list_append(protocolList, rfcommList);
    
      /* Attach protocol information to service record */
      accessProtocolList = sdp_list_append(0, protocolList);
      sdp_set_access_protos(record, accessProtocolList);
    
      /* Set name, provider, description */
      sdp_set_info_attr(record, sd->serviceName, sd->serviceProvider, sd->serviceDescription);
    
      /* Connect local SDP  server, register service record, then disconnect */
      if ((session=sdp_connect(BDADDR_ANY, BDADDR_LOCAL, SDP_RETRY_IF_BUSY))) {
        ret=sdp_record_register(session, record, 0);
      }
    
      /* Free allocated resources */
      sdp_data_free(channel);
      sdp_list_free(l2capList, 0);
      sdp_list_free(rfcommList, 0);
      sdp_list_free(rootList, 0);
      sdp_list_free(accessProtocolList, 0);
      sdp_list_free(svClassID, 0);
      sdp_list_free(profilesList, 0);
    
      sd->session = (void *)session;
    
      return ret;
    }
    
    int btBuildSocket(unsigned int channel, struct BT_SDESC *sd) {
      struct sockaddr_rc localAddr;
      int s=-1, res=-1;
    
      if ((sd->hciID=btCheckDevice())==-1) {
        return -1;
      }
      if (hci_open_dev(sd->hciID)<0) {
        return -1;
      }
      hci_close_dev(sd->hciID);
      memset(&localAddr, 0, sizeof(struct sockaddr_rc));
      if ((s=socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM))==-1) {
        return -1;
      }
    
      /* TODO: replace code below with code uses SDP */
      localAddr.rc_family = AF_BLUETOOTH;
      localAddr.rc_bdaddr = *BDADDR_ANY;
      localAddr.rc_channel = (uint8_t) channel;
      if ( (res=bind(s, (struct sockaddr *) &localAddr, sizeof(localAddr)))==-1 ) {
        close(s);
        return -1;
      }
    
      return s;
    }
    
    struct BT_SRV *btStartServer(int channel) {
      struct BT_SRV *bt=malloc(sizeof(struct BT_SRV));
      if (!bt) {
        btErr=BT_ERR_START_SERVER;
        btKillServer(bt);
        return NULL;
      }
      memset(bt, 0, sizeof(struct BT_SRV));
      bt->socketServer=bt->socketClient=-1;
      btErr=BT_OK;
    
      if (btCheckDevice()<0) {
        btErr=BT_ERR_NO_DEVICE;
        btKillServer(bt);
        return NULL;
      }
    
      if ( !(bt->sd=btBuildSDesc(channel)) ) {
        btErr=BT_ERR_SDESC_CREATION;
        btKillServer(bt);
        return NULL;
      }
    
      if (btSDescribe(bt->sd)==-1) {
        btErr=BT_ERR_SDESC_REGISTRATION;
        btKillServer(bt);
        return NULL;
      }
    
      if ((bt->socketServer=btBuildSocket(channel, bt->sd))==-1) {
        btErr=BT_ERR_BUILD_SOCKET;
        btKillServer(bt);
        return NULL;
      }
    
      if (listen(bt->socketServer,10)) {
        btErr=BT_ERR_SOCKET_LISTENING;
        btKillServer(bt);
        return NULL;
      }
      return bt;
    }
    
    ...
    
    struct BT_SRV *bt=NULL;
    
    int sendFileToClient(char *fname) {
      static char buf[1024];
      int h;
      long int bufsize=1024;
      long int sent=0;
      long int loaded;
      struct stat stbuf;
    logPrint("Send file \"%s\" to client.",fname);
      if (stat(fname,&stbuf)==-1) {
    logPrint("ERROR: cannot retreive file information.");
        return -1;
      }
      if ((h=open(fname,O_RDWR))<1) {
    logPrint("ERROR: cannot open file.");
        return -2;
      }
      sprintf(buf,"%010ld",stbuf.st_size);
    logPrint("Sending %ld bytes of data...",stbuf.st_size);
      write(bt->socketClient, buf, 10);
      while (sent<stbuf.st_size) {
        loaded=(stbuf.st_size>bufsize)?bufsize:stbuf.st_size;
        loaded=read(h,&buf,loaded);
        if (loaded<1) {
          break;
        }
        sent+=loaded;
        write(bt->socketClient, buf, loaded);
    logPrint("sent: %ld",sent);
      }
      close(h);
    logPrint("File is sent. %ld bytes transmitted.",sent);
      return sent;
    }
    
    ...
    
      bt=btStartServer(cfgBtChannel);
      ...
      bt->socketClient=accept(bt->socketServer,NULL,NULL);
      fcntl(bt->socketClient,F_SETFL,O_NONBLOCK);
      sendFileToClient("./projects/cloud/bin/Cloud.jar");
    

    Передача файла, на котором случается сбой, обрывается то на одном (в 80% случаев) месте файла, то на втором (в оставшихся 20%).
    Поделиться публикацией

    Похожие публикации

    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама

    Комментарии 3

      0
      а гденить можно скачать код сервера и клиента? сама идея носимово компутера достаточно интересна и я сам подумывал об чёмто таком.

      у меня есть 901 и трео650 (палмос, на нём есть какаято ява) — было бы интересно попробовать. есть также и е60 гдето в комоде, можно и его потестировать :)
        0
        Пока проект не выложен. Сейчас дописываю бета-версию J2ME клиента, как допишу, планирую заопенсорсить клиент и сервер. Адрес страницы проекта (пока там, правда, ничего нет) — advegam.tigris.org/

        Oops, не туда запостила ответ :(
        0
        Пока проект не выложен. Сейчас дописываю бета-версию J2ME клиента, как допишу, планирую заопенсорсить клиент и сервер. Адрес страницы проекта (пока там, правда, ничего нет) — advegam.tigris.org/

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

        Самое читаемое