Wiley.Mobile.Python.Rapid.prototyping.of.applications.on.the.mobile.platform.Dec.2007 (779889), страница 32
Текст из файла (страница 32)
By decoding the JSON message, the server-sideapplication ends up with the original list.This process required six steps in total – three on the client side andthree on the server side. In PyS60, however, you can send a request andreceive a response using this protocol stack in two lines of code. Take asneak peek at Example 86 and see the function json request.In some cases, you do not need the full protocol stack.
For example,if you only need to transfer plain strings (note that any files can berepresented as strings or sequences of bytes), HTTP without JSON isenough. If you do not have a web server already in place, JSONencoded strings over TCP, without the HTTP layer, might be a simpleand working solution. A simple solution like this is often agile, flexibleand robust by definition. There is no need to use the latest buzzwordcompliant, enterprise-level, middleware framework, if all you need isa quick prototype for your newest killer application. In the followingsections, you see how the protocols are used in practice.8.3.1TCP ClientWe start with a plain TCP client. If you only have access to a web server,as in environment D above, you can skip this example and proceed toSection 8.3.2.168MOBILE NETWORKINGOn the server side, we use the server in Example 69.
It is almost thesmallest sensible TCP server implementation in Python. Start the serverscript as instructed in Section 8.2.4.The TCP client, which runs on your phone, is in Example 70.Example 70: TCP clientimport socketsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)sock.connect(("192.168.0.2", 9000))out = sock.makefile("rw", 0)print >> out, "Hi! I’m the TCP client"out.close()print "Client ok"The endpoints in a TCP connection are called sockets. Logically, themodule socket includes the required Python interface. First, we createa new socket object: It is initialized with two parameters which specifythe type of the protocol. The parameters used above specify a TCPconnection. You might remember that the socket object was introducedin Chapter 7, where it was needed for RFCOMM communication.The next line opens a connection to the server.
You have to changethe IP address to correspond to your server’s real address – it is thesame one which you used in Section 8.2 to test the connection. If youdo not run the server script in port 9000, change the port number aswell.On the S60 platform, it is possible to define multiple networkingprofiles.
For instance, you can have one profile for a wireless network athome and another for a GPRS connection. Whenever you want to opena network connection, you have to choose the profile through which theconnection is established.By default, a popup menu, like the one in Figure 8.4 is shown automatically by the function socket.connect().
If the dialog does notinclude a desired profile, it has to be configured in the phone’s connectivity settings. In PyS60, it is possible to define the default access point,which prevents this dialog from opening (see Section 8.3.4).Once the execution returns from the connect() function, a newconnection has been established successfully. If connect() raises anexception, this is most often because of a wrong IP address or wrong portor a firewall blocking the connection.
If this happens, you should checkthat your test environment works correctly by following the instructionsin Section 8.2.For convenience, we make the new connection look like a file objectby calling the makefile() function. The parameter ‘rw’ specifies thatwe can both read from and write to the socket. The connection objectCOMMUNICATION PROTOCOLSFigure 8.4169Access point selection dialogout behaves exactly like its counterparts in the RFCOMM examples inChapter 7.
If everything works correctly, you should see ‘Hi! I’m the TCPclient’ printed out on your server.It is important to note that you cannot know how much data the otherside has sent, or is going to send, through the TCP connection. To handlethis situation, there are three alternatives:•Read everything with the read() function without any parameters.Reading continues until the other side closes the connection.•Read a fixed number of characters (bytes) at time, for instance,read(10) would read 10 bytes at most.•Read a character at time until a character denoting the message end,such as the new line character, is received.
The standard readline()function and the read and echo() function in Example 59 use thisapproach.In the previous examples, we have used the readline() approachbecause of its simplicity. Typically a protocol that works on top of TCP,such as HTTP and JSON, will take care of this issue internally.8.3.2HTTP ClientThe modern web is a diverse and complex environment. Even though itis possible, and actually quite easy, to load one web page from somepre-defined site using a plain TCP connection, writing a generic librarywhich would work with any website would be a major effort.170MOBILE NETWORKINGHowever, as we saw in Section 8.1, PyS60 makes interacting with theweb really smooth, thanks to the urllib module that implements anHTTP client in Python.
That section presented many examples based onthe urllib module and many more will follow in Chapter 9.8.3.3 JSON ClientFrom Python’s perspective, the TCP protocol only transfers stringsbetween hosts. The HTTP protocol transfers strings as well, but it includesa simple method to encode key–value pairs, in practice a dictionaryobject, to a request string using the urllib.urlencode() function.Technically speaking, this should suffice for all applications – assumingthat every application finds a way to encode its internal data structures tostrings and back. However, as there is only a small number of basic datastructures, namely strings, numbers, Boolean values, lists and dictionaries,it makes sense to provide a common way to encode them.
This savesyou from the error-prone task of parsing data back and forth. JSON is asolution to this task.JSON is mainly used as a lightweight data interchange format betweenclient-side JavaScript code, which runs inside a web browser, and theweb server. The protocol is textual and pleasantly human-readable. Theencoding represents closely the way simple data structures are initializedin the JavaScript code and also in Python. The official home page forJSON is at http://json.org.Several factors make JSON a nice companion to PyS60:•It is a lightweight, human-readable protocol.•Encoding and decoding can be performed with a single function call.•The data types it supports map well to Python.•You can use it to communicate both with PyS60 and web clients,which simplifies server software.•It is widely supported by many web frameworks, including Django,TurboGears and Ruby on Rails, and by many web services, includingYahoo! and Flickr, as you will see in Chapter 9.The best way to understand JSON is to open the Python interpreteron your PC and see how different encodings look like, for instance asfollows:>> import json>> json.write("hello world")'"hello world"’>> json.write({"fruits": ["apple", "orange"]})'{"fruits": ["apple", "orange"]}’>> json.write((1,2,3))'[1,2,3]’COMMUNICATION PROTOCOLS171>> json.read(json.write([1,2,3]))[1,2,3]To try this on your PC, open the Python interpreter on the samedirectory where json.py, which you downloaded earlier from the bookwebsite, resides.As you can see, JSON encodes the data structures to strings almostexactly as they are written in Python.
Tuples are a notable exception asthey are not recognized by JSON and they are encoded as lists instead.The last line shows that the string encoded by json.write() is decodedback to the original data structure by the function json.read().You can use JSON to save data structures in a file as well. As anexercise, you can replace our ad hoc format for saving dictionaries inChapter 6 with JSON.Next, we have a look at how to use JSON with HTTP. This exampleuses a web service by Yahoo! to retrieve information which is encodedin JSON.
As this example relies on the Yahoo! API, which might havechanged since the book’s publication, you should first check that thisservice is still available and works correctly. The following URL shouldproduce some output on your web browser:http://developer.yahooapis.com/TimeService/V1/getTime?appid=MobilePython&output=jsonIf it does, you can try out Example 71 on your phone.Example 71: Yahoo! web service testimport urllib, json, appuifw, timeURL = "http://developer.yahooapis.com/TimeService/V1/" +\"getTime?appid=MobilePython&output=json"output = json.read(urllib.urlopen(URL).read())print "Yahoo response: ", outputtstamp = int(output["Result"]["Timestamp"])appuifw.note(u"Yahoo says that time is %s" % time.ctime(tstamp))The web service is uninteresting: it just returns the current time. Webservices, such as this one, are accessed through normal urllib functions,in the same way as any other resource on the web.