0

I want to use Unix sockets for 2 Python programs on the same system to talk to each other.

There are examples of binding to a socket file here: https://gist.github.com/jmhobbs/11276249

The often-used socketserver library also has a UnixStreamServer, and a UnixDatagramServer, which sounds like it deals with unix sockets as well, but there are no examples of either one, and as far as I can tell, it requires an IP and Port, rather than a file when initializing either a UnixStreamServer or UnixDatagramServer.

Are UnixDatagramServer and UnixStreamServer a different type of unix sockets that demonstrated here? Or am I just not seeing how to use them to connect to a socket file properly? Are there examples? Why would someone use UnixDatagramServer/UnixStreamServer over binding to a socket file directly, as in my link?

And when talking about IP sockets, the difference between TCP/UDP makes sense - one is reliable, while the other is not, without the overhead. In a world of sockets, where I assume there's no such thing as unreliable communication, why are there still 2 different types (Datagram vs Stream)?

Tal
  • 322
  • 1
  • 7
  • 15

3 Answers3

3

As @GreenCloakGuy pointed out, you may want to use Pipes, but if you're set on using Unix sockets, here's a rough example of using StreamRequestHandler:

Server:

#!/usr/bin/env python3

from socketserver import UnixStreamServer, StreamRequestHandler, ThreadingMixIn
import os

os.unlink("/tmp/test")

class Handler(StreamRequestHandler):
    def handle(self):
        while True:
            msg = self.rfile.readline().strip()
            if msg:
                print("Data Recieved from client is: {}".format(msg))
            else:
                return

class ThreadedUnixStreamServer(ThreadingMixIn, UnixStreamServer):
    pass

with ThreadedUnixStreamServer('/tmp/test', Handler) as server:
    server.serve_forever()

Client:

#!/usr/bin/env python3

import socket
import sys 
import time

with socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) as client:
    client.connect("/tmp/test")

    while True:
        client.send(b"Client 1: hi\n")
        time.sleep(1)

    client.close()

The ThreadingMixIn isn't necessary, but lets you run 2 clients, and receive messages from both of them at the same time. Copy the client code into "client1.py" and "client2.py", and change "Client 1" to "Client 2" in client2.py, running both, to see this in practice.

I'm no expert, but it sounds like while Pipes are more efficient, they have the disadvantage of having only one program linked to one other program. If you have multiple clients, and one server, Unix sockets, as demonstrated here, might be your best bet.

John
  • 2,551
  • 3
  • 30
  • 55
  • How to change permission of the socket /tmp/test to ( 0o700) – sherin Sep 04 '21 at 06:40
  • with statement no need `client.close()` ? – CS QGB Mar 19 '23 at 03:43
  • @CSQGB the fact that you don't need to remember to close a resource is the primary reason to use a `with` statement, and that the `with` statement even exists, so no, you don't need to close if you're using `with`. It will close automatically when you exit the block – John Mar 20 '23 at 13:45
0
#!/usr/bin/env python2
# -*- coding: utf-8 -*-
#kate: syntax Python ;

# use them like so:

import          socket,               os , time
parent, child = socket.socketpair()

#child.close() # bad fdesc

pid           =                       os.fork()
if pid:
    #time.sleep(0.3)
    #child.close()
    print 'in   parent, sending    message'
    p =         parent.sendall('ping p')
    response1 = parent.recv(444)
    print      'response from child         :', response1
    p =         parent.close()

else:
    #time.sleep(0.7)
    #parent.close()

    print  'in child, waiting for message'
    message1 = child.recv(333)
    print  'message from parent         :', message1

    child.sendall('päng c')
    child.close()

#print "Ende" , pid
#print parent # , child
#print type(pid) , " -- " , type(child)
dotbit
  • 4,445
  • 1
  • 7
  • 8
-2

for 2 Python programs on the same system to talk to each other

Don't use sockets. Use pipes.

A socket, in particular, is essentially a link between the Application layer and the Transfer layer, in networking. This is why you need so supply an IP and port number - those are the important addressing information for anyone looking at your computer externally. It's also why you have Datagram vs Stream - TCP and UDP are the two main transport layer protocols, and when building your link to the transport layer you need to specify which protocol you want to use. Sockets are meant for communication using the network - there are alternate, more efficient and easier, ways to communicate between two processes on the same system.

Pipes are more like file descriptors that are used specifically for inter-process communication. There are essentially two ways to use pipes - named pipes and anonymous pipes. If your "two python programs" are splitting off from one original program using something like multiprocessing, then anonymous pipes are what you might want to go with, and you can use os.pipe() to set that up. Otherwise, you'll need to figure out a consistent name and location for your pipe that both programs know, and initialize it on one end with os.mkfifo() then just open it like a regular file on the other end. This functionality seems to only be available on Unix, so if you're on Windows you might have to investigate other solutions.

Green Cloak Guy
  • 23,793
  • 4
  • 33
  • 53
  • I wonder if this will start a war. I suggested something similar when someone was using multiple IPv4 loopback addresses (`127.0.0.0/8`) for inter-process communication, and wanted the same thing for IPv6, which has only one loopback address (`::1`), but I was chastised that the network stack is much faster than other IPC methods. I'm not sure I believe that because it involves too many other processes, both on the way "out" and on the way "in." – Ron Maupin Oct 23 '19 at 14:36
  • @RonMaupin I guess you *can* use the loopback address (and listen on a particular port), but it very much seems like applying the wrong tool for the situation. I haven't done speed tests myself, but I doubt the loopback is overwhelmingly more efficient than the file protocol. Also seems like the kind of thing if you're worrying about it then you wouldn't be asking this question – Green Cloak Guy Oct 23 '19 at 15:07
  • "_it very much seems like applying the wrong tool for the situation._" I agree, but I was strongly told in no uncertain terms that I was wrong. It just seems so inefficient to assign individual loopback addresses to processes, then use the network stack for communication. The person asking the question would have had to re-architect the whole thing to make it work with IPv6, and he wasn't the one who got on me for suggesting that it was done incorrectly in the first place. – Ron Maupin Oct 23 '19 at 15:10
  • In the github gist link above, the example is clearly using a file, rather than an IP/PORT, and is using the socket module to set that up, implying a socket, and not a pipe, is in use. Your answer seems to suggest that sockets always use the network Transfer layer, which the example doesn't. Something doesn't sound right. Does the gist actually use pipes, rather than sockets (coming from an unfortunately-named module)? Why are there unix socket files if sockets always use the networking stack? – John Oct 23 '19 at 15:41
  • @John I haven't done the necessary reading, but I would assume that unix sockets are represented as files so that programs can interact with them using file I/O protocols from the application layer. Which is the same with pipes, in fact. – Green Cloak Guy Oct 23 '19 at 15:59
  • @GreenCloakGuy your answer starts out with `Don't use sockets. Use pipes.`, and your argument to back that up is that sockets always use the network stack, whereas pipes don't. The Gist is clearly an example of unix sockets that are NOT using the network stack, but using files, which seems to undermine your argument. I don't mean to criticize - only to understand. Am I missing something? It sounds like unix sockets are just as efficient as Pipes in that regard if they both use files. – John Oct 23 '19 at 16:27
  • @John what's your argument for the sockets not using the network stack? They *are* - when the gist sends information with `client.send()`, it's going through the transport layer, encoded in the proper datagram format and whatnot. Probably also the top of the network layer before it's realized that it's supposed to loop back. The server receives through the socket using the same transport-layer protocol. The abstraction is in place for the benefit of the programmer, not because the same thing is actually going on beneath the hood. – Green Cloak Guy Oct 23 '19 at 16:46
  • It's not that they actually *use* files, it's that you *access them through file descriptors*, which is not the same thing. – Green Cloak Guy Oct 23 '19 at 16:46
  • @GreenCloakGuy ok - I follow. Makes sense. Thanks – John Oct 23 '19 at 17:10
  • The `DGRAM` in `SOCK_DGRAM` ensures that you receive datagrams of data without having to keep track of the underlying stream and byte-lengths. Pipes do not do that, and, as such, they are not interchangeable. – Błażej Michalik Oct 20 '22 at 13:36