有一些我无法理解的选择(),我希望你的导游。当我读到这个功能时,我发现了
select()函数为您提供了一种同时检查的方法 多个套接字,看看他们是否有数据等待recv()d,或者是否 你可以发送()数据给他们没有阻止,或者如果有一些例外 发生。
1)我理解的第一件事是这个函数可以并行检查套接字。现在假设sock1和sock2完全同时接收数据包(来自sock1的packet1和来自sock2的packet2)并且每个数据包都需要完成一些进程。是并行处理数据包?或者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()。还有更好的方法吗?
提前致谢
答案 0 :(得分:1)
返回select后,如果它没有返回0或-1,你的程序需要循环 readfds 的所有元素并评估是否ISSET,它是否设置了相应的socket必须处理。所以,假设只有sock1和sock2在 readfds 中设置,你的代码也是正确的。 readfds 中套接字的评估通常由同一个线程顺序完成。然后,可以顺序地或并行地处理每个套接字中的分组。 必须清楚的是,两个插座完全相互独立,不存在竞争条件。所有这些都取决于你如何编程。例如,对于ISSET返回true的每个套接字,您可以生成一个处理它的线程,或者您可以将它传递给工作队列,以便一组工作线程并行处理每个工作线程。没有任何限制。你甚至可以并行检查readfs,例如你可以让一个线程检查集合的下半部分,另一个线程检查上半部分。这只是一个例子。同样,没有限制,只要您在应用程序中不产生任何竞争条件就可以很好地编程。
关于阻塞或非阻塞的概念,select将始终阻塞,直到集合中的套接字具有要处理的事件(读取,写入,异常)或存在超时(如果设置超时值)。
你也可以谈论阻塞和非阻塞套接字,这是不同的。阻塞套接字是可以在读取或写入操作中阻止的套接字。阻塞套接字将在读取操作中阻塞,直到准备好读取字节为止,如果发送缓冲区已满并且无法在缓冲区中写入字节,则它将在写入操作中阻塞(这可能发生在STREAM套接字中)。它将阻塞,直到它可以写入其字节。如果没有要读取的内容,非阻塞套接字将不会在读取操作中阻塞,函数read将返回-1并且 errno 将设置为EAGAIN或EWOULDBLOCK(请参阅:http://man7.org/linux/man-pages/man2/read.2.html)
select 通常与非阻塞套接字一起使用,这样线程就会阻塞,直到有一个套接字可以处理。这很好,因为否则您的应用程序需要始终轮询非阻塞套接字,这是无效的。
选择会并行处理所有套接字,但只是检查是否有任何事件。 选择不会处理任何数据包,如果你注意你的例子,在选择返回后你的应用程序将从套接字读取数据,这可以顺序或并行完成。
我希望这个解释可以帮助你理解这个概念。