1. 程式人生 > 實用技巧 >如何通過python實現--監控伺服器是否有人遠端登入(詳細思路+程式碼)

如何通過python實現--監控伺服器是否有人遠端登入(詳細思路+程式碼)

@

目錄

文章首發:https://mp.weixin.qq.com/s/Lliuq-2rB6SIrcfkebv7Jg

起源

當同一個遠端伺服器有多個人使用的時候,想知道伺服器是否有人在用,我們不能直接的去登入,因為這樣可能會把對方擠下來,這並不友好,所以這裡提供一個監控遠端伺服器是否有人連線的方式

思路

遇到這個問題,想著如何去解決

剛開始的時候,我是想通過一個主動的方式,去監控到伺服器是否有人連線,就是說當我想要知道伺服器是否有人連線,我通過一個執行一個指令碼程式,然後返回給我一個結果,事實證明,我並沒有通過這樣的思路解決這個問題

後來想以一個被動的方式來監控,比如在伺服器上裝載一個指令碼,每5分鐘執行一次指令碼,來確定伺服器上是否有人連線,不過這也比較消耗資源,後來想到一個方式,就是監控伺服器連線和斷開的行為,在每次伺服器連線和斷開的時候,執行指令碼來知道伺服器是否有人連線

放個流程圖

這裡是一整套的監控流程圖,包括伺服器監控和介面展示

實現

我們有了思路,接下來就是實現的問題

實現起來也比較簡單

但是我們需要解決幾個問題

  1. 如何知道伺服器有沒有人連線?
  2. 如何監控遠端伺服器的連線和斷開?

cmd命令netstat監控3389埠

對於第一個問題,如何知道伺服器有沒有人連線?

這裡可以瞭解一下3389埠遠端桌面的服務埠)和netstat

命令,在windons伺服器中,一般是一個遠端連線的埠,就是說你可以監控這個埠,來知道伺服器有沒有人遠端連線;而netstat (顯示協議統計和當前 TCP/IP 網路連線)是一個cmd命令,我們可以通過它來監控埠情況

比如這裡我們要監控3389埠

我們先連線遠端連線伺服器,開啟cmd命令視窗,輸入命令:netstat -n -p tcp | find ":3389"

我們就得到一個類似如這樣的結果

TCP 10.11.174.373:55311 16.21.315.55:3389 ESTABLISHED

這裡有2個ip,一個10.11.174.373,這個是你本地的ip,一個16.21.315.55,這個就是你伺服器的ip

但你在伺服器上執行這個命令的時候,如果有遠端連線,那麼就會得到這樣的一個結果(當然,你自己連線的也算),當沒有人連線的時候,就會得到一個空的,沒有任何連線情況

python指令碼實現

這裡的指令碼,我們要實現3個功能:

  1. 獲取本地ip
  2. 獲取伺服器連線狀態(ip)
  3. 相關資料儲存到資料庫

雖然我們使用netstat命令監控3389埠的時候有本地的ip,但是這只是有遠端連線的時候有ip資訊,但是如果無人連線,那麼就獲取不到,當然,你也可以自填本地ip,不過這樣並不是很好

獲取本地ip,這裡我們是用python中的socket函式來實現

socket.getaddrinfo(socket.gethostname(),None)[-1][-1][0]

後面的伺服器連線,上面有說

資料庫儲存,也就不多做說明了,直接上下程式碼(這裡資料庫,請自行建好)

#!/usr/bin/env python
# -*- encoding: utf-8 -*-
'''
@File    :   server_ip.py
@Time    :   2020/04/23 10:08:15
@Author  :   吉祥鳥
@GitHub  :   https://github.com/jixn-hu
@CSDN    :   https://me.csdn.net/qq_37462361
'''


import os
import re
import pyodbc
import time
import socket

def now_time():
    """
    格式化返回當前時間
    :return:
    """
    now = int(time.time())
    local_time = time.localtime(now)
    format_now = time.strftime("%Y-%m-%d %H:%M:%S", local_time)
    return format_now

def open_184_db(db="rreporttask"):
    """
    開啟本地資料庫
    :param db: 資料庫(預設為rreporttask)
    :return: 建立好的資料庫連線
    """
    print(now_time(), '連線184資料庫%s' % db)
    driver = 'SQL Server'
    # 資料庫ip
    serverName = '******'
    # 登陸使用者名稱和密碼
    userName = '******'
    passWord = '******'
    # 建立連線並獲取cursor
    conn = pyodbc.connect(driver=driver, server=serverName,
                          user=userName, password=passWord, database=db, charset="gbk")
    return conn


def insert_many(conn, items, table_name):
    """
    多條資料插入到資料庫(注:插入的資料包含表裡的關鍵字)
    :param conn:資料庫
    :param items:插入的資料列表字典(列表內包含字典型別)
    :param table_name:資料庫表名
    :return:無
    """
    print(now_time(), "更新資料表{}...".format(table_name))
    # print(now_time(),"item:", items)
    if items:
        cursor = conn.cursor()
        sql1 = "insert into %s" % table_name
        sql2 = "("
        sql3 = ") values("
        sql4 = ")"
        for key in items[0].keys():  # 拼接sql語句
            sql2 += "%s," % key
            sql3 += "?,"
            # sql4 += "%s=values(%s)," % (key, key)
        sql = sql1 + sql2[:-1] + sql3[:-1] + sql4
        item_values = []
        for item in items:
            item_values.append(list(item.values()))
        num = len(item_values)
        # print(num)
        print(now_time(), '一共需要處理資料%s條' % num)
        # print(now_time(),"sql:", sql)

        try:
            for i in range(0, num, 1000):
                a = min(num, 1000 + i)
                # print(item_values[i:a])
                cursor.executemany(sql, item_values[i:a])
                conn.commit()
                print(now_time(), "當前已經處理%s條資料" % a)
        except Exception as e:
            print(now_time(), '更新資料失敗,回滾')
            print(e)
            conn.rollback()
    conn.close()


def main():
    items = []
    item = {}
    time.sleep(1)
    cmd = 'netstat -n -p  tcp | find ":3389"'
    command = os.popen(cmd)
    r = command.read()
    print(r)
    zz = r.split("\n")[0].split()
    if r=='':
        ip = "0000"
    else:
        local_ip = zz[1]
        local_ip = re.sub(r":.*$",'',local_ip)
        ip = zz[2]
    item["server_ip"]=socket.getaddrinfo(socket.gethostname(),None)[-1][-1][0] # 本地ip
    item["sign_ip"] = ip
    item["entrytime"] = now_time()
    items.append(item)
    print(item)
    conn = open_184_db()
    insert_many(conn,items,"server_sign")
    

if __name__ == "__main__":
    main()

你可以把這個python指令碼,打包成exe,然後放到伺服器上,設定觸發條件,當有人連線和斷開伺服器的時候,執行這個指令碼

至於如何設定這個觸發器,這就是第二個問題了,如何監控遠端伺服器的連線和斷開?

這裡可以百度下,windons自帶的任務計劃程式,通過這個我們可以設定exe伺服器連線和斷開的時,執行exe指令碼,放個圖,之後的自行摸索下

其實到這裡,基本就是結束了,詳細的思路和主要的實現,也都有了,我們可以直接查詢資料庫就能的知道伺服器連線的情況

展示

不過後面為了更方便看,後面我自己又使用flask做了一個介面展示

就不多說明了

先放個成果圖

直接上程式碼

server_sign.py:

#!/usr/bin/env python
# -*- encoding: utf-8 -*-
'''
@File    :   server_sign.py
@Time    :   2020/04/07 10:47:52
@Author  :   吉祥鳥
@GitHub  :   https://github.com/jixn-hu
@CSDN    :   https://me.csdn.net/qq_37462361
'''

import re
import pyodbc
import time
from flask import Flask,render_template

app=Flask(__name__)

def now_time():
    """
    格式化返回當前時間
    :return:
    """
    now = int(time.time())
    local_time = time.localtime(now)
    format_now = time.strftime("%Y-%m-%d %H:%M:%S", local_time)
    return format_now

def open_184_db(db="rreporttask"):
    """
    開啟本地資料庫
    :param db: 資料庫(預設為rreporttask)
    :return: 建立好的資料庫連線
    """
    print(now_time(), '連線184資料庫%s' % db)
    driver = 'SQL Server'
    serverName = '******'
    # 登陸使用者名稱和密碼
    userName = '******'
    passWord = '******'
    # 建立連線並獲取cursor
    conn = pyodbc.connect(driver=driver, server=serverName,
                          user=userName, password=passWord, database=db, charset="gbk")
    return conn


def select_one(conn, sql="select ios_id from ios_main"):
    """
    查詢資訊
    :param time:
    :param type:
    :return:
    """
    print(now_time(), "正在查詢資料庫......")
    cursor = conn.cursor()
    try:
        cursor.execute(sql)
        result = cursor.fetchall()
        conn.commit()
        print(now_time(), "資料查詢成功")
        return result
    except:
        print(now_time(), '更新資料失敗,回滾')
        conn.rollback()
    conn.close()



@app.route('/admin/<name>') # route() 裝飾器告訴 Flask 什麼樣的URL 能觸發我們的函式
def hello_world(name):
    conn = open_184_db()
    data_back = {}
    datas = select_one(conn,"select server_ip,sign_ip,entrytime from(select *,ROW_NUMBER()over(partition by server_ip order by entrytime desc)rank from rreporttask..server_sign) as z where rank=1 order by server_ip")
    for data in datas:
        if data[1]=='0000' or '3389' in data[1]:
            data_back[data[0]]="未連線"
            data[1]="無"
        else:
            data_back[data[0]]="連線ing"
    # print(datas)
    return render_template("login.html",name=name,datas=datas,data_back=data_back)


@app.route('/hal/<name>') # route() 裝飾器告訴 Flask 什麼樣的URL 能觸發我們的函式
def hello_world1(name):
    return "hellodd {}".format(name)

if __name__ == "__main__":
    app.run(debug = True,host='0.0.0.0') # 用 run() 函式來讓應用執行在本地伺服器上


login.html:

<html>
   <!-- CSS goes in the document HEAD or added to your external stylesheet -->
<style type="text/css">
   table.hovertable {
   font-family: verdana,arial,sans-serif;
   font-size:11px;
   color:#333333;
   border-width: 1px;
   border-color: #999999;
   border-collapse: collapse;
   }
   table.hovertable th {
   background-color:#c3dde0;
   border-width: 1px;
   padding: 8px;
   border-style: solid;
   border-color: #a9c6c9;
   }
   table.hovertable tr {
   background-color:#d4e3e5;
   }
   table.hovertable td {
   border-width: 1px;
   padding: 8px;
   border-style: solid;
   border-color: #a9c6c9;
   }
   </style>
   <body>
      <h1>伺服器登入狀態檢視</h1>
      <table class="hovertable">
         <tr>
            <th>伺服器ip</th>
            <th>登入ip</th>
            <th>連線時間</th>
            <th>連線狀態</th>
         </tr>
         {% for data in datas %}
            <tr>
               <td>{{ data[0] }}</td>
               <td>{{ data[1] }}</td>
               <td>{{ data[2] }}</td>
               <td>{{ data_back[data[0]] }}</td>
            </tr>
         {% endfor %}
      </table>

   </body>
   
</html>

思維導圖

最後,放一個思維導圖,供參考

關注我獲取更多內容
注:轉載還請註明出處,謝謝_