从命令行手动关闭端口

129 linux port sockets

我想关闭客户端和服务器应用程序之间处于侦听模式的开放端口。

Linux 中是否有任何手动命令行选项来关闭端口?

注意: 我开始知道“只有拥有连接的套接字的应用程序才能关闭它,这会在应用程序终止时发生。”

我不明白为什么只有打开它的应用程序才有可能......但我仍然很想知道是否还有其他方法可以做到这一点。

Dan*_*vid 159

我遇到了同样的问题,进程必须保持活动状态,但套接字必须关闭。在正在运行的进程中关闭套接字并非不可能但很困难:

  1. 找到进程:

    netstat -np
    
    Run Code Online (Sandbox Code Playgroud)

    你得到一张source/destination ip:port portstate pid/processname地图

  2. 在进程中定位socket的文件描述符

    lsof -np $pid
    
    Run Code Online (Sandbox Code Playgroud)

    您会得到一个列表:进程名称、pid、用户、文件描述符、...一个连接字符串。

    为连接找到匹配的 fileDescriptor 编号。它将类似于“97u”,意思是“97”。

  3. 现在连接进程:

    gdb -p $pid
    
    Run Code Online (Sandbox Code Playgroud)
  4. 现在关闭套接字:

    call close($fileDescriptor) //does not need ; at end.
    
    Run Code Online (Sandbox Code Playgroud)

    例子:

    call close(97)
    
    Run Code Online (Sandbox Code Playgroud)

    然后分离gdb:

    quit
    
    Run Code Online (Sandbox Code Playgroud)

    并且插座是关闭的。

  • 这是一个绝妙的解决方案 (11认同)
  • 如果您想模拟被远程端关闭的套接字(例如对等方退出),最好使用`shutdown`:`call shutdown($fileDescriptor, 0)`。 (10认同)
  • 一行通常看起来像:firefox 14812 szupervigyor 97u IPv4 32814564 0t0 TCP 192.168.2.4:40385->173.194.39.65:https (ESTABLISHED) as: process_name pidode user for fd_data_device_opentoto protocol] (2认同)
  • * 一行通常看起来像:firefox 14812 szupervigyor 97u IPv4 32814564 0t0 TCP 192.168.2.4:40385->173.194.39.65:https (ESTABLISHED) as:process_name pid 用户协议需要知道的进程_name pid 用户协议 fd_data 设备中的进程名地址并在最后一个col上找到。在我的示例中,97 是 FileDescriptor。如果您打开了与目标主机的多个连接,则搜索会很困难。 (2认同)

小智 81

你在这里问错了问题。从打开侦听它的套接字的应用程序外部简单地“关闭端口”是不可能的。唯一的方法是完全终止拥有该端口的进程。然后,大约一两分钟后,该端口将再次可用。这是发生了什么(如果您不在乎,请跳到最后,我将向您展示如何终止拥有特定端口的进程):

端口是操作系统分配给不同进程的资源。这类似于向操作系统询问文件指针。然而,与文件指针不同的是,一次只有一个进程可以拥有一个端口。通过 BSD 套接字接口,进程可以请求侦听端口,然后操作系统将授予该请求。操作系统还将确保没有其他进程获得相同的端口。在任何时候,进程都可以通过关闭套接字来释放端口。然后操作系统将回收该端口。或者,如果进程在没有释放端口的情况下结束,操作系统最终将收回端口(尽管它不会立即发生:它需要几分钟的时间)。

现在,由于两个原因,您想要执行的操作(只需从命令行关闭端口)是不可能的。首先,如果可能的话,这意味着一个进程可以简单地窃取另一个进程的资源(端口)。这将是不好的策略,除非仅限于特权进程。第二个原因是不清楚如果我们让它继续运行,拥有端口的进程会发生什么。该进程的代码是假设它拥有此资源而编写的。如果我们只是把它拿走,它最终会自己崩溃,所以操作系统不会让你这样做,即使你是一个特权进程。相反,您必须简单地杀死它们。

无论如何,以下是杀死拥有特定端口的进程的方法:

sudo netstat -ap | grep :<port_number>
Run Code Online (Sandbox Code Playgroud)

这将输出与进程保持端口对应的行,例如:

tcp  0  0 *:8000   *:* LISTEN  4683/procHoldingPort
Run Code Online (Sandbox Code Playgroud)

在这种情况下,procHoldingPort是打开端口的进程的名称,4683是它的 pid,8000(注意它是 TCP)是它持有的端口号。

然后,查看最后一列,您会看到 /。然后执行这个:

kill  <pid>
Run Code Online (Sandbox Code Playgroud)

如果这不起作用(您可以通过重新运行 netstat 命令来检查)。做这个:

kill -9 <pid>
Run Code Online (Sandbox Code Playgroud)

一般来说,如果可以,最好避免发送 SIGKILL。这就是为什么我告诉你kill之前尝试kill -9。只是使用kill发送更温和的 SIGTERM。

就像我说的,如果你这样做,端口仍然需要几分钟才能重新打开。我不知道有什么办法可以加快速度。如果其他人这样做,我很乐意听到。

  • @codingfreak 内核知道进程已经消失了。它知道它可以收回端口。实际上有关闭端口的时间规则,以确保没有任何杂散数据包漂浮在“网络”上。它怎么知道它有这些资源?这就是内核所做的,跟踪事物。 (3认同)
  • **这个答案不再正确,请否决它。** 在 2010 年,Linux 没有办法从命令行关闭任意端口。但这种能力是多年前添加到内核中的,并且 [`ss` 命令行工具](https://superuser.com/a/1468773/3094) [自 2016 年起就公开了它](https://github .com/shemminger/iproute2/commit/fb2594c183fbedbe8f91fe7b1f7fed1331bb3194),所以现在它应该几乎可以在任何地方使用。 (2认同)

小智 23

也可以使用定影器

fuser -k -n *protocol portno*
Run Code Online (Sandbox Code Playgroud)

这里的协议是 tcp/udp,而 portno 是您要关闭的号码。例如

fuser -k -n tcp 37
Run Code Online (Sandbox Code Playgroud)

熔断器手册页中的更多信息


Tom*_*son 15

您可以使用ss关闭监听套接字:

sudo ss --kill state listening src :1234
Run Code Online (Sandbox Code Playgroud)

其中 1234 是您的端口号。

ss 是 iproute2 软件包的一部分,因此有一个很大的变化,它已经安装在现代 Linux 上。

我是从一个相关问题的回答中了解到这一点的。


sup*_*tah 7

您也可以使用 iptables:

iptables -I INPUT -p tcp --dport 80 -j DROP
Run Code Online (Sandbox Code Playgroud)

它基本上完成了你想要的。这会将所有 TCP 流量丢弃到端口 80。

  • 不,这将使套接字保持打开状态,直到所有超时关闭它们。(它将隐藏拥有进程的所有流量,然后无法知道它应该关闭它。)您可以使用 `-j REJECT` 返回 TCP 重置标志,然后可以看到我的拥有进程(但只有当另一方试图发送某些东西时)。 (5认同)

小智 2

netstat -anp | grep 80
Run Code Online (Sandbox Code Playgroud)

它应该告诉你,如果你正在运行 apache,“httpd”(这只是一个例子,使用你的应用程序正在使用的端口而不是 80)

pkill -9 httpd 
Run Code Online (Sandbox Code Playgroud)

或者

killall -9 httpd
Run Code Online (Sandbox Code Playgroud)

  • 在使用-9之前尝试正常杀戮 (4认同)