单实例应用 - 传递命令
我正在使用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"
确实可以发送到正在运行的实例,只是我不知道如何在我的情况下让它工作(因为我实在太无知了)。
2 个回答
一个“单实例”应用程序有两个部分。
一个是“客户端”,你双击它就会开始运行。如果服务器没有启动,它会先启动服务器。然后它会把命令发送给服务器,最后停止运行,但服务器会继续运行。
另一个是“服务器”,每个客户端都会启动它。服务器负责“监听一个特定的端口”。有时候,它也可能通过一个命名管道来读取数据,这样效果会更好。
服务器负责真正的工作,而客户端则是把命令传递给服务器。
这是解决方案:
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()
基本上,我需要把服务器的应用程序和我的框架绑定在一起:
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,那么 data 的值将是:
\pathtoyourapplication\application.py test.app
所以我获取了它的位置并进行了读取,这就是我愚蠢的全部,希望这对某些人有帮助,哪怕是一点点。