2017-06-18 10 views
-2

私はpythonを初めて使い、tkinterテキストボックスにサーバのコマンドライン出力を表示するのに問題があります。私はtkinterテキストボックスに何が起こっているのかを表示し、リストボックスにIPアドレスのリストを表示したいと思います。私は本を​​見ましたが、これをうまく動作させるのに問題があります。私はPython 3.5を使用しています。サーバがtkinterで何をしているかを表示

from tkinter import * 
import tkinter as tk 
import threading 
import socket 
import time 
import sys 

from queue import Queue 
import struct 
import signal 

NUMBER_OF_THREADS = 2 
JOB_NUMBER = [1, 2] 
queue = Queue() 

COMMANDS = {'help':['Shows this help'], 
      'list':['Lists connected clients'], 
      'select':['Selects a client by its index. Takes index as a parameter'], 
      'quit':['Stops current connection with a client. To be used when client is selected'], 
      'shutdown':['Shuts server down'], 
      } 


class MultiServer(object): 

    def __init__(self): 
     self.host = '' 
     self.port = 9999 
     self.socket = None 
     self.all_connections = [] 
     self.all_addresses = [] 

    def print_help(self): 
     for cmd, v in COMMANDS.items(): 
      # print("{0}:\t{1}".format(cmd, v[0])) 
      self.textBox.insert("{0}:\t{1}".format(cmd, v[0])) 
     return 

    def register_signal_handler(self): 
     signal.signal(signal.SIGINT, self.quit_gracefully) 
     signal.signal(signal.SIGTERM, self.quit_gracefully) 
     return 

    def quit_gracefully(self, signal=None, frame=None): 
     print('\nQuitting gracefully') 
     for conn in self.all_connections: 
      try: 
       conn.shutdown(2) 
       conn.close() 
      except Exception as e: 
       print('Could not close connection %s' % str(e)) 
       # continue 
     self.socket.close() 
     sys.exit(0) 

    def socket_create(self): 
     try: 
      self.socket = socket.socket() 
     except socket.error as msg: 
      print("Socket creation error: " + str(msg)) 
      # TODO: Added exit 
      sys.exit(1) 
     self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 
     return 

    def socket_bind(self): 
     """ Bind socket to port and wait for connection from client """ 
     try: 
      self.socket.bind((self.host, self.port)) 
      self.socket.listen(5) 
     except socket.error as e: 
      print("Socket binding error: " + str(e)) 
      time.sleep(5) 
      self.socket_bind() 
     return 

    def accept_connections(self): 
     """ Accept connections from multiple clients and save to list """ 
     for c in self.all_connections: 
      c.close() 
     self.all_connections = [] 
     self.all_addresses = [] 
     while 1: 
      try: 
       conn, address = self.socket.accept() 
       conn.setblocking(1) 
       client_hostname = conn.recv(1024).decode("utf-8") 
       address = address + (client_hostname,) 
      except Exception as e: 
       print('Error accepting connections: %s' % str(e)) 
       # Loop indefinitely 
       continue 
      self.all_connections.append(conn) 
      self.all_addresses.append(address) 
      print('\nConnection has been established: {0} ({1})'.format(address[-1], address[0])) 
     return 

    def start_turtle(self): 
     """ Interactive prompt for sending commands remotely """ 
     while True: 
      cmd = input('turtle> ') 
      if cmd == 'list': 
       self.list_connections() 
       continue 
      elif 'select' in cmd: 
       target, conn = self.get_target(cmd) 
       if conn is not None: 
        self.send_target_commands(target, conn) 
      elif cmd == 'shutdown': 
        queue.task_done() 
        queue.task_done() 
        print('Server shutdown') 
        break 
        # self.quit_gracefully() 
      elif cmd == 'help': 
       self.print_help() 
      elif cmd == '': 
       pass 
      else: 
       print('Command not recognized') 
     return 

    def list_connections(self): 
     """ List all connections """ 
     results = '' 
     for i, conn in enumerate(self.all_connections): 
      try: 
       conn.send(str.encode(' ')) 
       conn.recv(20480) 
      except: 
       del self.all_connections[i] 
       del self.all_addresses[i] 
       continue 
      results += str(i) + ' ' + str(self.all_addresses[i][0]) + ' ' + str(
       self.all_addresses[i][1]) + ' ' + str(self.all_addresses[i][2]) + '\n' 
     print('----- Clients -----' + '\n' + results) 
     return 

    def get_target(self, cmd): 
     """ Select target client 
     :param cmd: 
     """ 
     target = cmd.split(' ')[-1] 
     try: 
      target = int(target) 
     except: 
      print('Client index should be an integer') 
      return None, None 
     try: 
      conn = self.all_connections[target] 
     except IndexError: 
      print('Not a valid selection') 
      return None, None 
     print("You are now connected to " + str(self.all_addresses[target][2])) 
     return target, conn 

    def read_command_output(self, conn): 
     """ Read message length and unpack it into an integer 
     :param conn: 
     """ 
     raw_msglen = self.recvall(conn, 4) 
     if not raw_msglen: 
      return None 
     msglen = struct.unpack('>I', raw_msglen)[0] 
     # Read the message data 
     return self.recvall(conn, msglen) 

    def recvall(self, conn, n): 
     """ Helper function to recv n bytes or return None if EOF is hit 
     :param n: 
     :param conn: 
     """ 
     # TODO: this can be a static method 
     data = b'' 
     while len(data) < n: 
      packet = conn.recv(n - len(data)) 
      if not packet: 
       return None 
      data += packet 
     return data 

    def send_target_commands(self, target, conn): 
     """ Connect with remote target client 
     :param conn: 
     :param target: 
     """ 
     conn.send(str.encode(" ")) 
     cwd_bytes = self.read_command_output(conn) 
     cwd = str(cwd_bytes, "utf-8") 
     print(cwd, end="") 
     while True: 
      try: 
       cmd = input() 
       if len(str.encode(cmd)) > 0: 
        conn.send(str.encode(cmd)) 
        cmd_output = self.read_command_output(conn) 
        client_response = str(cmd_output, "utf-8") 
        print(client_response, end="") 
       if cmd == 'quit': 
        break 
      except Exception as e: 
       print("Connection was lost %s" %str(e)) 
       break 
     del self.all_connections[target] 
     del self.all_addresses[target] 
     return 


def create_workers(): 
    """ Create worker threads (will die when main exits) """ 
    server = MultiServer() 
    server.register_signal_handler() 
    for _ in range(NUMBER_OF_THREADS): 
     t = threading.Thread(target=work, args=(server,)) 
     t.daemon = True 
     t.start() 
    return 


def work(server): 
    """ Do the next job in the queue (thread for handling connections, another for sending commands) 
    :param server: 
    """ 
    while True: 
     x = queue.get() 
     if x == 1: 
      server.socket_create() 
      server.socket_bind() 
      server.accept_connections() 
     if x == 2: 
      server.start_turtle() 
     queue.task_done() 
    return 

def create_jobs(): 
    """ Each list item is a new job """ 
    for x in JOB_NUMBER: 
     queue.put(x) 
    queue.join() 
    return 

def main(): 
    create_workers() 
    create_jobs() 



class App(threading.Thread, MultiServer): 

    def __init__(self): 
     MultiServer.__init__(self) 
     threading.Thread.__init__(self) 
     self.start() 


    def run(self): 
     self.root = Tk() 

     # create all of the main containers 
     self.top_frame = Frame() 
     self.center_frame = Frame() 

     # layout all of the main containers 
     self.root.grid_rowconfigure(1, weight=1) 
     self.root.grid_columnconfigure(0, weight=1) 

     self.top_frame.grid(row=0, sticky='NSEW') 
     self.center_frame.grid(row=1, pady=5, sticky='NSEW') 

     # Top frame 
     self.logo = Label(self.top_frame, text='SunGroup') 
     self.logo.grid(row=0, columnspan=3) 

     self.command = Entry(self.top_frame, width=25) 
     self.command.grid(row=1, column=0, padx=5) 

     self.addButton = Button(self.top_frame, text='Enter', width=5) 
     self.addButton.grid(row=1, column=1, padx=5) 

     self.listButton = Button(self.top_frame, text='List', width=5, command=self.list_connections) 
     self.listButton.grid(row=1, column=2) 

     self.selectButton = Button(self.top_frame, text='Select', width=5, command=self.get_target) 
     self.selectButton.grid(row=1, column=3) 

     self.quitButton = Button(self.top_frame, text='Quit', width=5, command=self.quit_gracefully) 
     self.quitButton.grid(row=1, column=4) 

     self.helpButton = Button(self.top_frame, text='Help', width=5, command=self.print_help) 
     self.helpButton.grid(row=1, column=5) 


     # Center frame 
     self.listbox = Listbox(self.center_frame, width=20, height=20) 
     self.listbox.grid(row=0, column=0, padx=5) 

     self.textBox = Text(self.center_frame, width=35, height=20) 
     self.textBox.grid(row=0, column=1, padx=5) 
     self.textBox.insert(END, self.start_turtle, self.print_help) 


     self.root.mainloop() 



if __name__ == '__main__': 
    app = App() 
    main() 
+1

SOは個人用のデバッグサービスではありません。[mcve]を投稿してください。 – zwer

+0

コードをすべてポーズするのではなく、あなたの特定の問題に対処するために必要な最小量を投稿してください。必要なのは、tkウィンドウ、テキストボックス、そしておそらくボタンと入力ボックスです。残りはちょうど途中です。その後、あなたが試したことのいくつかの例を与え、私たちはそれを使って作業することができます。 –

答えて

0

は、私はあなたのコードを実行すると、私が手::

turtle> Tcl_WaitForEvent: Notifier not initialized 
Abort 

とPythonが終了

は、ここに私のコードです。これも問題であれば、this postは、この非常にエラーを生成するTkがアクティブなときに、メインスレッドの外側でinput()を呼び出す問題を議論します。仕事は周りの代わりのようだ:

cmd = input('turtle> ') 

ような何か:

print('turtle>', end=' ') 
sys.stdout.flush() 
cmd = sys.stdin.readline().rstrip() 

をこれをさらに取得しますが、私は物事が、その後スムーズに実行と言うことはできません。あなたのクライアント/サーバコードはTkなしで動作しますか?私がTkでそれを試したり、Tkを完全に取り除くと、アクティブなクライアント接続がある場合、リストを実行するとハングしているようです。私のクライアントを終了すると、それは回復する。これは私がどのようにテストしているかのアーティファクトかもしれませんが、インターフェイスの上にインターフェイスをレイヤーする前に、コードが基本的に動作することが不可欠です。

関連する問題