你如何在 Python 中使用 Unix 套接字?

Posted

技术标签:

【中文标题】你如何在 Python 中使用 Unix 套接字?【英文标题】:How do you use Unix sockets in Python? 【发布时间】:2019-10-23 12:40:32 【问题描述】:

我想为同一系统上的 2 个 Python 程序使用 Unix 套接字来相互通信。

这里有绑定到套接字文件的示例:https://gist.github.com/jmhobbs/11276249

常用的 socketserver 库也有一个 UnixStreamServer 和一个 UnixDatagramServer,听起来它也处理 unix 套接字,但是没有任何一个例子,据我所知,它需要一个 IP和端口,而不是初始化 UnixStreamServer 或 UnixDatagramServer 时的文件。

UnixDatagramServer 和 UnixStreamServer 是不是演示 here 的不同类型的 unix 套接字?或者我只是没有看到如何使用它们正确连接到套接字文件?有例子吗?为什么有人会使用 UnixDatagramServer/UnixStreamServer 而不是直接绑定到套接字文件,如我的链接中所示?

当谈到 IP 套接字时,TCP/UDP 之间的区别是有道理的 - 一个是可靠的,而另一个是不可靠的,没有开销。在套接字的世界中,我认为不存在不可靠通信之类的东西,为什么仍然有 2 种不同的类型(数据报 vs 流)?

【问题讨论】:

【参考方案1】:

正如@GreenCloakGuy 指出的那样,您可能想要使用管道,但如果您打算使用 Unix 套接字,这里有一个使用 StreamRequestHandler 的粗略示例:

服务器:

#!/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()

客户:

#!/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()

ThreadingMixIn 不是必需的,但可以让您运行 2 个客户端,并同时接收来自这两个客户端的消息。将客户端代码复制到“client1.py”和“client2.py”中,并将client2.py中的“Client 1”更改为“Client 2”,同时运行,看实际效果。

我不是专家,但听起来虽然 Pipes 更高效,但它们的缺点是只有一个程序链接到另一个程序。如果您有多个客户端和一台服务器,那么此处演示的 Unix 套接字可能是您的最佳选择。

【讨论】:

如何将socket /tmp/test的权限改为(0o700)【参考方案2】:
#!/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)

【讨论】:

【参考方案3】:

让同一系统上的 2 个 Python 程序相互通信

不要使用套接字。使用管道。

特别是套接字,它本质上是网络中应用层和传输层之间的链接。这就是为什么您需要提供 IP 和端口号的原因——对于任何从外部查看您的计算机的人来说,这些都是重要的地址信息。这也是为什么您有数据报与流的原因 - TCP 和 UDP 是两个主要的传输层协议,在构建到传输层的链接时,您需要指定要使用的协议。套接字用于使用网络进行通信 - 在同一系统上的两个进程之间存在替代的、更有效和更容易的通信方式。

管道更像是专门用于进程间通信的文件描述符。基本上有两种使用管道的方法——命名管道和匿名管道。如果您的“两个 python 程序”使用 multiprocessing 之类的东西从一个原始程序中分离出来,那么您可能想要使用匿名管道,您可以使用 os.pipe() 进行设置。否则,您需要找出两个程序都知道的管道的一致名称和位置,并在一端使用os.mkfifo() 对其进行初始化,然后在另一端像常规文件一样打开它。这个功能似乎只在 Unix 上可用,所以如果你在 Windows 上,你可能需要investigate other solutions。

【讨论】:

不知道这会不会引发一场战争。当有人使用多个 IPv4 环回地址 (127.0.0.0/8) 进行进程间通信时,我提出了类似的建议,并且对只有一个环回地址 (::1) 的 IPv6 也想要同样的东西,但我被责备网络stack 比其他 IPC 方法快得多。我不确定我是否相信,因为它涉及太多其他过程,无论是在“退出”的路上还是在“进入”的路上。 @RonMaupin 我猜你可以使用环回地址(并在特定端口上侦听),但这很像是针对这种情况应用了错误的工具。我自己没有做过速度测试,但我怀疑环回比文件协议更有效。如果您担心它,那似乎也像是那种事情,那么您就不会问这个问题 这似乎是针对这种情况使用了错误的工具。”我同意,但我被明确告知我错了。将单个环回地址分配给进程,然后使用网络堆栈进行通信似乎效率很低。提出这个问题的人必须重新设计整个东西才能使其与 IPv6 一起使用,而且他并不是因为一开始就建议它做得不正确而责怪我的人。 在上面的 github gist 链接中,该示例显然使用了文件,而不是 IP/PORT,并且正在使用 socket 模块来设置它,这意味着一个套接字,而不是一个管道,正在使用中。您的回答似乎表明套接字始终使用网络传输层,而示例没有。听起来有些不对劲。要点是否真的使用管道,而不是套接字(来自一个不幸命名的模块)?如果套接字总是使用网络堆栈,为什么会有 unix 套接字文件? @John 我还没有完成必要的阅读,但我假设 unix 套接字表示为文件,以便程序可以使用来自应用程序层的文件 I/O 协议与它们交互。事实上,管道也是如此。

以上是关于你如何在 Python 中使用 Unix 套接字?的主要内容,如果未能解决你的问题,请参考以下文章

可以在Unix域套接字上使用SO_REUSEPORT吗?

将 Python xmlrpclib 与 unix 域套接字一起使用?

如何使用 akka 连接到 Unix 套接字?

使用 ssh 转发 unix 数据报套接字?

在 Python 中为 dovecot 创建一个基于 Unix 套接字的身份验证服务器

来回 unix 域套接字锁