从命令行手动关闭端口


112

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

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

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

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


5
不,打开的端口属于打开它们的过程,无法从外部进行控制。这是一件好事,否则所有应用程序都必须预料到其打开的端口(和文件)会混乱。但是,您可以通过防火墙(iptables)阻止到端口的通信,但这不会关闭并放弃该端口供其他使用。
尔根·斯特罗贝尔

10
许多回答者都没有回答这个问题。声明只有拥有该端口的应用程序可以断开它是毫无意义的。我可以走到盒子上并将以太网电缆从插座中拔出,或者通过杀死连接另一端的应用程序来断开连接!必须编写应用程序来处理此问题。那么---您如何测试以确保应用程序正确编写,而无需物理干预和/或控制另一台计算机?
戴尔·威尔逊

“ ...无法从外部进行控制。” 这是重要的一句话,将我引向下一个问题,我如何才能从外部参与过程?GDB。
丹科大卫

@JürgenStrobel确实可以从外部进行控制-tcpkill和ss都可以完全满足要求。因为打开的端口并不真正属于进程;它们是内核资源,为进程分配了一些权限,但仍然仅在内核乐意下存在。
汤姆·安德森

@ tom-anderson DaleW:tcpkill是防火墙工具,我确实提到了此选项。您可以阻止到端口的通信,这与关闭端口(套接字)不同。
尔根·斯特罗贝尔

Answers:


134

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

  1. 定位过程:

    netstat -np
    

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

  2. 在进程中找到套接字的文件描述符

    lsof -np $pid
    

    您将得到一个列表:进程名称,PID,用户,fileDescriptor,...一个连接字符串。

    找到用于连接的匹配的fileDescriptor编号。就像“ 97u”,意思是“ 97”。

  3. 现在连接过程:

    gdb -p $pid
    
  4. 现在关闭插座:

    call close($fileDescriptor) //does not need ; at end.
    

    例:

    call close(97)
    

    然后分离gdb:

    quit
    

    并且插座已关闭。


1
sudo lsof -np $pid给我大约200行,而我对于如何找到所需的FD感到困惑。在我的情况下过程是一个Chrome标签,我试图关闭打开的WebSockets ...
SET

2
一行通常看起来像:火狐14812 szupervigyor 97U的IPv4 32814564 0t0 TCP 192.168.2.4:40385->173.194.39.65:https(建立)为:PROCESS_NAME PID用户FD [opened_for]协议设备的inode protocol_data_toString
丹科大卫

2
*典型的行如下所示:firefox 14812 szupervigyor 97u IPv4 32814564 0t0 TCP 192.168.2.4:40385->173.194.39.65:https(ESTABLISHED)as:process_name pid user fd [opened_for]协议设备inode protocol_data_toString您需要知道远程ip地址并在最后一个栏上找到。在我的示例中,97是FileDescriptor。如果打开了到目标主机的多个连接,搜索将很困难。
丹科·大卫·

7
这是一个绝妙的解决方案
marcorossi 2015年

8
如果要模拟套接字被远端关闭(例如,对等端退出),则最好使用shutdowncall shutdown($fileDescriptor, 0)
ecatmur '16

75

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

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

现在,您要执行的操作(仅从命令行关闭端口)由于两个原因而无法实现。首先,如果可能的话,这意味着一个进程可以简单地窃取另一个进程的资源(端口)。除非限于特权进程,否则这将是错误的策略。第二个原因是,如果让端口继续运行,尚不清楚拥有该端口的进程将发生什么情况。假定过程拥有该资源,则编写该过程的代码。如果我们只是简单地删除它,它最终将自己崩溃,因此即使您是特权进程,OS也不允许您这样做。相反,您必须简单地杀死它们。

无论如何,这是如何杀死拥有特定端口的进程:

sudo netstat -ap | grep :<port_number>

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

tcp  0  0 *:8000   *:* LISTEN  4683/procHoldingPort

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

然后,在最后一列中,您将看到/。然后执行:

kill  <pid>

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

kill -9 <pid>

通常,最好避免发送SIGKILL。这就是为什么我告诉你去尝试kill之前kill -9。只需使用即可kill发送更柔和的SIGTERM。

就像我说的那样,如果要重新打开端口,仍然需要几分钟。我不知道有什么方法可以加快速度。如果有人这样做,我很想听听。


@smehmood-感谢您的详细解释..一个小小的疑问..内核如何通过突然终止的进程回收开放的端口?..您提供的解决方案似乎正在杀死持有该端口的进程...

3
@codingfreak内核知道进程已经消失。它知道它可以收回端口。实际上,有关于关闭端口的时间的规则,以确保在网络上没有任何杂散数据包。它怎么知道它拥有这些资源?内核就是这样做的,可以跟踪情况。
Rich Homolka

直到有人发表unix.tools.port.close(<my port number>)我会用的明智的话init 6
Snowcrash

对于不同的问题,这是一个很好的答案。这个问题是关于附加调试器和更改正在运行的程序,以使该程序调用文件描述符上的函数。
亚瑟·乌尔费尔特

19

也可以使用定影器

fuser -k -n *protocol portno*

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

fuser -k -n tcp 37

定影器手册页上的更多信息


只是取消拥有过程对我来说不起作用,但热熔器确实有效。谢谢!
webwurst,2013年

我得到的结果参差不齐,即使使用了定影器之后,当尝试从已终止的应用程序重用端口(甚至以root身份使用)时,也得到了“ socket已经在使用中”。另一方面,释放插槽的时间似乎比以前要短,所以还是要谢谢。
Jan Vlcinsky

@JanVlcinsky也许有一个“守护程序”进程可以在fuser运行后重新启动终止进程?
RedBaron'4

@RedBaron:根据评论superuser.com/a/415236/153413,我的问题出在编写不良的应用程序中,该应用程序无法清理/关闭处于终止状态的套接字。因此fuser,使用端口查找进程并将其杀死,但是无法解决套接字未关闭的事实。60秒,内核为我完成。
Jan Vlcinsky 2014年

6

您也可以使用iptables:

iptables -I INPUT -p tcp --dport 80 -j DROP

它基本上完成了您想要的。这会将所有TCP通信丢弃到端口80。


4
不,这将保持套接字打开,直到所有超时关闭它们为止。(它将隐藏所有者进程中的所有流量,然后没有办法知道应将其关闭。)您可以使用-j REJECT返回TCP重置标志,然后将其视为所有者进程(但仅当另一方尝试时)发送东西)。
Marki555

3
netstat -anp | grep 80

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

pkill -9 httpd 

要么

killall -9 httpd

4
在诉诸于-9
Thilo

@omfgroflmao-但是它将杀死打开端口的进程?

@codingfreak持有端口的进程,是的,它将杀死它。

2

您可能只需要找出哪个进程打开了与端口关联的套接字,然后杀死该进程即可。

但是,您将必须意识到,除非该进程的处理程序取消初始化它正在使用的所有内容(打开的文件,套接字,派生类,除非在终止时正确关闭,否则这些内容会持续存在),那么您将已经创建了该处理程序。拖累系统性能。另外,套接字将保持打开状态,直到内核意识到该进程已被终止为止。通常只需要一分钟。

我想更好的问题是:您要停止哪个端口(属于哪个进程)?

如果您想终止发现的后门或病毒,那么在终止数据之前,至少应了解来回的数据。(wireshark对此很有用)(还有进程的可执行文件名称,因此您可以删除它并防止其在重新启动时再次出现),或者,如果已安装了某些文件(例如HTTPD或FTPD等),则您应该已经可以访问过程本身。

通常它将具有一个控制程序(HTTPD停止|启动之类的东西)。或者,如果这是系统性的事情,那么您可能不应该将其弄乱。无论如何,我认为既然其他所有人都在给您“如何做”的角度,我应该给您一些警告。


很好的评论。我有一个程序,该程序在终止时不会关闭套接字,这将导致所描述的行为-套接字无法使用约60秒。当我停止并开始该过程时,它抱怨约一分钟,表明该地址和端口已被使用。最好的解决方案是纠正行为异常的进程以使其正常关闭,但是有时候这不是一个选择。有没有办法要求内核在60秒内检查被阻塞的套接字?
Jan Vlcinsky 2014年

2

我首先寻找mongo和node进程,然后执行以下操作:

ps -A | grep node

10418 pts/23   00:00:05 node

10551 pts/23   00:00:00 node

ps -A | grep mongo

10490 pts/23   00:00:00 mongod

确定后,只需使用kill命令杀死进程。

kill -9 10418
kill -9 10490

最后,键入meteor,它应该可以再次工作。


1

您可以编写一个脚本来修改iptables并重新启动它们。一个脚本用于添加丢弃该端口上所有数据包的规则,另一个脚本用于删除该规则。

其他答案还向您展示了如何终止与端口绑定的进程-这可能不是您想要的。如果希望服务器继续运行,但要阻止客户端连接,则要阻止端口,而不是停止进程。


@Michael Shimmins ... hmm听起来很吸引人,因为我们可以在服务器端阻止端口,以便客户端不会发送任何消息。

那么客户端可以将消息发送所有他们想要我们刚刚关闭了大门,使他们无法得到的。

1

还有一个问题:内核有时自己拥有端口。我知道NAT路由会将一些端口开放给NAT使用。您不能为此终止进程,它是一个内核,需要重新配置并重新引导。


1

如果您希望更快地释放端口,则必须设置以下值:

echo 1 > /proc/sys/net/ipv4/tcp_fin_timeout

将其从60秒(默认)设置为1秒


1

您可以使用名为killcx的命令来关闭连接,而无需杀死任何进程。

  • 句法:
killcx [dest_ip:dest_port] {interface}

  dest_ip              : remote IP
  dest_port            : remote port
  interface (optional) : network interface (eth0, lo etc).
  • 例:
killcx 120.121.122.123:1234
killcx 120.121.122.123:1234 eth0

//,大多数Linux机器都具有killcx吗?我尝试过的所有程序都没有安装此killcx命令,而没有安装它们当前存储库配置不可用的软件包。
弥敦道(Nathan Basanese)'16

否,您可以在这里找到该工具:killcx.sourceforge.net
shuaiming

//,我知道我可以找到该工具,在数千台服务器上安装它只是一个痛苦。
弥敦道(Nathan Basanese)'16

使用P @NathanBasanese :)
SHOUBHIK BOSE

1

我知道,严格来说,这个答案并不能回答问题本身,但是读到它可能是相关的信息:

将套接字绑定到端口(和地址)的默认行为是,当由于突然终止进程而关闭套接字时,套接字将在TIME_WAIT中停留一段时间。这意味着您无法立即重新绑定到该地址/端口。如果要通过标准BSD套接字接口开发系统本身,则可以(至少在某种程度上)使用SO_REUSEADDR套接字选项控制此行为。如果套接字处于TIME_WAIT状态,则基本上可以使您再次绑定到相同的地址/端口。每个端口仍然有一个插座!

但是,此信息仅应用作开发辅助,因为TIME_WAIT首先存在是有原因的,在其他答案中已经对此进行了解释。


// , 对。当然,终止进程不是释放端口的最佳方法。我已经注意到,如果我终止了Vagrant进程挂起的进程,那么一段时间后我将无法再进行升级。我敢打赌这与TIME_WAIT有关。
弥敦道(Nathan Basanese)'16

0

如果您不希望通过套接字的通信,但希望保持活动状态,请执行以下操作:tcpkill

tcpkill -i eth0 host xxx.xxx.xxx.xxx and port yyyy

将启动一个嗅探守护程序,该守护程序拦截并丢弃该端口上的所有流量。对于测试您的应用程序的网络拆分非常方便。


0

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

sudo ss --kill state listening src :1234

其中1234是您的端口号。

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

我从一个相关问题的答案中学到了这一点。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.