Pythonでtelnet接続してみる-wxPython(その7)

リモートホストが落ちていたり、IPアドレスが誤っていると、下記のエラーがDOS窓に表示される。

  ....
  ....
  File "C:\Python27\lib\telnetlib.py", line 225, in open
    self.sock = socket.create_connection((host, port), timeout)
  File "C:\Python27\lib\socket.py", line 571, in create_connection
    raise err
socket.error: [Errno 10060] 接続済みの呼び出し先が一定の時間を過ぎても
正しく応答しなかったため、接続できませんでした。または接続済みのホストが応答しなかったため、
確立された接続は失敗しました。

socket.error については17.2. socket — 低レベルネットワークインターフェース — Python 2.7ja1 documentationに記述がある。

exception socket.error
この例外は、ソケット関連のエラーが発生した場合に送出されます。例外の値は障害の内容を示す文字列か、または os.error と同様な (errno, string) のペアとなります。オペレーティングシステムで定義されているエラーコードについては errno を参照してください。
バージョン 2.6 で変更: socket.error は IOError の子クラスになりました。

このエラーが発生したら、接続できない旨のメッセージを表示させるようにすることにした。

socket.error例外(exception)を捕捉するには、try..except文を使う。

    try:
        res = tn.connect()
    except socket.error, msg:
        e_no, e_str = msg
        e_msg = "could not connect to %s\n" % HOST
        e_msg += "[Errno %s] %s" % (e_no, e_str)
        p.WriteText(e_msg)
        return

プログラム

# -*- coding: utf-8 -*-

import wx
import re
import socket
import telnetlib

class MyTelnet(object):
    def __init__(self, host, user, pswd, prompt):
        self.host = host
        self.user = user
        self.pswd = pswd
        self.prompt = prompt

    def connect(self):
        self.tn = telnetlib.Telnet(self.host)
        self.tn.read_until("login: ")
        self.tn.write(self.user + "\n")
        self.tn.read_until("Password: ")
        self.tn.write(self.pswd + "\n")
        res = self.tn.read_until(self.prompt)
        return self.cvtstr(res)

    def action(self, cmd):
        self.tn.write(cmd + "\n")
        res = self.tn.read_until(self.prompt)
        return self.cvtstr(res)

    def disconnect(self):
        self.tn.write("exit\n")
        res = self.tn.read_all()
        return self.cvtstr(res)

    def cvtstr(self, s):
        #エスケープシーケンスの除去
        r = re.compile(r'\x1b\[.*?m\[?')
        s = re.sub(r,'',s)
        #文字コードutf-8をunicodeに変換
        return s.decode('utf-8')


def telnet_ub01(p):
    HOST = "192.168.11.201"  # your server
    USER = "bty"             # your user name
    PASSWORD = "*******"     # your password
    PROMPT = "bty@ub01:~$"   # your prompt

    tn = MyTelnet(HOST, USER, PASSWORD, PROMPT)

    try:
        res = tn.connect()
    except socket.error, msg:
        e_no, e_str = msg
        e_msg = "could not connect to %s\n" % HOST
        e_msg += "[Errno %s] %s" % (e_no, e_str)
        p.WriteText(e_msg)
        return

    p.WriteText(res)
    res = tn.action("ls -al")
    p.WriteText(res)
    res = tn.action("df")
    p.WriteText(res)
    res = tn.disconnect()
    p.WriteText(res)


class MyFrame(wx.Frame):
    def __init__(self, parent, title):
        wx.Frame.__init__(self, parent, title=title, size=(600,400))

        ctlPanel = wx.Panel(self)
 
        connectBtn = wx.Button(ctlPanel, label=u"接続")
        self.Bind(wx.EVT_BUTTON, self.onConnectBtn, connectBtn)

        quitBtn = wx.Button(ctlPanel, label=u"終了")
        self.Bind(wx.EVT_BUTTON, self.onQuitBtn, quitBtn)
 
        ctlSz = wx.BoxSizer(wx.VERTICAL)
        ctlSz.Add(connectBtn)
        ctlSz.Add(quitBtn)
        ctlPanel.SetSizer(ctlSz)
 
        self.dspText = wx.TextCtrl(self, style=wx.TE_MULTILINE) 
        font = wx.Font(12,  wx.DEFAULT, wx.NORMAL, wx.NORMAL, False, "Terminal")
        self.dspText.SetFont(font)

        sz = wx.BoxSizer(wx.HORIZONTAL)
        sz.Add(ctlPanel, 0, wx.EXPAND)
        sz.Add(self.dspText, 1, wx.EXPAND)
        self.SetSizer(sz)

        self.Show(True)

    def onConnectBtn(self, event):
        telnet_ub01(self.dspText)

    def onQuitBtn(self, event):
        self.Close()


app = wx.App(False)
frame = MyFrame(None, 'MYTELNET')
app.MainLoop()

実行結果

リモートホストをシャットダウンして「接続」ボタンをクリックして接続してみる。

wxtelnet3

参考

20.14. telnetlib — Telnet クライアント — Python 2.7ja1 documentation

6. 組み込み例外 — Python 2.7ja1 documentation

17.2. socket — 低レベルネットワークインターフェース — Python 2.7ja1 documentation

wxPythonについては下記ページからたどると、使える情報の書かれたページリンクがたくさんある
FrontPage – wxPyWiki

Pythonでtelnet接続してみる-wxPython(その6)

Pythonでtelnet接続してみる-wxPython(その5)の実験では、表示する文字が小さく、等幅でないので見にくい。また、リモートホストから受信した文字列がワンテンポ遅れて表示される。なんとか、これらの不満を改善してみた。

●表示を見やすくする

フォントを等幅にするために”Terminal”を設定し、サイズを12ポイントにする

font = wx.Font(12,  wx.DEFAULT, wx.NORMAL, wx.NORMAL, False, "Terminal")
self.dspText.SetFont(font)

●ワンテンポ遅れの表示を改善する

onConnectBtnメソッドでtelnet_ub01関数から文字列を受け取って表示させていたが、telnet_ub01関数内で表示させるようにする。厳密なリアルタイムじゃないけど、目的からすればこれでじゅうぶんだ。

1) onConnectBtnメソッドから telenet_ub01関数に self.dspTextオブジェクトを渡す。

def onConnectBtn(self, event):
    telnet_ub01(self.dspText)

2) telnet_ub01関数の中で、WriteTextメソッドを呼び、文字列を表示する。

def telnet_ub01(p):
    ....
    res = tn.connect()
    p.WriteText(res)
    ....

プログラム

# -*- coding: utf-8 -*-

import wx
import re
import telnetlib

class MyTelnet(object):
    def __init__(self, host, user, pswd, prompt):
        self.host = host
        self.user = user
        self.pswd = pswd
        self.prompt = prompt

    def connect(self):
        self.tn = telnetlib.Telnet(self.host)
        self.tn.read_until("login: ")
        self.tn.write(self.user + "\n")
        self.tn.read_until("Password: ")
        self.tn.write(self.pswd + "\n")
        res = self.tn.read_until(self.prompt)
        return self.cvtstr(res)

    def action(self, cmd):
        self.tn.write(cmd + "\n")
        res = self.tn.read_until(self.prompt)
        return self.cvtstr(res)

    def disconnect(self):
        self.tn.write("exit\n")
        res = self.tn.read_all()
        return self.cvtstr(res)

    def cvtstr(self, s):
        #エスケープシーケンスの除去
        r = re.compile(r'\x1b\[.*?m\[?')
        s = re.sub(r,'',s)
        #文字コードutf-8をunicodeに変換
        return s.decode('utf-8')


def telnet_ub01(p):
    HOST = "192.168.11.201"  # your server
    USER = "bty"             # your user name
    PASSWORD = "*******"     # your password
    PROMPT = "bty@ub01:~$"   # your prompt

    tn = MyTelnet(HOST, USER, PASSWORD, PROMPT)

    res = tn.connect()
    p.WriteText(res)
    res = tn.action("ls -al")
    p.WriteText(res)
    res = tn.action("df")
    p.WriteText(res)
    res = tn.disconnect()
    p.WriteText(res)


class MyFrame(wx.Frame):
    def __init__(self, parent, title):
        wx.Frame.__init__(self, parent, title=title, size=(600,400))

        ctlPanel = wx.Panel(self)
 
        connectBtn = wx.Button(ctlPanel, label=u"接続")
        self.Bind(wx.EVT_BUTTON, self.onConnectBtn, connectBtn)

        quitBtn = wx.Button(ctlPanel, label=u"終了")
        self.Bind(wx.EVT_BUTTON, self.onQuitBtn, quitBtn)
 
        ctlSz = wx.BoxSizer(wx.VERTICAL)
        ctlSz.Add(connectBtn)
        ctlSz.Add(quitBtn)
        ctlPanel.SetSizer(ctlSz)
 
        self.dspText = wx.TextCtrl(self, style=wx.TE_MULTILINE) 
        font = wx.Font(12,  wx.DEFAULT, wx.NORMAL, wx.NORMAL, False, "Terminal")
        self.dspText.SetFont(font)

        sz = wx.BoxSizer(wx.HORIZONTAL)
        sz.Add(ctlPanel, 0, wx.EXPAND)
        sz.Add(self.dspText, 1, wx.EXPAND)
        self.SetSizer(sz)

        self.Show(True)

    def onConnectBtn(self, event):
        telnet_ub01(self.dspText)

    def onQuitBtn(self, event):
        self.Close()


app = wx.App(False)
frame = MyFrame(None, 'MYTELNET')
app.MainLoop()

実行結果

wxtelnet2

Pythonでtelnet接続してみる-wxPython(その5)

やっぱり、Windowsで動かすアプリはGUIじゃないと格好つかない。

ということで、wxPython で GUIプログラムの実験をしてみた。

wxPython では、ベースとなる Frame に、ボタンを配置するための ctlPanel と、リモートホストから受信した文字列を表示するための dspText を作る。

ctlPanelに表示するボタンは、telnet接続してコマンド実行するための「接続」ボタン、アプリを終了するための「終了」ボタンを作った。BoxSizerで垂直方向(VERTICAL)に並べる。

そして、ボタンを配置したctlPanel と、dspText を BoxSizer で水平方向(HORIZONTAL)にならべて画面を作った。

「接続」ボタンをクリックすると、Bindメソッドで紐づけられた onConnectBtnメソッドが呼ばれ、telnet接続する telnet_ub01関数を実行してリモートホストからの文字列が返る。dspText の WriteTextメソッドで文字列を表示させる。

WriteTextメソッドで渡す文字列の文字コードはunicodeでなければならない。なので、MyTelnet クラスで、cvtstrメソッドの文字コード変換部分を utf-8 から unicode への変換としている。

実行してみると、telent接続、コマンド実行の一連の処理が終了してから、結果が表示されるので、反応がのろい感じがしてしまう。接続、コマンド実行の単位で結果表示するようにしないと、アプリが動作しているのかどうか不安になる。

いろいろ問題があるにせよ、こんな簡単なスクリプトで、Windows GUIアプリが作れてしまう。

プログラム

# -*- coding: utf-8 -*-

import wx
import re
import telnetlib

class MyTelnet(object):
    def __init__(self, host, user, pswd, prompt):
        self.host = host
        self.user = user
        self.pswd = pswd
        self.prompt = prompt

    def connect(self):
        self.tn = telnetlib.Telnet(self.host)
        self.tn.read_until("login: ")
        self.tn.write(self.user + "\n")
        self.tn.read_until("Password: ")
        self.tn.write(self.pswd + "\n")
        res = self.tn.read_until(self.prompt)
        return self.cvtstr(res)

    def action(self, cmd):
        self.tn.write(cmd + "\n")
        res = self.tn.read_until(self.prompt)
        return self.cvtstr(res)

    def disconnect(self):
        self.tn.write("exit\n")
        res = self.tn.read_all()
        return self.cvtstr(res)

    def cvtstr(self, s):
        #エスケープシーケンスの除去
        r = re.compile(r'\x1b\[.*?m\[?')
        s = re.sub(r,'',s)
        #文字コードutf-8をunicodeに変換
        return s.decode('utf-8')


def telnet_ub01():
    HOST = "192.168.11.201"  # your server
    USER = "bty"             # your user name
    PASSWORD = "*******"     # your password
    PROMPT = "bty@ub01:~$"   # your prompt

    tn = MyTelnet(HOST, USER, PASSWORD, PROMPT)

    res = tn.connect()
    res += tn.action("ls -al")
    res += tn.action("df")
    res += tn.disconnect()
    return res


class MyFrame(wx.Frame):
    def __init__(self, parent, title):
        wx.Frame.__init__(self, parent, title=title, size=(600,400))

        ctlPanel = wx.Panel(self)
 
        connectBtn = wx.Button(ctlPanel, label=u"接続")
        self.Bind(wx.EVT_BUTTON, self.onConnectBtn, connectBtn)

        quitBtn = wx.Button(ctlPanel, label=u"終了")
        self.Bind(wx.EVT_BUTTON, self.onQuitBtn, quitBtn)
 
        ctlSz = wx.BoxSizer(wx.VERTICAL)
        ctlSz.Add(connectBtn)
        ctlSz.Add(quitBtn)
        ctlPanel.SetSizer(ctlSz)
 
        self.dspText = wx.TextCtrl(self, style=wx.TE_MULTILINE) 
        sz = wx.BoxSizer(wx.HORIZONTAL)
        sz.Add(ctlPanel, 0, wx.EXPAND)
        sz.Add(self.dspText, 1, wx.EXPAND)
        self.SetSizer(sz)

        self.Show(True)

    def onConnectBtn(self, event):
        result = telnet_ub01()
        self.dspText.WriteText(result)

    def onQuitBtn(self, event):
        self.Close()


app = wx.App(False)
frame = MyFrame(None, 'MYTELNET')
app.MainLoop()

実行結果

wxtelnet1