程序问答   发布时间:2022-05-31  发布网站:大佬教程  code.js-code.com
大佬教程收集整理的这篇文章主要介绍了使 pynng 和 socket 相互通信大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。

如何解决使 pynng 和 socket 相互通信?

开发过程中遇到使 pynng 和 socket 相互通信的问题如何解决?下面主要结合日常开发的经验,给出你关于使 pynng 和 socket 相互通信的解决方法建议,希望对你解决使 pynng 和 socket 相互通信有所启发或帮助;

TL;DR

我使用 pynng 启动了服务器,然后来自 Python 标准库 socket客户端将尝试向其发送消息。

问题是客户端可以发送消息,但服务器却没有注意到。因此,它不起作用。

我错过了什么吗?一些低级协议设置?一些终止符?

我这样做的原因是我将构建一个使用 pynng 作为服务器的 Python 脚本。然后一个非 Python 程序(我假设它了解基本的 TCP 协议)将尝试与这个 Python 服务器通信。因此,我使用了恕我直言我可以操作的最原始的套接字库,即标准库中的 socket 模块。

详情

我将在讨论时展示代码片段,但我会在最后展示完整的最小代码示例。

我正在尝试使用 pynng

启动服务器
def server():
    with pynng.Pair0(Listen=f'tcp://{HOST:s}:{PORT:D}',recv_timeout=10000) as s:
        print("Server running")
        data = s.recv()  # Blocks forever here
        print(data)

然后,看起来像这样的客户端将尝试连接到它:

def clIEnt():
    with socket.create_connection(address=(HOST,PORT),timeout=5) as s:
        print("ClIEnt connected")
        s.sendall(b'Hello world')
        print("ClIEnt sent message")

我将它们放在一起使用 threading

def main():
    srv = threading.Thread(target=server)
    cli = threading.Thread(target=clIEnt)

    srv.start()
    cli.start()

    srv.join()
    cli.join()

最低工作代码

总而言之,这是最低限度的工作代码:

import socket
import pynng
import threading

HOST = "127.0.0.1"
PORT = 65432

def main():
    srv = threading.Thread(target=server)
    cli = threading.Thread(target=clIEnt)

    srv.start()
    cli.start()

    srv.join()
    cli.join()

def server():
    with pynng.Pair0(Listen=f'tcp://{HOST:s}:{PORT:D}',recv_timeout=10000) as s:
        print("Server running")
        data = s.recv()  # Blocks forever here
        print("message received")
        print(data)

def clIEnt():
    with socket.create_connection(address=(HOST,timeout=5) as s:
        print("ClIEnt connected")
        s.sendall(b'Hello world')
        print("ClIEnt sent message")


if __name__ == "__main__":
    main()

然后我在终端运行这个

$ python main.py

似乎 server 无法recv 发送消息,因此 recv 尝试在 10000 毫秒时超时。

Server running
ClIEnt connected
ClIEnt sent message
Exception in thread Thread-1:
TraceBACk (most recent call last):
  file "/home/kmonisit/miniconda3/envs/engg/lib/python3.8/threading.py",line 932,in _bootstrap_inner
    self.run()
  file "/home/kmonisit/miniconda3/envs/engg/lib/python3.8/threading.py",line 870,in run
    self._target(*self._args,**self._kwargs)
  file "main.py",line 39,in server
    data = s.recv()  # Blocks forever here
  file "/home/kmonisit/miniconda3/envs/engg/lib/python3.8/site-packages/pynng/nng.py",line 454,in recv
    check_err(ret)
  file "/home/kmonisit/miniconda3/envs/engg/lib/python3.8/site-packages/pynng/exceptions.py",line 201,in check_err
    raise exc(String,err)
pynng.exceptions.Timeout: Timed out

解决方法

pynng 基于 Nanomsg Next Generation,它是 Scalability Protocols 的实现。可扩展性协议适用于许多不同的传输,包括 tcp,但裸 sockets 不兼容。但是,通过一点祈祷和肘部润滑脂,它们可以兼容。也就是说,如果需要,您可以在纯 Python 中实现可扩展性协议。

首先,我们需要知道wire格式是什么;谢天谢地,in an RFC in the original nanomsg repository 已记录在案。 Pair0 客户端的实现如下:

class Pair0:
    """A poor implementation of the Pair0 protocol"""

    def __init__(self,host,port,timeout=NonE):
        self._sock = socket.create_connection(address=(host,port),timeout=timeout)
        # https://github.com/nanomsg/nanomsg/blob/master/rfc/sp-tcp-mapping-01.txt
        # upon making a connection,both ends are required to send this header
        self._sock.send(b'\x00SP\x00\x00\x10\x00\x00')
        print(self._sock.recv(8))

    def send(self,data):
        # messages are simply "length + payload".  Length is 64-bit in network byte
        # order.
        packed = struct.pack('!Q',len(data))
        self._sock.sendall(packed + data)

    def recv(self):
        size_bytes = self._sock.recv(8)
        (size,) = struct.unpack('!Q',size_bytes)
        received = 0
        parts = []
        while received < size:
            data = self._sock.recv(size - received)
            received += len(data)
            parts.append(data)
        return b''.join(parts)

并集成到您的测试程序中:

import socket
import struct
import pynng
import threading
import time

HOST = "127.0.0.1"
PORT = 65432


def main():
    srv = threading.Thread(target=server)

    srv.start()
    # sleep to give the server time to bind to the address
    time.sleep(0.1)
    _client = Pair0(HOST,PORT,1)
    _client.send(b'Hello pynng')
    _client.send(b'hope everything is going well for you')
    print(_client.recv())
    print(_client.recv())
    srv.join()


def server():
    with pynng.Pair0(listen=f'tcp://{HOST:s}:{PORT:D}',recv_timeout=1000) as s:
        print("Server running")
        for _ in range(2):
            data = s.recv()
            print("message received")
            print(data)
        s.send(b'Hello bad client')
        s.send(b'I hope you are doing okay')


class Pair0:
    """A poor implementation of the Pair0 protocol"""

    def __init__(self,size_bytes)
        received = 0
        parts = []
        while received < size:
            data = self._sock.recv(size - received)
            received += len(data)
            parts.append(data)
        return b''.join(parts)


if __name__ == "__main__":
    main()

现在,这远不及 pynng 中的实现(它依赖于底层的 nng 实现)那么健壮。 nng 在边缘条件下执行 The Right Thing™,包括丢失网络、处理多个客户端、跟踪状态机、处理 SIGINT 等。这也是一个不完整的实现,因为它没有 bind 等。>

免责声明:我是 pynng 的作者。

大佬总结

以上是大佬教程为你收集整理的使 pynng 和 socket 相互通信全部内容,希望文章能够帮你解决使 pynng 和 socket 相互通信所遇到的程序开发问题。

如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。