Python检测服务器端口状态+ServerChan推送

近期用来科学上网的VPS连续被封端口,多次莫名其妙上不了Google后催生了想法。

Python检测端口连通脚本

如何检测端口状态

  • 在命令行检测一个端口的状态可以使用curl指令,虽然无法直接返回端口的连通状态,但是可以根据返回的代码来确定端口是否被封锁
  • 如果端口未开放,curl会输出代码7,并且提示连接失败;如果端口开放但是不返回curl的请求,curl会输出代码52,并提示主机没有回复;如果端口被封,会返回代码28(设置超时时间后)。所以可以根据返回代码是否为“52”来判断端口状态。

如何在python执行命令

  • python3后取消了commands模块,取而代之的是subprocess。而subprocess执行系统命令的方法也有很多,这里选择subprocess.call()方法。
  • call()支持以字符串或者序列的方式传入指令,如果指令有额外参数,则需要传入一个序列
  • 对于curl指令,需要建立一个四个元素的序列——“curl“、”–connect-timeout“参数、”[超时时间]“和”[IP地址]:[Port]“

代码实现

import subprocess as Sub

PORT = ["Port1", "Port2"] # 多个服务器
LIST = ["IP1", "IP2"]
NAME = ["Name1", "Name2"]
CMD = "curl"
TIMEOUT = "--connect-timeout"
TIME = "5"


def main():
    for i in range(0,len(LIST)):
        args = [CMD, TIMEOUT, TIME, LIST[i]+":"+PORT[i]]
        result = Sub.call(args, stdout = Sub.PIPE, stderr = Sub.PIPE)
        if result != 52:
            do ... something


if __name__ == "__main__":
    main()

ServerChan推送

关于ServerChan,可以去官网了解:Server酱

简单说就是在官网登入Github领取SCKEY后,向链接发送GET请求就可以推送到手机(绑定微信后也可以推送到微信)

我们可以在检测到端口连接出问题后,通过ServerChan推送到手机

  • iOS端有一款叫Bark的App也可以以iOS原生方式推送,推送方式同ServerChan

这里我简单封装了一个类——为了减少代码量:

from urllib import request


class MyChan:
    URL = ""
    SCKEY = ""

    def __init__(self, key=""):
        self.URL = "http://sc.ftqq.com/"
        if key != "":
            self.SCKEY = key
        else:
            self.SCKEY = ""

    def changekey(self, key):
        self.SCKEY = key

    def push_text(self, text="", desp=""):
        text = text.replace(' ', '_')
        desp = desp.replace(' ', '_')
        url = self.URL + self.SCKEY + ".send?text=" + text + "&desp=" + desp
        req = request.Request(url)
        response = request.urlopen(req)
        response = response.read().decode('utf-8')
        if "\"errmsg\":\"success\"" in response:
            return 1
        else:
            return 0

最后应用到端口监控

import subprocess as Sub
from MyClass.SERVERCHAN import *
PORT = ["Port1", "Port2"]
LIST = ["IP1", "IP2"] 
NAME = ["Name1", "Name2"]
CMD = "curl"
TIMEOUT = "--connect-timeout"
TIME = "5"

def main():
    chan = MyChan()
    for i in range(0,len(LIST)):
        args = [CMD, TIMEOUT, TIME, LIST[i]+":"+PORT[i]]
        result = Sub.call(args, stdout = Sub.PIPE, stderr = Sub.PIPE)
        # print(result)
        if result != 52:
            if chan.push_text(NAME[i], "Port_" + PORT[i] + "_Blocked") == 1:
                pass


if __name__ == "__main__":
    main()