Одноэкземплярное приложение - Передача команд

Я использую wxPython и пытаюсь создать приложение с одним экземпляром. В этом нет никаких проблем. Моя проблема заключается в передаче команд в уже существующий экземпляр.
Итак, допустим, что когда я дважды щелкаю файл, связанный с моим приложением, он читает файл и отображает его, вот пример:

import wx
import sys
import os
import SocketServer
import socket
import threading
class MyFrame(wx.Frame):
    def __init__(self, parent, id, title):
        wx.Frame.__init__(self, parent, id, title, wx.DefaultPosition, wx.Size(320, 350))

        getfile = os.path.abspath(sys.argv[1])
        print getfile
        fopen = open (getfile, 'r')
        fread = fopen.read()

        panel = wx.Panel(self, -1)
        wx.StaticText(panel, -1, fread, (45, 25), style=wx.ALIGN_CENTRE)
        self.Centre()
class ThreadedTCPRequestHandler(SocketServer.BaseRequestHandler):
    def handle(self):
        data = self.request.recv(1024)
        cur_thread = threading.currentThread()

        # do something with the request
        print "work"
        # could instead of the length of the input, could return error codes, more
        # information (if the request was a query), etc.  Using a length function
        # as a simple example
        response = 'string length: %d' % len(data)

        print 'responding to',data,'with',response
        self.request.send(response)
class ThreadedTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
    stopped = False
    allow_reuse_address = True

    def serve_forever(self):
        while not self.stopped:
            self.handle_request()

    def force_stop(self):
        self.server_close()
        self.stopped = True

def client(ip, port, message):
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.connect((ip, port))
    sock.send(message)
    response = sock.recv(1024)
    print "Received: %s" % response
    sock.close()

def start_server(host, port):

    server = ThreadedTCPServer((host, port), ThreadedTCPRequestHandler)
    ip, port = server.server_address

    # Start a thread with the server -- that thread will then start one
    # more thread for each request
    server_thread = threading.Thread(target=server.serve_forever)
    # Exit the server thread when the main thread terminates
    server_thread.setDaemon(True)
    server_thread.start()

    return server
class MyApp(wx.App):
    def OnInit(self):
        frame = MyFrame(None, -1, 'test')
        frame.Show(True)
        self.SetTopWindow(frame)
        return True

def main():
    app = MyApp(0)
    app.MainLoop()

if __name__ == '__main__':
    HOST, PORT = socket.gethostname(), 61955

    server = None
    try:
        client(HOST, PORT, ' '.join(sys.argv))
        sys.exit()
    except socket.error:
        server = start_server(HOST, PORT)
        main()

Это прекрасно работает, но теперь я хочу сделать это приложение с одним экземпляром. И я знаю, что есть несколько способов сделать это, и в моем случае я обнаружил, что прослушивание определенного порта, вероятно, является лучшим вариантом. Но даже используя такую ​​опцию, я понятия не имею, как я могу передать информацию о файле или, по крайней мере, имя исходному экземпляру и отобразить его.

Итак, приложение должно быть:

  • Единичное приложение.
  • Он должен иметь возможность читать файлы, по которым дважды щелкнули мышью.
  • Если экземпляр уже открыт, передайте информацию или имя файла исходному экземпляру, чтобы он мог автоматически обновлять и отображать данные файла.

Кроме того, я не включил какой-либо код для прослушивания определенного порта, потому что я действительно мало о нем знаю, поэтому любая помощь по этому вопросу также приветствуется.

РЕДАКТИРОВАТЬ: Код, отредактированный с использованием "прослушивания определенного порта", взят из примера. Обратите внимание, что print "work" действительно отправляет в запущенный экземпляр, я просто не знаю, как заставить его работать в моем случае (из-за моего простого незнания).


person dpswt    schedule 02.04.2011    source источник
comment
чистое невежество? Которого? Укажите, что не работает. У вас есть ряд требований - какой конкретный вопрос, проблема или ошибка вы получаете?   -  person S.Lott    schedule 04.04.2011
comment
Ничего, я разобрался, наверное, скоро опубликую ответ, но это было довольно легко. Спасибо, в любом случае.   -  person dpswt    schedule 05.04.2011
comment
Хотите поделиться с нами своим решением?   -  person Ivo Flipse    schedule 07.04.2011
comment
@Ivo Извините, я сейчас отправлю ответ.   -  person dpswt    schedule 09.04.2011


Ответы (2)


Приложение «Единственный экземпляр» состоит из двух частей.

"Клиент", по которому дважды щелкают мышью и запускается. Если сервер не запущен, он запускает сервер. Он передает команды серверу. И останавливается. Оставляя сервер работающим.

«Сервер», который запускает каждый клиент. Он «слушает определенный порт». Или, возможно, чтение из именованного канала (что иногда работает лучше).

Сервер делает реальную работу. Клиент передает ему команды.

person S.Lott    schedule 02.04.2011
comment
Да, я вроде как понимаю основную концепцию этого, я действительно просто не совсем знаю, как использовать это должным образом в моем конкретном случае. - person dpswt; 02.04.2011
comment
@ Франсиско Алейксо: просто не знаю, как правильно им пользоваться. Хорошо. Почему бы вам на самом деле не прочитать о написании клиентов и серверов. Прочтите об именованных каналах, сокетах, общей памяти и т.п. и напишите небольшую крошечную программу, которая является клиентом, запускающим сервер, а затем задайте конкретные вопросы об этом коде. Здесь сложно предоставить что-то большее, потому что ваш вопрос (не совсем знаю) слишком расплывчатый, чтобы на него можно было ответить. - person S.Lott; 02.04.2011
comment
Что ж, у меня есть код, который действительно делает это, и он действительно работает с точки зрения превращения его в приложение с одним экземпляром, и он отправляет информацию в запущенный экземпляр, но я не совсем знаю, как обработать его, чтобы обновить это, я отредактирую пост с кодом, который фактически скопирован из другого примера (и вы правы, я подробнее прочитаю об этом) - person dpswt; 02.04.2011
comment
@Francisco Aleixo, возможно, вы захотите включить ссылку на ваш исходный пост так что каждый может получить лучшее представление о том, что вы сделали на данный момент. ;) - person AWainb; 02.04.2011

Это решение:

import wx
import sys
import os
import SocketServer
import socket
import threading
class MyFrame(wx.Frame):
    def __init__(self, parent, id, title):
        wx.Frame.__init__(self, parent, id, title, wx.DefaultPosition, wx.Size(320, 350))

        getfile = os.path.abspath(sys.argv[1])
        print getfile
        fopen = open (getfile, 'r')
        fread = fopen.read()

        panel = wx.Panel(self, -1)
        self.static = wx.StaticText(panel, -1, fread, (45, 25), style=wx.ALIGN_CENTRE)
        self.Centre()
class ThreadedTCPRequestHandler(SocketServer.BaseRequestHandler):
    def handle(self):
        data = self.request.recv(1024)
        cur_thread = threading.currentThread()

        data = data.split()
        gfile = os.path.abspath(data[-1])
        fopen = open(gfile, 'r')
        fread = fopen.read()
        self.server.app.static.SetLabel(fread)
        #Note to the self.server.app
        response = 'string length: %d' % len(data)

        print 'responding to',data,'with',response
        self.request.send(response)
class ThreadedTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
    stopped = False
    allow_reuse_address = True

    def serve_forever(self):
        while not self.stopped:
            self.handle_request()

    def force_stop(self):
        self.server_close()
        self.stopped = True

def client(ip, port, message):
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.connect((ip, port))
    sock.send(message)
    response = sock.recv(1024)
    print "Received: %s" % response
    sock.close()

def start_server(host, port):

    server = ThreadedTCPServer((host, port), ThreadedTCPRequestHandler)
    ip, port = server.server_address

    # Start a thread with the server -- that thread will then start one
    # more thread for each request
    server_thread = threading.Thread(target=server.serve_forever)
    # Exit the server thread when the main thread terminates
    server_thread.setDaemon(True)
    server_thread.start()

    return server
class MyApp(wx.App):
    def OnInit(self):
        frame = MyFrame(None, -1, 'test')
        frame.Show(True)
        server.app = frame
        #Note the server.app
        self.SetTopWindow(frame)
        return True

def main():
    app = MyApp(0)
    app.MainLoop()

if __name__ == '__main__':
    HOST, PORT = socket.gethostname(), 61955

    server = None
    try:
        client(HOST, PORT, ' '.join(sys.argv))
        sys.exit()
    except socket.error:
        server = start_server(HOST, PORT)
        main()

По сути, мне пришлось привязать server.app к моему фрейму:

class MyApp(wx.App):
    def OnInit(self):
        frame = MyFrame(None, -1, 'test')
        frame.Show(True)
        server.app = frame
        #Note the server.app

Чтобы я мог позвонить позже:

data = self.request.recv(1024)
cur_thread = threading.currentThread()

data = data.split()
gfile = os.path.abspath(data[-1])
fopen = open(gfile, 'r')
fread = fopen.read()
self.server.app.static.SetLabel(fread)

Здесь важен self.server.app, хотя я хотел передать команды работающему экземпляру. И data делает это за меня. Скажем, я открываю уже открытое приложение с файлом test.app, тогда значение данных будет:

\pathtoyourapplication\application.py test.app

Так что я взял его местоположение и прочитал, и это в значительной степени из-за моей глупости, надеюсь, что это может быть кому-то полезно в какой-то мере.

person dpswt    schedule 09.04.2011