如何在C中拒绝一个socket连接?

22

如果我想接受一个连接,我会调用accept,但是如何拒绝一个连接呢?

在一个工作的socket回声客户端中,我有这个if语句。在回声服务器中,我该如何使回声客户端达到这个printf语句?

...
if (connect(sock, (struct sockaddr *) &server, sizeof(server)) < 0) { 
    printf("Connecting failed\n"); 
    return 1; 
}
...

1
接受并立即关闭 - Bart Friederichs
2
基于什么原因你会拒绝?我认为你想要的是防火墙的工作。我所知道的大多数应用程序都可以使用黑名单或类似功能来接受和关闭。 - Bart Friederichs
实际上,我只想在这个特定的端口上建立一个连接。任何其他连接都应该以非常明显的方式失败。 - c00kiemonster
1
将backlog参数设置为listen(2)。 - fizzer
不接受任何连接并关闭套接字。客户端将在连接时触发超时错误。 - Ben
显示剩余5条评论
5个回答

13
为了获得所需的行为(只接受一个连接,其他尝试连接的客户端应该失败),有两个选择。
  • 你可以在接受连接后关闭监听套接字。在已接受的连接关闭后重新创建您的监听套接字。
  • 如果已经有一个连接正在进行中,则可以关闭新建立的连接。如果要让客户端看到TCP重置,则大多数TCP堆栈将在启用具有超时为0的延迟选项时触发一个TCP重置。

    struct linger lo = { 1, 0 };
    setsockopt(s, SOL_SOCKET, SO_LINGER, &lo, sizeof(lo));
    close(s);


第一个选项在实践中真的被使用吗?保持监听套接字打开可能更好,以确保资源在程序运行期间一直被程序“拥有”并使用。 - Craig McQueen
@CraigMcQueen:如果使用此选项,我假设服务器端口已经被配置。 - jxh

8
据我所知,TCP并不是这样工作的。 accept(..)调用将始终返回客户端详细信息。没有办法窥视连接并有选择性地拒绝。你现在所做的方式实际上是正确的:接受然后关闭。如果您在此层之上有其他消息结构,则可以创建自定义“拒绝消息”。这个选项完全取决于您的用例。
如果您想根据IP地址拒绝请求,则不在您的应用程序域内。这是您的防火墙(如@Bart Friederichs所说)的工作。这样,请求甚至不会触及TCP堆栈。
实际上,我希望只有一个连接可以在这个特定的端口上进行。任何其他连接都应该以非常明显的方式失败。 不要让accept调用处于您的控制流中。只有当您等待accept时,您的程序才会等待套接字连接,否则永远不会。

6
在大多数平台的标准套接字API中,没有拒绝连接的方式。如果不想要该连接,您必须先accept()该连接,然后立即关闭它。
例外情况是Winsock特定的WSAAccept()函数。它提供了一个回调函数,允许应用程序基于每个连接来决定是否接受、拒绝或将其保留在等待队列中。

2

在成功接受客户端连接后,关闭监听服务器套接字并在客户端连接由于任何原因而断开后重新建立它可能会很有帮助。

  1. 在成功使用accept()函数接受客户端连接后,关闭监听服务器套接字。
  2. 在客户端连接由于任何原因而中断后,重新建立监听服务器套接字。

1
有点晚了,但您可以使用WSAAccept()代替accept()。WSAAccept()具有可选的回调函数,允许您窥视谁在敲门并决定是否要回答。您的回调函数可以返回常量CF_ACCEPT、CF_REJECT和CF_DEFER。前两个显而易见。第3个允许您推迟回答,以防需要稍后决定。一旦您确定了,您再次调用WSAAccept()并接受或拒绝。

不幸的是,您必须接受或拒绝才能从侦听队列的前面删除条目。我说这很不幸的原因是,在被拒绝和没有得到响应(超时)之间,连接机器之间存在明显的差异。

如果黑客正在使用端口扫描器,他们将知道您正在监听该端口,如果您拒绝,他们就可以开始入侵。能够在不做任何操作的情况下从队列的前面删除条目,并使另一端的人不知道您在该端口上进行侦听,这将是很好的。


很奇怪居然没有这方面的函数。我正在创建一个Web服务器,考虑让每个被禁止的IP超时(不打开TCP连接并使我的操作系统释放为该传入连接分配的任何信息)。但是似乎没有可能做到这一点,除非编写自己的操作系统或网络驱动程序?我认为如果我从未打开连接,那么路由器也不会接受来自它的更多数据包。因此,在DoS的情况下,我可以节省一些带宽。 - Joakim L. Christiansen
对我上面写的内容的跟进。由于我正在使用Linux,我发现服务firewalld可以做我想要的事情。我可以告诉它“禁止”某些IP地址,对于它们来说,看起来像我没有运行服务器。而且我可以从自己的服务器与这个服务进行交互 :) - Joakim L. Christiansen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接