![]() |
Welcome to SIMPL Programming for Python
|
| Course content | Enter chat room | Send email
to mailing list |
Check calendar |
Lesson Overview |
In this lesson we want to think about how we would transport messages between a python gui-based sending program running on a Windows host and a C coded receiving program running on a Linux host.
We have purposefully chosen a situation where Windows/Linux communications are necessary. The situation could be Linux/Linux or Linux/MAC OS X or Windows/MAC OS X or Unix/Linux etc. The Windows/Linux scenario has occurred in a real-world project we were involved in. We believe that it is important to be able SIMPL communicate with programs running on a Windows platform due to the shear number of Windows hosts in existence. It would be a shame if a project specified that the user interface resides on a Windows host and there was no easy way to interface this requirement to the rest of the system.
SIMPL communications between Windows and Linux hosts is accomplished with the aid of the tclSurrogate. This program is named this way because its original purpose was to allow a Tcl-based program running on a Windows host to SIMPL communicate through a network with any SIMPL program on a Linux host.
In this lesson we are going to use the tclSurrogate to allow a python program to SIMPL communicate with a C program; this is exactly the same situation as in Lesson #4. This requires the use of a new module called pysimpl.
We recommend that you read the documents called readme.tcl and readme.python which are located in the docs directory below the SIMPL root directory. These docs contain many details regarding the tclSurrogate program and the pysimpl python module.
It must be made clear at this point however, SIMPL communications between networked hosts is normally accomplished with the aid of the TCP/IP or RS-232 surrogates. For example, in most cases SIMPL communications between two Linux hosts would be via TCP/IP surrogates. The tclSurrogate is normally used for Tcl or Python programs only running on Windows. For more information on the other surrogates see readme.surrogateTCP also in the docs directory.
As in Lesson #4, the sender program is able to send three different types of messages and the receiver program to receive these messages and react appropriately.
Note:For the purposes of this lesson, we are going to run all of our programs on one Linux host. We will replace the network aspect of our real world example by routing our SIMPL communications through the TCP/IP loopback interface. |
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/senderw_gui.py file. We
will examine it line by line.
| 1. """
2. senderw_gui.py: This is a python simpl gui-based sender. 3. Refer to lesson #6. 4. Usage: python senderw_gui.py 5. """ 6. 7. #! /usr/bin/python 8. 9. # import necessary modules 10. import sys 11. import wssimpl 12. from Tkinter import * 13. 14. nee = None 15. 16. # define the callback for button 1 17. def hndlButton1(event): 18. token = 10 19. nee.packInt(token, nee.BIN) 20. a = 99 21. nee.packInt(a, nee.BIN) 22. b = 999 23. nee.packInt(b, nee.BIN) 24. c = 9999 25. nee.packInt(c, nee.BIN) 26. makeSend() 27. 28. # define the callback for button 2 29. def hndlButton2(event): 30. token = 20 31. nee.packInt(token, nee.BIN) 32. d = 3.1415 33. nee.packFloat(d, nee.BIN) 34. makeSend() 35. 36. # define the callback for button 3 37. def hndlButton3(event): 38. token = 30 39. nee.packInt(token, nee.BIN) 40. s = "We are the knights who say Neee." 41. l = len(s) 42. nee.packInt(l, nee.BIN) 43. nee.packString(s, nee.BIN) 44. makeSend() 45. 46. # define the call for the simpl send 47. def makeSend(): 48. retVal = nee.send(receiverId) 49. if retVal == -1: 50. print "%s: send error-%s" %(sName, nee.whatsMyError()) 51. sys.exit(-1) 52. 53. # define the exit call 54. def die(event): 55. sys.exit(0) 56. 57. # initialize some required variables 58. sName = "50000:localhost:SENDER" 59. rName = "RECEIVER" 60. 61. # create an instance of Simpl 62. nee = wssimpl.Simpl() 63. 64. # attach a simpl name 65. retVal = nee.nameAttach(sName, 1024) 66. if retVal == -1: 67. print "%s: name attach error-%s" %(sName, nee.whatsMyError()) 68. sys.exit(-1) 69. 70. # name locate the receiver 71. receiverId = nee.nameLocate(rName) 72. if receiverId == -1: 73. print "%s: name locate error-%s" %(sName, nee.whatsMyError()) 74. sys.exit(-1) 75. 76. # initialize Tk for graphics 77. root = Tk() 78. 79. # set up a button to initiate the sending of message token type 10 80. button = Button(root) 81. button["text"] = "send message token type 10" 82. button.bind(" 83. button.pack() 84. 85. # set up a button to initiate the sending of message token type 20 86. button = Button(root) 87. button["text"] = "send message token type 20" 88. button.bind(" 89. button.pack() 90. 91. # set up a button to initiate the sending of message token type 30 92. button = Button(root) 93. button["text"] = "send message token type 30" 94. button.bind(" 95. button.pack() 96. 97. # set up a button for program exit 98. button = Button(root) 99. button["text"] = "Exit" 100. button.bind(" 101. button.pack() 102. 103. # handle user input 104. root.mainloop() |
| Lines 10-12 | import required modules. Note that we are using the wssimpl module because we need the tclSurrogate as our network surrogate. |
| Lines 17-55 |
define the various callback functions etc.
Notice that the various message components are set here, the binary messages are constructed and then the message is sent. We use binary type messages because we are sending to a C program which works well well with that type. |
| Line 48 | is where the actual SIMPL send operation is called. |
| Line 58 | sets the SIMPL name for this program. Note the format of the name, 50000:localhost:SENDER. The "50000" refers to the port number where TCP/IP sockets are bound to. We have chosen port 50000 because it should be out of the range of any port numbers usually claimed by other programs. The "localhost" refers to the host machine where the receiver program is running which is the the same as this program; normally this would not be the case. "SENDER" is our SIMPL name for this program. |
| Line 59 | sets the SIMPL name for the receiver program. |
| Line 62 | creates an instance of Simpl with the global name "nee". |
| Lines 65-68 | perform the SIMPL name attach. |
| Lines 72-74 | perform the SIMPL name locate. |
| Lines 77-101 | create the various graphical bits required by the program. When any of the available GUI buttons are selected, a particular tokenized message is created and then sent to the SIMPL receiver program. |
| Line 104 | creates an infinite event loop on the root window that awaits incoming events (in this case mouse clicks on the various buttons). |
Let's examine the receiving program. Note: this is exactly the same receiving program used in Lessons #3 and #4. |
| 1. /*
2. FILE: receiver.c 3. DESCRIPTION: This is a C simpl receiver. 4. Refer to lessons 3, 4, 6, 7. 5. USAGE: receiver 6. */ 7. 8. // include required headers 9. #include <stdio.h> 10. #include <stdlib.h> 11. #include <simpl.h> 12. 13. // define possible message structures 14. typedef struct 15. { 16. int token; 17. int var1; 18. int var2; 19. int var3; 20. } MSG1; 21. 22. typedef struct 23. { 24. int token; 25. float var1; 26. } MSG2; 27. 28. typedef struct 29. { 30. int token; 31. int var1; 32. char var2[34]; 33. } MSG3; 34. 35. int main() 36. { 37. char *me = "RECEIVER"; 38. char *sender; 39. char mem[1024]; 40. int n; 41. MSG1 *in1; 42. MSG2 *in2; 43. MSG3 *in3; 44. int *token; 45. 46. // perform simpl name attach 47. if (name_attach(me, NULL) == -1) 48. { 49. printf("%s: cannot attach name-%s\n", me whatsMyError()); 50. exit(-1); 51. } 52. 53. while (1) 54. { 55. // receive incoming messages 56. n = Receive(&sender, mem, 1024); 57. if (n == -1) 58. { 59. printf("%s: Receive error-%s\n", me, whatsMyError()); 60. continue; 61. } 62. 63. // set a pointer to the value of the message token 64. token = (int *)mem; 65. 66. // decide course of action based on the value of the token 67. switch (*token) 68. { 69. case 10: 70. in1 = (MSG1 *)mem; 71. Printf("token=%d var1=%d var2=%d var3=%d\n", 72. & nbsp; in1->token, 73. & nbsp; in1->var1, 74. & nbsp; in1->var2, 75. & nbsp; in1->var3); 76. break; 77. 78. case 20: 79. in2 = (MSG2 *)mem; 80. printf("token=%d var1=%d\n", 81. & nbsp; in2->token, 82. & nbsp; in2->var1); 83. break; 84. 85. case 30: 86. in3 = (MSG3 *)mem; 87. printf("token=%d var1=%d var2=%.*s\n", 88. in3->token, 89. & nbsp; in3->var1, 90. & nbsp; in3->var1, 91. & nbsp; in3->var2); 92. break; 93. 94. default: 95. printf("%s: unknown message token=%d\n", me. token); 96. } 97. 98. // reply to sender 99. Reply(sender, NULL, 0); 100. } 101. 102. return(0); 103. } |
| Lines 9-11 | include the required C header files. Note the inclusion of the simpl.h header file. |
|
Lines 14-20 | define the binary message that corresponds to token value 10. |
|
Lines 22-26 | define the binary message that corresponds to token value 20. |
|
Lines 28-33 | define the binary message that corresponds to token value 30. |
|
Line 35 | is the start of the program. |
|
Lines 37-44 | declare necessary local variables. |
|
Lines 47-51 | handle the simpl name attach. |
|
Line 53 | starts an infinite loop which awaits incoming messages. |
|
Lines 56-61 | receive the incoming messages. |
|
Line 64 | sets a pointer to the incoming message token. |
|
Lines 67-96 | deal with each message type based on the token by printing the various message components to the screen. |
| Line 99 | replies a null message to the blocked sender. This reply message could be anything at all but in the interests of simplicity, the reply message has been made null. |
The Makefile for the C receiver program. |
The receiver program must be compiled and linked before it can be of any use. Go to ../src and at the command prompt type:
make cleanThen type:
make installThis makes a new executable of receiver.c called receiver and puts it in ../bin .
Note:In order to run this Makefile, the shell variable SIMPL_HOME must be set so that the make can find the SIMPL header files and library. |
Let's run the required three programs. |
In order to run the senderw_gui.py script, C receiver program, and the tclSurrogate program do the following:
You should see the receiver program print the contents of each message
as you choose the various message buttons displayed by the sender gui.
Summary |
Let's summarize what you should have observed in this lesson: