![]() |
Welcome to SIMPL Programming for Python
|
| Course content | Enter chat room | Send email
to mailing list |
Check calendar |
Lesson Overview |
In this lesson we are going to examine the detailed workings of a python text-based sending program and a python text-based receiving program.
The sender program is able to send three different types of messages and the receiver program to receive these messages and react appropriately.
With this algorithm we hope to demonstrate the following:
Note:Do NOT cut and paste the following code pieces. The scripts are available in the .../src directory for you to run directly. |
Let's examine the sending script. |
The following code can be found in the ../src/sender_txt.py file. We
will examine the important points by line number.
| 1. """
2. sender_txt.py: This is a python SIMPL text-based sender. 3. Refer to lessons #2 and #3. 4. Usage: python sender_txt.py tokenType 5. """ 6. 7. #! /usr/bin/python 8. 9. # import necessary modules 10. import sys 11. import wcsimpl 12. 13. # initialize necessary variables 14. sName = "SENDER" 15. rName = "RECEIVER" 16. 17. # create an instance of Simpl 18. nee = wcsimpl.Simpl() 19. 20. # enable this script to utilize simpl 21. retVal = nee.nameAttach(sName, 1024) 22. if retVal == -1: 23 print "%s: name attach error-%s" %(sName, nee.whatsMyError()) 24. sys.exit(-1) 25. 26. # name locate the receiver program 27. receiverId = nee.nameLocate(rName) 28. if receiverId == -1: 29. print "%s: name locate error-%s" %(sName, nee.whatsMyError()) 30. sys.exit(-1) 31. 32. # compose the message you wish to send based on the value of the token 33. if sys.argv[1] == "10": 34. print "token = 10" 35. nee.packInt(10, nee.CHR) 36. nee.packInt(99, nee.CHR) 37. nee.packInt(999, nee.CHR) 38. nee.packInt(9999, nee.CHR) 39. elif sys.argv[1] == "20": 40. print "token = 20" 41. nee.packInt(20, nee.CHR) 42. nee.packFloat(3.1415, nee.CHR) 43. elif sys.argv[1] == "30": 44. print "token = 30" 45. s = "We are the knights who say Neee." 46. l = len(s) 47. nee.packInt(30, nee.CHR) 48. nee.packInt(l, nee.CHR) 49. nee.packString(s, nee.CHR) 50. else: 51. print "unknown message type" 52. sys.exit(-1) 53. 54. # send the message 55. retVal = nee.send(receiverId) 56. if retVal == -1: 57. print "%s: send error-%s" %(sName, nee.whatsMyError()) 58. sys.exit(-1) |
| Line 11 | imports the wcsimpl module. This module is responsible for supplying the SIMPL functionality to the Python script. The module name stands for wrapper-csimpl. The wcsimpl module adds a layer to the more fundamental csimpl module that packs and unpacks the contents of the outgoing and incoming messages respectively. This helps to make the construction and deconstruction of messages more convenient. The csimpl module relies directly on the struct module for packing/unpacking messages. |
| Lines 14 and 15 | set the unique SIMPL names for the sender and the receiver programs. These names could be any type of string which is convenient. In this case the names are in uppercase implying that they are constants. |
| Line 18 | creates an instance of Simpl. Like the tkinter module for example, the wcsimpl module API allows the programmer to call the various aspects of wcsimpl via a class instance or as module functions, depending on the application's needs and/or programming tastes. |
| Lines 21-24 | make the necessary nameAttach() call that must precede all other SIMPL calls because nameAttach() is responsible for much of the required initialization required by SIMPL. This program is a SIMPL sender so it attaches the name created for the sender above. The parameter 1024 tells SIMPL that the largest expected incoming or outgoing message will not be larger than 1 kbyte. The call to whatsMyError() returns a string describing the SIMPL error, if encountered. |
| Lines 27-30 | make a SIMPL nameLocate() call that returns the unique SIMPL ID of the receiving program that a message will be sent to. This is required for the SIMPL send() call to follow. |
| Lines 33-52 | compose the message that will be sent to the receiver. Notice that all of the pack() methods contain an argument called CHR. This instructs the pack() software how to organize the data elements within the message. The possibilities are BIN, CHR, and offset. BIN instructs the packing/unpacking routines to write/read message items to/from the message memory with a binary approach to the memory; like a C binary structure. BIN would be used when sending to or receiving from a C program that uses structures as their message definitions. BIN based messages are usually larger in size because they must give deference to memory boundaries. CHR tells the packing/unpacking routines to simply read/write data items byte by byte. CHR is used when BIN is unnecessary. Offset is a positive nondefinite number which forces the pack/unpack routines to place a data item at the specified offset relative to the start of the message memory. |
| Lines 33-38 | take the value of the token passed into the script on the command line as 10. This number serves as a "token" for the message. A token is a unique identifier which allows the receiving program to understand the message data to follow within a received message. In this case, the sender packs three integers, namely 99, 999, and 9999. When the receiver unpacks the message it is understood that the first thing in the message is an integer token which will direct any further unpacking. Hence, in this case a token value of 10 indicates that three more integers are to follow in the message content. |
| Lines 39-42 | take a token value of 20 and build a message containing a floating point number. Note that in C, floats are four byte signed numbers, while in Python all floats are C doubles (eight byte signed numbers). If all of the SIMPL programs are written in one language (Python say) and reside on similar platforms (32-bit say), then less attention needs to be paid in packing/unpacking messages. On the other hand, if the languages/platforms used view data types differently, care must be taken that the appropriate types are used when composing messages in order to preserve the proposed meaning of the message content. |
| Lines 43-49 | use a token value of 30 and create a message containing a string. Notice that the length of the string is also sent as part of the message so that the receiver knows how long the string actually is. |
| Lines 55-58 | perform the actual SIMPL sending of the message to the receiving program. There are no unpack() calls after the send() indicating that there is no expected reply in this case. Often, there is a reply of some sort from the receiver, but for the sake of simplicity in this example, a reply message has been omitted. |
Let's examine the receiving script. |
The following code can be found in the ../src/receiver_txt.py file. We
will examine it line by line.
| 1. """
2. receiver_txt.py: This is a python SIMPL text-based receiver. 3. Refer to lesson #2. 4. Usage:: python receiver_txt.py 5. """ 6. 7. #! /usr/bin/python 8. 9. # import required modules 10. import sys 11. import wcsimpl 12. 13. # set this program's name 14. rName = "RECEIVER" 15. 16. # enable this script to utilize SIMPL 17. retVal = wcsimpl.nameAttach(rName, 1024) 18. if retVal == -1: 19. print "%s: name attach error-%s" %(rName, wcsimpl.whatsMyError()) 20. sys.exit(-1) 21. 22. # receive and process a message 23. while 1: 24. # receive a message 25. messageSize, senderId = wcsimpl.receive() 26. 27. # check for errors 28. if messageSize == -1: 29. print "%s: receive error-%s" %(rName, wcsimpl.whatsMyError()) 30. sys.exit(-1) 31. # is it a non-null message? 32. elif messageSize > 0: 33. # extract the token from the message 34. token = unpackInt(wscsimpl.CHR) 35. 36. # react on token value 37. if token == 10: 38. a = wcsimpl.unpackInt(wcsimpl.CHR) 39. b = wcsimpl.unpackInt(wcsimpl.CHR) 40. c = wcsimpl.unpackInt(wcsimpl.CHR) 41. print "%s: token=%d a=%d b=%d c=%d" %(rName, token, a, b, c) 42. elif token == 20: 43. d = wcsimpl.unpackFloat(wcsimpl.CHR) 44. print "%s: token=%d d=%f" %(rName, token, d) 45. elif token == 30: 46. length = wcsimpl.unpackInt(wcsimpl.CHR) 47. myStr = wcsimpl.unpackString(length, wcsimpl.CHR) 48. print "%s: token=%d str=%s" %(rName, token, myStr) 49. else: 50. print "%s: unknown token type=%d" %(rName, token) 51. 52. # reply to sending program 53. retVal = Reply(senderId, None) 54. if retVal == -1: 55. print "%s: reply error-%s" %(rName, whatsMyError()) 56. sys.exit(-1) |
| Line 11 | imports the wcsimpl module. For the sake of generality, the SIMPL functionality will be called as module functions in the code to follow; that is, in comparison with the sender code above. |
| Line 14 | sets the unique SIMPL name for the receiver programs. |
| Lines 17-20 | make the necessary nameAttach() call that must precede all other SIMPL calls. This program is a SIMPL receiver so it attaches the name created for the receiver above. The 1024 tells SIMPL that the largest expected incoming or outgoing message will not be larger than 1 kbyte. |
| Line 23 | starts an infinite loop wherein messages are received, processed, and replied to indefinitely. |
| Line 25 | performs the actual blocking receive. The receive() call returns the message size in bytes and the SIMPL ID of the sending program which is needed for the reply(). |
| Lines 28-30 | handle the case of an error. Errors are flagged by a return value of -1 from receive() in the returned message size. |
| Line 32 | ascertains that there is indeed a message because the message size is not zero. It is indeed possible to send a message with no content which would then be of zero size. |
| Line 34 | unpacks the token from the incoming message. The token is always present at the beginning of a message. The token which was set by the sending program, provides a unique identifier to the receiving program so that how the message content is to be interpreted and dealt with is clearly understood. |
| Lines 37-50 | handle the message based on the value of the token. In each case, the relevant message structure values are unpacked and printed out to the screen. |
| Lines 60-63 | reply a NULL message to the send blocked sending program. The reply message is NULL for the sake of simplicity, but often there is a reply message to be sent back to the sender. |
Let's run the two scripts. |
In order to run the above programs, sender_txt.py and receiver_txt.py, do the following:
This last command indicates:
You should see the receiver program report the contents of the message
identified by token=10 printed in the first shell window. Repeat
step 7 but using the token numbers 20 and 30. Again, the contents
of these messages should be printed out on the shell window by the receiver
program.
To end the receiver program, simply enter <cntl>-c.
Summary |
Let's summarize what you should have observed in this lesson: