2017-04-24 126 views
0

有一些點,我不明白select(),我希望你的指導。當我讀到這個功能,我發現討論關於select()

的select()函數爲您提供了一種方法來同時檢查 多個插槽),看看他們是否有數據等待的recv(d,或如果 您可以發送()數據給他們沒有阻塞,或者如果發生了一些異常 。

1)我明白的第一件事是該函數可以並行檢查套接字。現在想象一下sock1和sock2在同一時間接收數據包(來自sock1的數據包1和來自sock2的數據包2),並且必須對每個數據包進行一些處理。並行處理數據包?或者packet1會處理數據包2會處理? (例如,在下面的代碼)

int rv = select(maxSd, &readfds, NULL, NULL, NULL); 

if (rv == -1) { 
    perror("select"); // error occurred in select() 
} else if (rv == 0) { 
    printf("Timeout occurred! No data after 10.5 seconds.\n"); 
} else { 
    // one or both of the descriptors have data 
    if (FD_ISSET(sock1, &readfds)) { 
     printf("socket %i RECEIVED A PACKET \n", sock1); 
     recvlen = recvfrom(sock1, buf, BUFSIZE, 0, (struct sockaddr *)&remaddr1, &addrlen1); 
     if (recvlen > 0) { 
      buf[recvlen] = 0; 
      printf("received message: \"%s\" (%d bytes)\n", buf, recvlen); 
      Packet mp; 
      mp.de_packet((unsigned char *)buf,recvlen); 
     } 
     else { 
      printf("uh oh - something went wrong!\n"); 

     } 
    } 
    if (FD_ISSET(sock2, &readfds)) { 
     printf("socket %i RECEIVED A PACKET \n", sock2); 
     recvlen2 = recvfrom(sock2, buf2, BUFSIZE, 0, (struct sockaddr *)&remaddr2, &addrlen2); 
     if (recvlen2 > 0) { 
      buf[recvlen2] = 0; 
      printf("received message2: \"%s\" (%d bytes)\n", buf2, recvlen2); 
      Packet mp; 
      mp.de_packet((unsigned char *)buf,recvlen); 
     } 
     else 
      printf("uh oh - something went wrong2!\n");       
    } 
} 

2)關於選擇其它疑問,我已經涉及阻塞和非阻塞。 阻塞的意義究竟是什麼?這是否意味着程序停止在這條線上直到事件發生? 我認爲,爲了避免阻塞,可以使用timeval tv或fcntl()。還有更好的方法嗎?

在此先感謝

回答

1

在選擇的回報,只要它沒有返回0或-1,你的程序需要對readfds所有元素循環,如果ISSET,它被設置相應的評估套接字必須被處理。因此,假設僅在readfds中設置了sock1和sock2,那麼您的代碼也是正確的。對readfds中的套接字的評估通常由同一個線程按順序完成。然後,可以按順序或並行處理每個套接字中的數據包。 必須清楚的是,兩個插座是完全獨立的,沒有競爭條件的可能性。這一切取決於你如何編程。例如,對於每個ISSET返回true的套接字,您都可以生成一個處理該套接字的線程,或者可以將它傳遞給一組工作線程的工作隊列,以並行處理每個線程。沒有任何限制。你甚至可以同時檢查readfs,例如你可以有一個線程檢查下半部分,另一個線程檢查上半部分。這只是一個例子。同樣,沒有任何限制,只要您在應用程序中生成任何競爭條件,就可以編程。

關於阻塞或非阻塞的概念,select將始終阻塞,直到套件中的套接字有事件要處理(讀取,寫入,異常)或有超時(如果您設置超時值)。

你也可以談論阻塞和非阻塞套接字,這是不同的。阻塞套接字是那些可以在讀或寫操作中被阻塞的套接字套接字。如果發送緩衝區已滿並且無法在緩衝區中寫入字節(這可能發生在STREAM套接字中),阻塞套接字將在讀取操作中阻塞,直到有字節準備好被讀取並且它將在寫入操作中阻塞。它會阻塞,直到它可以寫入它的字節。如果沒有什麼要讀取,非阻塞套接字將不會在讀取操作中阻塞,函數讀取將返回-1,並且errno將設置爲EAGAIN或EWOULDBLOCK(請參閱:http://man7.org/linux/man-pages/man2/read.2.html)。

select通常與非阻塞套接字一起使用,以便一個線程只是在那裏阻塞,直到有一個套接字準備好被處理。這很好,因爲否則您的應用程序將需要始終輪詢非阻塞套接字,這是無效的。

select將並行處理所有套接字,但只是爲了檢查是否有任何事件。 select不處理任何數據包,如果你注意你的例子,選擇返回後你的應用程序將從套接字讀取數據,這可以按順序或並行完成。

我希望這個解釋能幫助你理解這個概念。