Python 和 Kotlin 应用程序套接字同步问题

Python and Kotlin applications socket sync issue

我正在 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 的消息,但我试图让它在循环内的单独消息中接收所有消息。 我不是最好的程序员,所以对这段代码的任何帮助将不胜感激! 提前致谢!

正如 SOCK_STREAM 所建议的那样,您在这里并不是真正的 send/receive 消息,而是字节流。您在这里使用的 TCP 不理解消息。发一次"AAAAA"和发五次"A"就差不多了

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

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

Kotlin/client

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/server

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"))

请注意,此代码可能尚未投入生产。应针对网络断开等错误场景进行测试

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