wxpython 服务器

1 投票
1 回答
793 浏览
提问于 2025-04-17 17:23

我正在尝试通过套接字将数据从一个C程序发送到一个Python脚本,以便使用matplotlib进行实时数据可视化。我还使用wxPython创建了一个图形用户界面(GUI)。

我使用了socket模块、SocketServer模块和twisted。在每个模块中,我都遇到了不同的问题。

使用socket模块时,我收到了多个消息合并在一起的情况。我尝试减少recv()函数的缓冲区大小,但结果只收到了一个数据包,之后就没有了。

然后我开始使用twisted,但我仍然收到了打包在一起的数据,而不是一个一个地接收。此外,当我在C文件中插入延迟时,我的Python脚本崩溃了。

接着我转向了SocketServer,并创建了一个线程来运行服务器。消息按我想要的方式发送过来了,但我就无法再与GUI进行交互了。

我想做的就是将四个值的字符串发送到Python脚本,处理这些数据并绘制图形,同时保持一个互动的用户界面,但我找不到关于服务器、matplotlib和wxPython协作的示例。

这是我找到并正在使用的C代码:

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <string.h>
#include <unistd.h>
#define PORT        9992
#define HOST        "localhost"
#define DIRSIZE     8192

main(argc, argv)
int argc; char **argv;
{
char hostname[100];
char dir[DIRSIZE];
int sd;
struct sockaddr_in sin;
struct sockaddr_in pin;
struct hostent *hp;
char message[50];
int i = 0;
int count = 50;

strcpy(hostname,HOST);
if (argc>2)
{ strcpy(hostname,argv[2]); }

/* go find out about the desired host machine */
if ((hp = gethostbyname(hostname)) == 0) {
    perror("gethostbyname");
    exit(1);
}

/* fill in the socket structure with host information */
memset(&pin, 0, sizeof(pin));
pin.sin_family = AF_INET;
pin.sin_addr.s_addr = ((struct in_addr *)(hp->h_addr))->s_addr;
pin.sin_port = htons(PORT);

/* grab an Internet domain socket */
if ((sd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
    perror("socket");
    exit(1);
}

/* connect to PORT on HOST */
if (connect(sd,(struct sockaddr *)  &pin, sizeof(pin)) == -1) {
    perror("connect");
    exit(1);
}

/* send a message to the server PORT on machine HOST */
while (i < 100){
    sprintf(message, "%d %d %d %d \n", count, count + 50, count + 100, count + 130);
    if (send(sd, message, strlen(message), 0) == -1) {
        perror("send");
        exit(1);
    }
    count = count + 50;
    i++;
    sleep(1);
}


shutdown (sd, 2);
}

这是我目前拥有的Python代码(在网上搜索了很久):

class ThreadedEchoRequestHandler(SocketServer.StreamRequestHandler):

def handle(self):
    cur_thread = threading.currentThread()
    line = self.rfile.readline()
    while True:
        line = self.rfile.readline()
        if not line: break
        print "%s wrote: %s" % (self.client_address[0], line.rstrip())
        self.wfile.write(line)
    return 

class ThreadedEchoServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
    pass
########################################################################################
class MyFrame(wx.Frame):
def __init__(self, parent, title):
    wx.Frame.__init__(self, parent, -1, title, size=(1024,768))

    self.SetIcon(wx.Icon('sim.ico', wx.BITMAP_TYPE_ICO))
    self.SetBackgroundColour('#ece9d8')

    self.add_toolbar()
    self.Centre()

    #Flag variables
    self.isLogging = False
    self.threads = []
    server = ThreadedEchoServer(('localhost',9997), ThreadedEchoRequestHandler)
    t = threading.Thread(target=server.serve_forever)
    t.start()

    #Create data buffers

    #Some GUI Design Code

    #Create timer to read incoming data and scroll plot

    #Create start/stop button
    self.start_stop_button = wx.Button(self, label="Start", pos=(80,550), size=(150,150))
    self.start_stop_button.SetFont(wx.Font(14, wx.DEFAULT, wx.NORMAL, wx.NORMAL, False))
    self.start_stop_button.Bind(wx.EVT_BUTTON, self.onStartStopButton)

def add_toolbar(self):
    # Toolbar code

def onStartStopButton(self, event):
    if not self.isLogging:
        self.isLogging = True
        self.start_stop_button.SetLabel("Stop")
        call(["/home/user/Misc/socketTest/socketTest"])   
    else:
        self.isLogging = False
        self.start_stop_button.SetLabel("Start")                

def GetSample(self, msg):
### Manipulate Data from socket for matplotlib update

if __name__ == '__main__':
     app =wx.App(False)
     frame = MyFrame(None, 'Sim')
     frame.Show(True)
     app.MainLoop()

抱歉,我对Python还很陌生。提前谢谢你。

1 个回答

0

我不能说socket通信的最佳方法是什么,这真的要看你的应用需求、传输的数据类型和格式、数据量等等。不过,我可以帮你理解如何把这些东西和图形用户界面(GUI)应用结合起来。

在给GUI应用添加socket服务时,有几个关键原则需要注意。首先,为了让用户界面保持响应,尽量不要在用户界面事件处理程序或其他回调中做可能会让用户感觉到延迟的事情。其次,除了用户界面线程外,尽量不要在其他线程中创建或操作任何GUI元素。

所以,你的直觉是对的,应该在另一个线程中运行SocketServer(或者你最终使用的其他东西)。这样可以让这个线程专心处理通信,而不需要处理更复杂的事情,比如定期检查、等待用户界面事件处理等等。它可以直接等待接收数据。

有几种方法可以把从socket接收到的数据传递到用户界面线程。最简单的方法可能是使用wxPython的wx.CallAfter函数。这个函数允许你指定一个可调用的对象(也就是可以执行的函数),以及要传递给它的参数,然后它会在用户界面线程的上下文中稍后调用这个函数。

撰写回答