Select() WinSOCK

0

Witam,

Pisze serwer odbierający dane UDP broadcast ( w BCB ) używając funkcji recvfrom().
Funkcja ta niestety jest blokująca, i "wiesza" mi program, a ja w międzyczasie muszę wykonywać w nim
inne operacje, więc muszę jakoś uniknąć blokowania.
Poczytałem artykuły i doszedłem do wniosku że pomoże mi funkcja select() lub/i ioctlsocket ( raczej
nie chciałbym używać wątków ).

Proszę o wskazówki w jaki sposób pozbyć się blokowania... Napisałem poniższy kod z użyciem
wspomnianego select i ioctlsocket, jednak nadal to nie to o co mi chodziło. Prawdopodobnie popełniłem
gdzieś wstrętną gafę ;-P

Nie wiem czy dobrze kombinowałem - chciałem za pomocą select() funkcją FD_ISSET wykrywać czy na
gnieździe s_socket są dane do odebrania, jeśli tak, to przełączam gniazdo w stan blokowania ( i
odbierania ), a jeśli nie ma danych do odebrania to w stan nieblokujący...

Niedziałający poprawnie fragment kodu odpowiedzialny za odbieranie UDP z użyciem select ( wszystko w Timerze ):

      //------------------------------------------------------------------------
      // Utworzenie gniazda
      //------------------------------------------------------------------------

        if (WSAStartup( MAKEWORD( 2 , 0 ) , &WSD) != 0) {
	Label1->Caption="Nie udało się wczytac biblioteki WinSock...!";
	}

      s_socket=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);  

      char broadcast = '1';

      if(setsockopt(s_socket,SOL_SOCKET,1,&broadcast,sizeof(broadcast)) < 0)
      {
      Label1->Caption="Błąd podczas ustawiania opcji broadcastu...";
      closesocket(s_socket);
      }

      //------------------------------------------------------------------------
      // ODEBRANIE datagramu
      //------------------------------------------------------------------------

      SenderAddr.sin_family=AF_INET;
      SenderAddr.sin_port=htons(67); 
      SenderAddr.sin_addr.s_addr=INADDR_ANY;

        if (bind(s_socket,(sockaddr*)&SenderAddr, sizeof (SenderAddr)) < 0)
        {
        Label1->Caption="Nie udało się wykonac bind dla socketu...";
        closesocket(s_socket);
        }


        fd_set read, write, excp;         // SELECT()

        int max = s_socket;

        FD_ZERO(&read);
        FD_SET(s_socket, &read);

        struct timeval timeout;
        timeout.tv_sec = 1;
        timeout.tv_usec = 0;


        if(select(max + 1, &read, NULL, NULL, &timeout))
        {

                if(FD_ISSET(s_socket, &read))
                {
                 unsigned long flags=0;
                 ioctlsocket(s_socket, FIONBIO, &flags);
                 recvfrom(s_socket,RecvBuf,BufLen,0,(SOCKADDR *)&SenderAddr,&SenderAddrLen);
                }
                else
                {
                 unsigned long flags=1;
                 ioctlsocket(s_socket, FIONBIO, &flags);
                }

        } else Label1->Caption="Błąd select()";
0

Pod linuchem jest flaga, ktora moze Ci pomoc i zapewne znajdziesz odpowiednik pod Windowsem, ale do konca nie wiem, czy o to Ci sie rozchodzi.

Mowa o SO_RCVTIMEO. Za pomoca niej mozesz ustawic maksymalna wartosc czasu oczekiwania na dane, wiec nie bedzie Ci blokowac programu, jesli nastawisz na malutka wartosc.

Druga mozliwosc tez nie wiem czy pod Windowsem dostepna to ustawic sygnalizator O_NONBLOCK w parametrach funkcji recvfrom.

0

blad, blad: nie w parametrach O_NONBLOCK, tylko za pomoca fcntl na sockecie.

0

Proszę o wskazówki w jaki sposób pozbyć się blokowania...

Rób transmisję w osobnym wątku. Niech się blokuje, ale reszta programu w tym czasie się kręci.

0
mac_ldz napisał(a)

raczej nie chciałbym używać wątków

Azarien napisał(a)

Proszę o wskazówki w jaki sposób pozbyć się blokowania...

Rób transmisję w osobnym wątku. Niech się blokuje, ale reszta programu w tym czasie się kręci.

0

Dzięki wielkie za odp

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.