我已经忙了两天了,还是没明白。 这段代码中
select()
做了什么?
我知道,如果有一个可以接受的传入连接,
copy.fd_array[]
将包含ListenSocket
,但是当 while 循环重复时它仍然存在。那么我们如何知道客户端是否断开连接呢? fd_set copy
调用后 select()
包含什么?
fd_set master;
FD_ZERO(&master);
FD_SET(ListenSocket, &master);
while (1)
{
fd_set copy = master;
select(FD_SETSIZE, ©, NULL, NULL, NULL);
for (int i = 0; i < FD_SETSIZE; i++)
{
// If new connection
if (FD_ISSET(ListenSocket, ©))
{
printf("[+] New connection\n");
// Accept connection
SOCKET AcceptedClient = accept(ListenSocket, NULL, NULL);
FD_SET(AcceptedClient, &master);
// Send welcome message to client
char buff[128] = "Hello Client!";
send(AcceptedClient, buff, sizeof(buff), 0);
}
}
}
我忙了两天了,还是没明白。
难怪你看不懂代码:示例中的代码是废话。
检查
ListenSocket
应在 for
循环之外完成。并且还必须检查 FD_ISSET
是否使用 accept
接受的连接。
while
循环内的正确代码如下所示:
fd_set copy = master;
select(FD_SETSIZE, ©, NULL, NULL, NULL);
// If new connection
if (FD_ISSET(ListenSocket, ©))
{
...
}
for (int i = 0; i < FD_SETSIZE; i++)
{
// If an existing connection has data
// or the connection has been closed
if ((i != ListenSocket) && FD_ISSET(i, ©))
{
nBytes = recv(i, buffer, maxBytes, 0);
// Connection dropped
if(nBytes < 1)
{
close(i); // other OSs (Linux, MacOS ...)
// closesocket(i); // Windows
FD_CLR(i, &master);
}
// Data received
else
{
...
}
}
}
我知道,如果有可以接受的传入连接,
将包含copy.fd_array[]
,但当ListenSocket
循环重复时,它仍然存在。while
select() 调用后 fd_set 副本包含什么?
首先:在调用
select()
之前,copy.fd_array[]
必须包含您感兴趣的所有套接字句柄。这意味着它必须包含ListenSocket
和accept()
返回的所有句柄。
master.fd_array[]
包含所有这些句柄,因此 fd_set copy = master;
将确保 copy.fd_array[]
也包含所有这些句柄。
select()
(以 NULL
作为最后一个参数)将等待,直到至少一个套接字变得“可用”。这意味着它将等待至少满足以下条件之一:
accept()
接受的连接被另一方关闭accept()
接受的连接具有可以接收的数据accept(ListenSocket...)
一旦满足一个条件,
select()
就会从copy.fd_array[]
中删除所有其他句柄:
ListenSocket
将从 copy.fd_array[]
中删除accept()
返回的句柄如果两个事件同时发生,
copy.fd_array[]
将包含多个句柄。
您可以使用
FD_ISSET()
检查某个句柄是否仍在数组中。
那么我们如何知道客户端是否断开连接呢?
当您检测到
FD_ISSET(i, ©)
中存在由 i
返回的值 accept()
时,您必须调用 recv()
(在 Linux 下 read()
也可以工作):
如果
recv()
返回 0(如果出现错误则返回负值),则另一台计算机已断开连接。您必须调用 close()
(在 Windows 上为 closesocket()
)并从 copy.fd_array[]
中删除句柄(这意味着:由于 master.fd_array[]
行,您必须从 fd_set copy = master;
中删除它)。
如果
recv()
返回正值,则这是已接收的字节数。