0

我写了一个转发代理。我将它用于windows和linux。我确实需要根据操作系统进行更改。但是,我不断看到一些加薪条件。大多数情况下,我相信它们是由于我在猜测哪个是最后一个数据包(FIN sigal)时的误解。目前我确实选择了一组套接字。无论哪个套接字发出信号,我都会对其进行 read() 。如果 read 返回 0,那么我认为它是一个 FIN 数据包,然后我关闭该套接字。是否会发生我的 read() 给出非零值。但是该数据包确实包含 FIN(我认为它可能会发生)。因此,尽管某些套接字已关闭,但我不会关闭它们。我不确定代理如何检测哪个套接字已关闭?或者是已建立连接上的最后一个数据包。

我的代码如下所示:

我从客户那里接受了 100 个 fds。我将它们存储为一个数组sock_array[total_size]

select(copy_of_sock_array,timeout)                                                          
for(int cnt=0;cnt<total_size;cnt++)                                                          
{                                                                                            
   if(FD_ISSET(sock_array[cnt],sock_array))                                                  
   {
            ret = recv(sock_array[cnt],buffer,len);                                          
            if(ret<=0){                                                                      
                /*This must be a FIN packet */                                               
                /* Close corresponding socket which is opened with outer world */            
                close(/*corresponding socket*/);                                                                      
            }                                                                                  
   }                                                                                          
}                                                                                                

这看起来好吗?

谢谢

4

2 回答 2

1

您需要进行非阻塞读取,并继续从套接字读取,直到获得指示您应该停止读取的返回值。

ssize_t r = 0;
for (;;) {
    r = recv(sock, buf, bufsz, MSG_DONTWAIT);
    if (r <= 0) {
        if (r < 0 && errno == EINTR) {
            continue;
        }
        break;
    }
    /* ... handle data in buf .. */
}
if (r < 0) {
    if (errno == EAGAIN) {
        /* ... wait in select again ... */
    } else {
        /* ... handle error ... */
    }
} else {
    /* got FIN */
}

请注意,仅仅因为收到 FIN 并不一定意味着应该关闭连接。FIN 仅表示不再发送数据,但对等方可能仍愿意接受更多数据。这可能发生在客户端只需要一个响应的 HTTP 中,因此它会在请求后传递一个 FIN。它仍然希望收到响应。

您的代理可能有两个套接字,例如 sock1 和 sock2。因此,在 sock1 上收到 FIN 应该意味着该指示在已在其上排队的任何数据已被传递之后被转发到 sock2(并且镜像也是如此)。您可以使用 转发 FIN shutdown

shutdown(sock2, SHUT_WR);

当从 sock1 和 sock2 收到 FIN 时,您可以调用close两个套接字。

所以解决你的问题。

是否会发生我的 read() 给出非零值。但是该数据包确实包含 FIN(我认为它可能会发生)。

是的,这可能会发生。这就是为什么你继续阅读直到你得到停止的指示。好吧,从技术上讲,您不必这样做。如果您遇到每个连接的公平性问题,您可以将其推迟到处理完其他连接。但是,在进入选择等待之前,您需要返回并完成阅读。

因此,尽管某些套接字已关闭,但我不会关闭它们。我不确定代理如何检测哪个套接字已关闭?或者是已建立连接上的最后一个数据包。

正如我所描述的,作为一个(透明的)代理,一旦你在其上转发了一个 FIN 并且收到了一个 FIN,就可以安全地关闭套接字。如果您不是透明代理,那么您将遵循一组不同的规则,因为在这种情况下您确实是客户端的服务器。因此,只要您正在实施的应用程序协议允许您这样做,您就可以关闭套接字。

于 2012-08-10T21:45:42.237 回答
0

套接字具有明确定义的行为。如果您收到数据并在此之后关闭连接,您将需要两个 read()。第一个将返回数据,第二个将返回 0,表示连接结束。

在系统调用返回 0 之前,您必须一直阅读。

而且您不需要非阻塞读取来检测这一点!

于 2012-08-10T22:30:53.567 回答