Thursday, 19 May 2016

Simple data transfer across local network

I wanted to play around with sending an receiving XML data from my laptop to a web server running on the Raspberry Pi. At the moment, I'm happy for all this to happen over my local network.

I decided to use webpy for its ease of development in allowing you to setup a simple server using Python. It can be installed with the following:

sudo easy_install web.py

It's then very simple to write a web server that takes xml passed through a post method and saves it as a file:

import web, urllib

urls = (
 '/index', 'index'
)

class index:
    def GET(self):
        x = web.input()
        return "<b>text=<b>"

    def POST(self):
        # This is the xml string passed from the client
        x = web.data()
       
        # Remove the header "data="
        cleaned = x[5:]
         
        # Write the XML string to file
        filedir = '/home/pi/Scratch/test'
        fout = open(filedir + '/test.xml', 'w')

        # Decode url characters
        fout.write(urllib.unquote_plus(cleaned))
        fout.close()
        return x

if __name__ == "__main__":
    app = web.application(urls, globals())
    app.run()


The client was the Supermarket Planner app. For testing I put the code in the call to print. The first step was to convert the data collection to an XML string.

Because I used an ObservableCollection of SelectedMeal objects, this was simple using an XmlSerialiser:

SelectedMealCollection mealData;
XmlSerializer xs = new XmlSerializer(typeof(SelectedMealCollection));
          
string xml = "";

using (StringWriter writer = new StringWriter())
{
       xs.Serialize(writer, mealData);
       xml = writer.ToString();
}


Finally, I used an async method to create and call an HttpClient with the payload created above.

Note this creates the "data=" part of the payload from the KeyValuePair which needed to be trimmed by the server before using the XML.


private async Task<string> post( string payload )
{        
    using (var client = new HttpClient())
    {
         var postData = new KeyValuePair<string, string>[]
         {
               new KeyValuePair<string, string>("data", payload),
         };

         var content = new FormUrlEncodedContent(postData);
         var response = await client.PostAsync("http://192.168.0.2:8080/index", content);

         if (!response.IsSuccessStatusCode)
         {
              var message = String.Format("Server returned HTTP error {0}: {1}.", (int)response.StatusCode, response.ReasonPhrase);
              throw new InvalidOperationException(message);
         }

         var data = await response.Content.ReadAsStringAsync();
         return data;
    }
}

No comments:

Post a Comment