为什么套接字在数千次迭代后才准备好读取?
why socket is ready to read only after thousands of iterations?
我正在编写我的 http 服务器。我使用 select 函数,看到套接字随时可以写入,但只能在数千次迭代后才能读取。如果我使用 select(Max+1, &rfd, NULL, NULL, NULL),我就没有这样的问题。为什么迭代了这么多次才准备好读取?
int iteration = -1;
while (true)
{
iteration++;
FD_ZERO(&rfd);
FD_ZERO(&wfd);
FD_SET(listeningSocket, &rfd);
for (std::set<int>::iterator Iter = servingSockets.begin(); Iter != servingSockets.end(); Iter++)
{
FD_SET(*Iter, &rfd);
FD_SET(*Iter, &wfd);
}
int Max = std::max(listeningSocket, *std::max_element(servingSockets.begin(), servingSockets.end()));
res = select(Max + 1, &rfd, &wfd, NULL, NULL);
if (res <= 0)
continue;
if (FD_ISSET(listeningSocket, &rfd))
{
if ((newSocket = accept(listeningSocket, (struct sockaddr *)&listeningSocketAddr, (socklen_t *)&listeningSocketAddr)) < 0)
continue;
fcntl(newSocket, F_SETFL, O_NONBLOCK);
servingSockets.insert(newSocket);
}
for (std::set<int>::iterator Iter = servingSockets.begin(); Iter != servingSockets.end();)
{
if (FD_ISSET(*Iter, &rfd))
{
std::cout<<"iter in loop: "<<iteration<<std::endl;
int bytes_recvd = recv(*Iter, request, request_buffer_size - 1, 0);
if (bytes_recvd < 0)
{
fprintf(stderr, "error recv\n");
shutdown(*Iter, SHUT_RDWR);
close(*Iter);
servingSockets.erase(*Iter);
continue;
}
request[bytes_recvd] = '[=10=]';
parse_http_request(request, &req);
}
if (FD_ISSET(*Iter, &wfd) && req.path[0] != '[=10=]')
{
send(*Iter, "HTTP/1.1 200 OK\n\n<h1><a href=\"\">external</a><br><a href=\"internal\">internal</a></h1>", 122, 0);
shutdown(*Iter, SHUT_RDWR);
close(*Iter);
Iter = servingSockets.erase(Iter);
continue;
}
Iter++;
}
}
一个套接字将总是可写,除非你填满它的缓冲区。
因此 select
将在每次调用时立即 return,并将所有套接字标记为可写。
只有当您确实有东西要写入时,才将套接字添加到 write-set。一旦你写完所有你需要的,然后从集合中删除它们并且不要添加它们(直到下一次你需要写入套接字)。
当您不使用 write-set 时,select
将不会 return,直到 read-set 中有活动的套接字。
我正在编写我的 http 服务器。我使用 select 函数,看到套接字随时可以写入,但只能在数千次迭代后才能读取。如果我使用 select(Max+1, &rfd, NULL, NULL, NULL),我就没有这样的问题。为什么迭代了这么多次才准备好读取?
int iteration = -1;
while (true)
{
iteration++;
FD_ZERO(&rfd);
FD_ZERO(&wfd);
FD_SET(listeningSocket, &rfd);
for (std::set<int>::iterator Iter = servingSockets.begin(); Iter != servingSockets.end(); Iter++)
{
FD_SET(*Iter, &rfd);
FD_SET(*Iter, &wfd);
}
int Max = std::max(listeningSocket, *std::max_element(servingSockets.begin(), servingSockets.end()));
res = select(Max + 1, &rfd, &wfd, NULL, NULL);
if (res <= 0)
continue;
if (FD_ISSET(listeningSocket, &rfd))
{
if ((newSocket = accept(listeningSocket, (struct sockaddr *)&listeningSocketAddr, (socklen_t *)&listeningSocketAddr)) < 0)
continue;
fcntl(newSocket, F_SETFL, O_NONBLOCK);
servingSockets.insert(newSocket);
}
for (std::set<int>::iterator Iter = servingSockets.begin(); Iter != servingSockets.end();)
{
if (FD_ISSET(*Iter, &rfd))
{
std::cout<<"iter in loop: "<<iteration<<std::endl;
int bytes_recvd = recv(*Iter, request, request_buffer_size - 1, 0);
if (bytes_recvd < 0)
{
fprintf(stderr, "error recv\n");
shutdown(*Iter, SHUT_RDWR);
close(*Iter);
servingSockets.erase(*Iter);
continue;
}
request[bytes_recvd] = '[=10=]';
parse_http_request(request, &req);
}
if (FD_ISSET(*Iter, &wfd) && req.path[0] != '[=10=]')
{
send(*Iter, "HTTP/1.1 200 OK\n\n<h1><a href=\"\">external</a><br><a href=\"internal\">internal</a></h1>", 122, 0);
shutdown(*Iter, SHUT_RDWR);
close(*Iter);
Iter = servingSockets.erase(Iter);
continue;
}
Iter++;
}
}
一个套接字将总是可写,除非你填满它的缓冲区。
因此 select
将在每次调用时立即 return,并将所有套接字标记为可写。
只有当您确实有东西要写入时,才将套接字添加到 write-set。一旦你写完所有你需要的,然后从集合中删除它们并且不要添加它们(直到下一次你需要写入套接字)。
当您不使用 write-set 时,select
将不会 return,直到 read-set 中有活动的套接字。