1

I am trying to send data from a C program to a python script through sockets in order to perform real-time visualization of the data using matplotlib. I have also created a GUI using wxPython. I have used socket module, SocketServer module and twisted. In each one I had different problems.

Using socket module I was getting more than one messages combined. I reduced the buffer size of the recv() function but I was then getting only one package and after that nothing.

Then I started using twisted. I was still getting the packages as a collection and not one by one. Moreover when a delay was inserted in C file my python script crashed.

Then i moved to SocketServer and I created a thread to run the server on. The messages were coming as I wanted to but I can no longer interact with the GUI.

All I want to do is send a string of 4 values to the Python script, strip it and the plot it, having an interactive UI and I can't find an example of server,matplotlib and wxPython collaboration.

This is the C code that I found and I am using:

#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);
}

And this is the Python code that i currently have (after searching all over the net):

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()

Sorry but I am new to Python. Thank you in advance.

  • This is a very complicated problem, is there anyway you can break it down in to smaller, easier to understand/address chunks? – tacaswell Feb 28 '13 at 16:20
  • I can't understand what do you mean. I think that my server is on a different thread so the gui shouldn't be affected. But it does. Sorry but I am not familiar with Python. – user2117698 Feb 28 '13 at 21:43
  • If you think this is primarily a threading/wx issue then strip out all the `matplotilb` code so it is easier to see what is going on. You will get more and better answers with a question that includes _only_ the code that is relevant to reproducing your problem. – tacaswell Feb 28 '13 at 21:59
  • or, we don't need to see all the details of your UI design, the less working code people have to shift through to find the problem the better. Help us to help you;) – tacaswell Feb 28 '13 at 22:01
  • Thank you, I added comments for the parts of the code that have no real impact in the problem... – user2117698 Feb 28 '13 at 23:16

1 Answers1

0

I can't say what the best approach to socket communications is, it really depends on the needs of your application, the type and format of the data being transfered, the volume, etc. But I can help with the integration with the GUI application.

There are a few key principles to be aware of when adding things like socket services to a GUI application. First, in order to keep the UI responsive to the user you should not do anything in UI event handlers or other callbacks that could block for a "user noticeable" amount of time. Second, you should not do anything that creates or manipulates any GUI elements from a thread other than the UI thread.

So your instinct to run the SocketServer (or whatever you end up using) from another thread is a good one. That lets you give the thread's full attention to handling the communication and not have to deal with more complex things like periodic polling, yielding for UI event processing, etc. It can just block waiting for incoming data.

There are a few methods that can be used to communicate the incoming data from the socket to the UI thread. Probably the easiest is to use wxPython's wx.CallAfter function. It allows you to specify some callable object that should be called, and the parameters to be passed to it, and then it will cause that call to happen shortly thereafter in the context of the UI thread.

RobinDunn
  • 6,116
  • 1
  • 15
  • 14
  • Yes, but the problem is that my GUI blocks although I run my server in a different thread. I can't interact with the GUI and my server keeps running in the background... – user2117698 Feb 28 '13 at 23:20
  • Is the server thread CPU-bound? That could cause the UI thread to get starved for cycles. If you make a small runnable sample that demonstrates the problem it will be easier to help. If you post it to the wxPython-users list then you will probably get lots of help. http://wiki.wxpython.org/MakingSampleApps – RobinDunn Mar 02 '13 at 00:56