python - Android客户端不会从python服务器接收
问题描述
嘿,我刚开始学习 android,我的任务是制作一个从 python 服务器发送和接收数据的应用程序。它完美地发送数据,但我无法让客户端接收数据。请放轻松,我是新手,这是我的代码:
安卓代码:
class MyTask extends AsyncTask<Void, Void, Void> {
@SuppressLint(("Wrong Thread"))
@Override
protected Void doInBackground(Void... voids) {
try {
Log.d("ORI", "1- before connect");
sock = new Socket(LOCAL_HOST, PORT);
Log.d("ORI", "2 - after connect" );
prWriter = new PrintWriter(sock.getOutputStream());
prWriter.write(msg);
prWriter.flush();
BufferedReader in = new BufferedReader(new InputStreamReader(sock.getInputStream()));
StringBuilder response = new StringBuilder();
String line;
while ((line = in.readLine()) != null) {
response.append(line);
}
Toast.makeText(getApplicationContext(), response, Toast.LENGTH_LONG);
sock.close();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
这是我的 Python 服务器:
import socket
server_sock = socket.socket()
server_sock.bind(("0.0.0.0", 5024))
server_sock.listen(1)
client, addr = server_sock.accept()
print(addr[0])
flag = False
while True:
try:
data = client.recv(1024).decode()
except Exception as e:
print(str(e))
break
else:
if not flag:
if data == '':
pass
print(data)
try:
client.send("K".encode())
except Exception as e:
print(e)
else:
print("OK")
flag = True
server_sock.close()
解决方案
这是一个在 Python 中更灵活、更可靠的套接字服务器的想法。
如果您无法确定要读取多少数据,则从套接字读取可能具有挑战性。例如,如果假设没有消息会超过 1K,那么您可能会想使用recv(1024),但这并不可靠。具体来说,客户端可以发送 800 个字节,但服务器可能会在一次调用 recv() 时“看到”更少的字节。
因此,您需要一个协议,使服务器能够准确地知道需要多少数据。
一种方法是对消息使用固定长度的前导码。我们可以利用 pack/unpack 函数(来自 struct 模块)来构建独立于网络的整数,这些整数在实际消息之前发送。服务器知道期望前导码(它是固定长度的)并且通过解包该值可以执行 recv() 以获得精确的字节数。
下面的例子通过实现一个回显过程来利用这个范例,服务器在它自己的线程中运行,客户端发送一条消息,服务器立即回复它首先收到的任何内容。在此示例中,客户端以“终止开关”结束。
我可能会接受各种批评,但无论如何:
import socket
import threading
from struct import pack, unpack
HOST = 'localhost'
PORT = 7070
FORMAT = ('!Q', 8)
MSG = '''The Owl and the Pussy-cat went to sea
In a beautiful pea-green boat,
They took some honey, and plenty of money,
Wrapped up in a five-pound note.
The Owl looked up to the stars above,
And sang to a small guitar,
"O lovely Pussy! O Pussy, my love,
What a beautiful Pussy you are,
You are,
You are!
What a beautiful Pussy you are!"'''
def sendbuffer(s, b):
buffer = pack(FORMAT[0], len(b)) + b
offset = 0
while offset < len(buffer):
offset += s.send(buffer[offset:])
def recvbuffer(s):
p = s.recv(FORMAT[1], socket.MSG_WAITALL)
n = unpack(FORMAT[0], p)[0]
return None if n == 0 else s.recv(n, socket.MSG_WAITALL)
def server():
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind((HOST, PORT))
s.listen()
conn, _ = s.accept()
with conn:
while (data := recvbuffer(conn)):
sendbuffer(conn, data)
def client(msg):
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.connect((HOST, PORT))
sendbuffer(s, msg.encode())
data = recvbuffer(s)
print(data.decode())
sendbuffer(s, b'') # kill switch
def main():
threading.Thread(target=server).start()
client(MSG)
if __name__ == '__main__':
main()
注意 这已经在 macOS 上进行了测试,在 Windows 上可能无法按预期工作
推荐阅读
- string - 如何在 SIMD/AVX2 代码中连接有界长度的字符串
- algorithm - 加权圆图的总路径概率
- macos - 我可以使用通配符来阻止主机文件中的网站吗?
- python - ```time.perf_counter()``` 命令有什么作用?
- java - Java:如何将 0 到 1 之间的值四舍五入到至少 3 位小数?
- c# - 我在 Visual Studio 2013 的可扩展性选项卡中找不到添加自定义命令选项
- linux - CMake/CPack:将二进制文件从 Linux 部署到 Mac OSX
- asp.net-core - 基于策略的授权,仅允许作为资源所有者的用户能够查看/编辑
- python - 访问类外的类方法变量
- azure-devops - 如何在 azure DevOps YAML 管道中发送构建后消息?