netstatコマンドのGUIラッパー

PCの通信状態を調べるときに使われるコマンド netstat をラップするGUIwxPythonで作成した。
コマンドプロンプトで、"netstat -a"としたときの実行結果を画面で表示しているだけで単純だが、始めの一歩ということで。

  • 応用として考えられること
    • コマンドの実行結果をそのまま表示するのではなく、理解しやすい言葉に直して表示する。
    • タブで画面を切り替えられるようにして、他のネットワーク関係のコマンドを実行できる画面を加えていく。
    • このアプリ一つで、ネットワークの状態を診断できるようなものにする。

ソースコードは、2つに分けてあり、_main_tree.pyとMainFrame.pyがある。_main_tree.pyの方を実行すればよい。

実行画面は、以下の通り。ボタンを押すと、裏で"netstat"を実行して結果を表に表示している。

ソース(その1)_main_tree.py

#!/bin/env python
# coding: utf-8
#----------------------------------------------------------------------------
# Name:         _main_tree.py
# Purpose:      MSNetstat: wrapper for "netstat -a"
# Date:         2008/07/30     
#----------------------------------------------------------------------------
import os, sys
import wx

import MainFrame

class Application(wx.App):
    def OnInit(self):
        frame = MainFrame.MainFrame(None, -1)
        frame.Show(True)
        self.SetTopWindow(frame)
        return True

def main():
    import time

    app = Application(0)
    app.MainLoop()

if __name__ == '__main__':
    main()

ソース(その2)MainFrame.py

#!/bin/env python
# coding: utf-8 
#----------------------------------------------------------------------------
# Name:         MainFrame.py
# Purpose:      wrapper for "netstat -a"
# Date:         2008/07/30      
#----------------------------------------------------------------------------
# system library
import sys, os
import wx
import wx.grid
import popen2

class MainFrame(wx.Frame):       
    def __init__(self, id, title):
        width, height = 680, 360
        wx.Frame.__init__(self, id, title=u"通信状態確認プログラム(netstat)",
                          size=wx.Size(width, height))

        # status bar
        sb = self.CreateStatusBar(2)
        sb.SetStatusWidths([-1, 150])
        sb.SetStatusText("")

        # panel
        self.Pan = wx.Panel(self, -1)

        Sizer1 = wx.BoxSizer(wx.VERTICAL)
        BtnExe = wx.Button(self.Pan, -1, u"状態調査")
        BtnExe.Bind(wx.EVT_BUTTON, self.ExeCmd)
        self.tabl = RsltTable(self.Pan)
        
        Sizer1.Add(BtnExe,    0, wx.FIXED_MINSIZE | wx.ALL, 10)
        Sizer1.Add(self.tabl, 0, wx.ALL, 10)
        self.Pan.SetSizer(Sizer1)
        
        # menu bar
        self.SetMenuBar(self.MakeMenu())
        
    def MakeMenu(self):
        menuBar = wx.MenuBar()

        self.menu1 = wx.Menu()
        self.menu1.Append(101, u"アプリケーションを終了(&E)")
        menuBar.Append(self.menu1, u"終了(&E)")
        wx.EVT_MENU(self, 101, self.ExitAppl)

        return menuBar

    def ExeCmd(self, event):
        cmd_name = 'netstat.exe -a'
        output = 'netstat.log'
        fd = open(output, 'w')
        r, w, e = popen2.popen3(cmd_name)
        while True:
            s = r.readline()
            if s == '':
                break
            if fd:
                fd.write(s)

        fd.close()

        # parser for netstat.log
        parse = ParseFile()
        parse.ParseFile1(output)
        num = len(parse.LstAddFrom)

        self.tabl.UpdateList(num, 0, parse.LstAddFrom)
        self.tabl.UpdateList(num, 1, parse.LstAddFromP)
        self.tabl.UpdateList(num, 2, parse.LstAddTo)
        self.tabl.UpdateList(num, 3, parse.LstAddToP)
        self.tabl.UpdateList(num, 4, parse.LstStatus)


    def ExitAppl(self, event):
        Dlg = wx.MessageDialog(self,u"本当に終了してもよろしいですか?OKボタンで終了します。",
                               u"終了", style=wx.OK|wx.CANCEL|wx.ICON_QUESTION,
                               pos=(0,0))
        Answer = Dlg.ShowModal()
        if Answer == wx.ID_OK:
            self.Close()
        Dlg.Destroy

class RsltTable(wx.grid.Grid):
    def __init__(self, parent):
        wx.grid.Grid.__init__(self, parent, -1)

        self.clmnum = 10   # maximum column number
        self.CreateGrid(self.clmnum, 5)
        self.SetColLabelValue(0, u"通信元")
        self.SetColLabelValue(1, u"ポート")
        self.SetColLabelValue(2, u"通信先")
        self.SetColLabelValue(3, u"ポート")
        self.SetColLabelValue(4, u"状態")
        self.SetColSize(0, 150)
        self.SetColSize(1, 80)
        self.SetColSize(2, 150)
        self.SetColSize(3, 80)
        self.SetColSize(4, 100)

    def UpdateList(self, num, cnum, data):
        if self.clmnum < num:
            self.AppendRows(num - self.clmnum)
            self.clmnum = num

        for k in xrange(num):
            self.SetCellValue(k, cnum, data[k])


class ParseFile:
    def __init__(self):
        self.LstAddFrom = []
        self.LstAddTo   = []
        self.LstAddFromP= []
        self.LstAddToP  = []
        self.LstStatus  = []

    def ParseFile1(self, filename):
        input = open(filename, 'r')
        L = input.readlines()
        input.close()

        for i in xrange(len(L)):
            tmp = L[i].split()
            if tmp != [] and tmp[0] == 'TCP':
                addfrom = tmp[1]
                addto   = tmp[2]
                stat    = tmp[3]
                self.LstAddFrom.append(addfrom.split(':')[0])
                self.LstAddFromP.append(addfrom.split(':')[1])
                self.LstAddTo.append(addto.split(':')[0])
                self.LstAddToP.append(addto.split(':')[1])
                self.LstStatus.append(stat)