This article shows how to communicate between Python and Dyalog APL through the use of sockets. We will use the module socket
from Python and the Conga workspace from Dyalog.
Programs communicate with each other all the time. For example, your browser communicated with my server to retrieve this article. Sometimes, you may want your programs to communicate with others, and when that time comes, you may want to use sockets1.
This article will show how to communicate between Python and Dyalog APL using sockets:
sockets
on the Python side; andBoth sockets
for Python and Conga for Dyalog APL come with their respective systems by default, so that should make things easier for us.
Thanks to some investigation I did some months ago and an article I wrote about sockets
, we can see that it doesn't take much code to create a socket server in Python.
In fact, the four lines of code that follow are enough to create a socket server in Python that will listen on port 7342 on the local host:
import socket
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(("localhost", 7342))
server.listen()
If you are following along, what I suggest is that you run this code in your REPL, so that the Dyalog APL socket you create in the next step connects to your server and you see what is going on.
Go ahead, paste those four lines of code in your REPL, and then add this fifth one to wait for a socket to connect:
client, address = server.accept()
If all went well, running that line of code should make your interpreter hang, which is normal because you are waiting for a socket to connect to your server.
Let's see how to connect from the APL side
To work with sockets in Dyalog APL we need to load the Conga workspace, or we can just copy the namespace DRC
in:
)copy conga DRC
Next up, we initialise the namespace:
DRC.Init ''
βββ¬ββββββββββββββββββββββββββββββ
β0βConga loaded from: conga34_64β
βββ΄ββββββββββββββββββββββββββββββ
The exact numbers you get in the conga34_64
portion of the output will differ from version to version (and possibly from OS to OS).
Finally, we use the function DRC.Clt
to create a client socket.
We will pass four arguments to DRC.Clt
:
'localhost'
in our example);7342
in our example); and'Text'
in our example): DRC.Clt 'my socket' 'localhost' 7342 'Text'
βββ¬ββββββββββ
β0βmy socketβ
βββ΄ββββββββββ
If the first element of the result vector is a 0
, that means everything worked out and you managed to create your socket.
Otherwise, that integer will have an error code that you can use to identify what went wrong.
When the client socket connects to the Python server, the statement client, address = server.accept()
will no longer be hanging and you will be back in control of your Python REPL.
This means that client
is now the client socket that can communicate with Dyalog APL.
Now that we have a connection between Dyalog and APL, we can use the function DRC.Send
on the Dyalog side to send messages to Python.
The function DRC.Send
will take two arguments, which are the name of the socket that should send the message and the message itself.
Because our socket 'my socket'
is of the type 'Text'
, we can send character vectors without having to encode them:
β From the APL side:
DRC.Send 'my socket' 'Hello, Python, from the Dyalog side.'
βββ¬βββββββββββββββββββββββ
β0βmy socket.Auto00000000β
βββ΄βββββββββββββββββββββββ
Again, if the first integer of the result is a 0
, that means sending worked out great.
Now, if we head over to the Python side, we can receive that message:
# From the Python side:
>>> client.recv(1024)
b'Hello, Python, from the Dyalog side.'
Receiving a message in Dyalog APL is also simple.
The function DRC.Wait
accepts a name of a socket and will attempt to wait for a message from that socket.
However, if you run DRC.Wait 'my socket'
you will get a timeout almost instantly:
β From the APL side:
DRC.Wait 'my socket'
βββββ¬ββββββββ¬ββββββββ
β100βTIMEOUTβTimeoutβ
βββββ΄ββββββββ΄ββββββββ
By default, the function DRC.Wait
will wait for a message for 100ms and will return with an error code 100
if that times out.
You can increase the timeout limit by providing the number of milliseconds as the second argument:
DRC.Wait 'my socket' 999999
This should give you plenty of time to go to the Python REPL and send a message through there:
# From the Python side:
>>> client.send(b"Hello Dyalog, from the Python side.")
35
When you go back to the Dyalog APL session, you should have received your message:
β From the APL side:
DRC.Wait 'my socket' 999999
βββ¬ββββββββββ¬ββββββ¬ββββββββββββββββββββββββββββββββββββ
β0βmy socketβBlockβHello Dyalog, from the Python side.β
βββ΄ββββββββββ΄ββββββ΄ββββββββββββββββββββββββββββββββββββ
Again, the code 0
means everything worked great.
The remaining three values are:
Before we conclude this article, let us see how we could establish a similar connection but with the socket server on the Dyalog APL side.
We assume that the namespace DRC
has been loaded and Conga was initialised as shown in the section about creating a client socket in Dyalog APL.
First, we need to use the function DRC.Srv
to create a server:
server_name β 'my server'
address β '' β empty for localhost
port β 7373 β DIFFERENT port
type β 'Text'
DRC.Srv server_name address port type
βββ¬ββββββββββ
β0βmy serverβ
βββ΄ββββββββββ
Next, we wait for a socket to connect:
rc obj event data β DRC.Wait 'my server' 999999
β Should hang for a bit.
Now, we go to the Python side to create a socket and to connect it to the server:
>>> client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
>>> client.connect(("localhost", 7373))
>>> client.send(b"Hello Dyalog, from the Python side.")
35
Finally, if we go back to the Dyalog APL side, we can see that the Python socket was connected to the server and created a new socket with an automatic name:
rc obj event data β DRC.Wait 'my server' 999999
rc obj event data
βββ¬ββββββββββββββββββββββ¬ββββββββ¬ββ
β0βmy server.CON00000003βConnectβ0β
βββ΄ββββββββββββββββββββββ΄ββββββββ΄ββ
In this example, the socket name ends with 3
because of some failed attempts I made when writing this article!
Now, if we want to receive the message that we sent from the Python side, we need to call DRC.Wait
on the new socket object:
DRC.Wait obj
βββ¬ββββββββββββββββββββββ¬ββββββ¬ββββββββββββββββββββββββββββββββββββ
β0βmy server.CON00000003βBlockβHello Dyalog, from the Python side.β
βββ΄ββββββββββββββββββββββ΄ββββββ΄ββββββββββββββββββββββββββββββββββββ
That's it for this article! I hope you enjoyed it and feel free to share your thoughts in the comment section below or on social media.
I am not a networking expert and I am not qualified enough to say whether or not you should use sockets or anything else. I just know sockets work and, at the end of the day, I just need to get the job done.Β β©
+35 chapters. +400 pages. Hundreds of examples. Over 30,000 readers!
My book βPydon'tsβ teaches you how to write elegant, expressive, and Pythonic code, to help you become a better developer. >>> Download it here ππ.