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
,等等。另一方面,它不提供给我们关于已连接客户端的信息,它不会通知我们有关断开连接等信息。
我正在 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
,等等。另一方面,它不提供给我们关于已连接客户端的信息,它不会通知我们有关断开连接等信息。