【问题标题】:Python and Kotlin applications socket sync issuePython 和 Kotlin 应用程序套接字同步问题
【发布时间】:2021-09-14 18:05:57
【问题描述】:

我正在 Kotlin 上编写一个使用 Python 后端服务器的应用程序,我似乎在将它们连接在一起时遇到了一些麻烦。

我在 python 上使用

from socket import socket, AF_INET, SOCK_STREAM
from threading import Thread
def handle_connection(c):
    amount = int(c.recv(2048).decode("utf8"))
    for i in range(amount):
        print(c.recv(2048).decode("utf8"))
class FileReceiver:
    def __init__(self):
        self.socket = socket(AF_INET, SOCK_STREAM)

    def run(self):
        try:
            self.socket.bind(('0.0.0.0', 7557))
            self.socket.listen()
            while True:
                c, a = self.socket.accept()
                thr = Thread(target=handle_connection, args=(c,))
                thr.run()
        except KeyboardInterrupt:
            self.socket.detach()
            self.socket.close()

fr = FileReceiver()
fr.run()

从客户端接收数据。 在 Kotlin 上我使用

val socket = Socket(server_ip, server_port)
val input = BufferedReader(InputStreamReader(socket.getInputStream()))
val out = PrintWriter(socket.getOutputStream())
out.write("10")
out.flush()
for (i in 1..10)
{
    out.write("A")
    out.flush()
}

发送数据。 使用此代码会导致服务器仅接收一条带有所有 A 的消息,但我试图让它在循环内的单独消息中接收所有这些消息。 我不是最好的程序员,因此将不胜感激有关此代码的任何帮助! 提前谢谢!

【问题讨论】:

    标签: python kotlin synchronization client-server


    【解决方案1】:

    正如SOCK_STREAM 建议的那样,您实际上并不是在这里发送/接收消息,而是字节流。您在此处使用的 TCP 不理解消息。发送一次"AAAAA" 和发送五次"A" 几乎是一样的。

    如果您需要发送消息并在发送消息时接收它们,则必须在 TCP 之上引入某种协议。该协议将在一侧对消息进行编码,并在接收端对其进行解码。

    手动实现此功能的最简单方法是发送例如2 个字节与消息的大小,然后是消息本身。在接收端,您首先读取 2 个字节,然后读取所需的字节数以解码完整消息。可以这样实现:

    Kotlin/客户端

    fun main() {
        ...
    
        val out = DataOutputStream(socket.getOutputStream())
        out.writeMsg("10".toByteArray())
        for (i in 1..10)
        {
            out.writeMsg("A".toByteArray())
        }
    }
    
    fun DataOutputStream.writeMsg(msg: ByteArray) {
        require(msg.size.toUShort() <= UShort.MAX_VALUE)
        writeShort(msg.size)
        write(msg)
    }
    

    Python/服务器

    def recvall(sock, size):
        result = bytearray()
        while len(result) < size:
            result.extend(sock.recv(size - len(result)))
        return result
    
    def recvmsg(sock):
        size = struct.unpack('>H', recvall(sock, 2))[0]
        return recvall(sock, size)
        
    
    def handle_connection(c):
        amount = int(recvmsg(c).decode("utf8"))
        for i in range(amount):
            print(recvmsg(c).decode("utf8"))
    

    请注意,此代码可能不是生产就绪的。应该针对网络断开等错误场景进行测试。

    您也可以尝试使用提供基于消息的网络的现有协议/库。一个这样的库是ZeroMQ - 它是多语言的,相对简单且易于使用。请注意,它确实是纯粹基于消息的,因此有时使用起来可能看起来很奇怪。例如,它以无连接方式工作,它向用户隐藏网络连接。这很好,因为我们不需要接受连接,它会自动重新连接,我们可以在bind/listen 之前connect 等。另一方面,它不向我们提供有关已连接客户端的信息,它不会通知我们断开连接等。

    【讨论】:

    • 非常感谢!但是你能推荐一个我可以同时用于 Kotlin 和 Python 的库吗?
    • 我更新了我的答案以提供一些示例。是的,您可以在 Python 和 Kotlin 中使用 ZeroMQ。请记住,您可以在 Kotlin 中使用任何 Java 库。如果您有兴趣,我建议选择 JeroMQ 实现。然而……再想一想,ZeroMQ 可能不是最好的主意。它真的很棒,让网络变得超级简单,但另一方面,它引入了几个可能看起来很奇怪并且必须学习的概念。这可能不是一个好的起点,最好先了解网络本身,然后跳到 ZeroMQ 之类的框架。
    猜你喜欢
    • 2011-06-14
    • 1970-01-01
    • 1970-01-01
    • 2012-07-24
    • 2010-09-18
    • 1970-01-01
    • 2011-08-19
    • 2022-12-11
    相关资源
    最近更新 更多