【问题标题】:How do you use Unix sockets in Python?你如何在 Python 中使用 Unix 套接字?
【发布时间】: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 流)?

【问题讨论】:

    标签: python python-3.x networking


    【解决方案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 协议与它们交互。事实上,管道也是如此。
      猜你喜欢
      • 2019-02-01
      • 2010-12-11
      • 2021-08-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-10-14
      • 1970-01-01
      相关资源
      最近更新 更多