在调用listen(fd,backlog)之后,是否可以在套接字上放开?
编辑:我没有明确表示自己的错误。 我希望能够暂时在套接字上打听。 调用close()会使套接字处于M2LS状态,并阻止我重新打开它(或者更糟糕的是,某些恶意程序可能会绑定到该套接字)
暂时不会是一种方式(可能不是最好的方式)向上游负载平衡器发出信号,表明这个应用程序不能接受任何更多的请求
有些套接字库允许您专门拒绝传入的连接。 例如: GNU的CommonC ++:TCPsocket类有一个拒绝方法。
BSD套接字没有这个功能。 您可以接受连接,然后立即关闭连接,同时打开套接字:
while (running) { int i32ConnectFD = accept(i32SocketFD, NULL, NULL); while (noConnectionsPlease) { shutdown(i32ConnectFD, 2); close(i32ConnectFD); break; } }
关闭套接字后,你的程序可能仍然会告诉你套接字“正在使用”,这是因为我不太确定的一些奇怪之处。 但是关于套接字的manpage会告诉你有一个标志可以重复使用同一个套接字,懒洋洋地称之为“SO_REUSEADDR”。 使用“setsockopt()”进行设置。
关闭它。 据我回忆;
close(fd);
根据您编辑的问题版本,我不确定您必须“unlisten”或关闭()。 想到两个选择:
1)调用listen()之后,连接实际上不会被接受,直到(在逻辑上)调用accept()。 你可以通过简单地忽略套接字活动来“解除”,并推迟accept(),直到你为它们做好准备。 任何入站连接尝试积压到在侦听模式下打开端口时创建的队列中。 一旦积压队列在栈中已满,进一步的连接尝试就会被放在地板上。 当您使用accept()继续时,您将快速将待办事项列出并准备好进行更多连接。
2)如果您确实希望端口暂时处于完全关闭状态,则可以动态地将内核级数据包筛选器应用到端口,以防止入站连接尝试到达网络堆栈。 例如,您可以在大多数* nix平台上使用伯克利包过滤器(BPF)。 那就是你要使用平台的防火墙功能来丢弃入站到感兴趣的端口的数据包。 当然,这是因平台而异,但是可能的方法。
我不认为这是一个信号上游负载平衡器的好方法。 在消息传递之前,实际上必须发送一些连接到你的服务器 – 这些连接可能会被拒绝。
同样,当您关闭侦听套接字时,挂起的任何连接都将关闭,并且没有数据。
如果你想发信号给上游的负载均衡器,你应该有一个协议来做到这一点。 不要试图滥用TCP来做到这一点。
幸运的是,如果客户端是正常的网页浏览器,你可以逃脱很多 – 只要关闭套接字通常会导致他们重试对用户透明(到某一点)。
没有明确的方法来解除!
您可以close(fd)
或shutdown(fd, how)
fd is the socket file descriptor you want to shutdown, and how is one of the following: 0 Further receives are disallowed 1 Further sends are disallowed 2 Further sends and receives are disallowed (like close())
在基本级别上,套接字是打开或关闭的(我们将忽略这里的TCP / IP状态图的细节)。
如果您的套接字已关闭,则无法将数据发送到该套接字。 如果它是开放的,那么传入的数据将被TCP / IP堆栈接受和确认,直到缓冲算法哭声“足够”。 那时候,进一步的数据将不会被确认。
你有两个选择,我可以看到。 当你想“unlisten”时关闭()套接字,并在以后重新打开 – 使用setsockopt()和SO_REUSEADDR标志来允许你在TIME_WAIT2过期之前重新连接到知名的端口。
另一种选择是保持插座的打开状态,但是在“忙碌”时根本不接受()。 假设你有一个应用程序级别的确认请求,你负载平衡器会意识到它没有得到一个响应,并采取相应的行动。
根据你编辑的问题,这是一个相当难看的方法:
打开一个套接字来听取正常积压。 继续。
当你想“关闭”,打开第二个积压1和SO_REUSEADDR。 关闭第一个。 当准备好恢复时,另一个套接字与正常的积压工作交替。
从你关闭的套接字中排除接受队列的挑剔细节将成为这里的杀手锏。 可能足以使这种方法成为不可靠的杀手。
我不认为这是一个好主意,但…
您可能可以再次拨打电话。 POSIX规范并没有说不。 也许你可以再次调用它,当你想“unlisten”时,backlog参数为0。
当积压为0的调用listen时会发生什么似乎是实现定义的。 POSIX规范说,它可能允许连接被接受,这意味着一些实现可能会选择拒绝所有的连接,如果backlog参数是0.更有可能的是,你的实现将选择一些正值,当你传入0(可能是1或SOMAXCONN)。
这个问题没有说什么样的socket。 如果它是一个unix套接字,则可以停止并使用重命名(2)开始监听。 您也可以使用取消链接永久停止收听(2),并且由于套接字保持打开状态,您可以继续处理待办事项。 这种方法似乎非常方便,虽然我以前没有见过,只是自己探索。
你已经得到了一些关于通过套接字API不可能做到的答案。
您可以使用其他操作系统方法(即主机firwewall / iptables / ipfilter)设置一个临时拒绝规则。
我发现,大多数负载平衡器在识别连接问题方面的能力有限(其中大多数负载平衡器仅在连接探测器中识别RST,而不是作为正确连接尝试的答案)。
无论如何,如果您受到探测无效的探测器的限制,您可以设置一个应用程序级别的探测器来执行HTTP请求或FTP登录,或者在接受之后简单地关闭,就可以识别类似的事情。 它甚至可以解释像“500服务不可用”这样的错误消息,无论如何,这对我来说似乎更清洁。 有了SNMP,一些负载平衡器也可以使用结果作为负载提示。