2017-04-24 83 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不处理任何数据包,如果你注意你的例子,选择返回后你的应用程序将从套接字读取数据,这可以按顺序或并行完成。

我希望这个解释能帮助你理解这个概念。