转发代理检测FIN包

时间:2012-08-10 21:32:00

标签: c linux proxy network-programming

我写了一个转发代理。我将它用于Windows和Linux。我确实需要根据操作系统进行更改。但是,我一直看到一些加薪条件。大多数情况下,我认为他们是因为我在猜测哪个是最后一个数据包(FIN sigal)时的误解。目前我选择套接字。无论哪个套接字发出信号,我都会读取()。如果读取返回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*/);                                                                      
            }                                                                                  
   }                                                                                          
}                                                                                                

这看起来不错吗?

由于

2 个答案:

答案 0 :(得分: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上。您可以使用shutdown转发FIN。

shutdown(sock2, SHUT_WR);

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

所以解决你的问题。

  

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

是的,这可能会发生。这就是为什么你继续阅读,直到你得到停止的迹象。嗯,从技术上讲,你没有必要。如果您有每个连接的公平性问题,您可以推迟,直到您处理了一些其他连接。但是,在进入选择等待之前,您需要回到它并完成阅读。

  

所以,虽然他们已经关闭但我没有关闭一些套接字。我不确定代理如何检测哪个套接字已关闭?或者是已建立连接上的最后一个数据包。

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

答案 1 :(得分:0)

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

在syscall返回0之前,您必须始终阅读。

你不需要非阻塞读取来检测这个!