【问题标题】:Android client won't receive from python serverAndroid客户端不会从python服务器接收
【发布时间】:2021-12-19 11:18:18
【问题描述】:

嘿,我刚开始学习 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()

【问题讨论】:

  • 您没有发布任何错误或异常跟踪您的问题
  • 我忘了提到它在 BufferedReader 中显示错误 = new BufferedReader(new InputStreamReader(sock.getInputStream()));它说套接字已关闭。
  • 以及来自 logcat 的完整错误跟踪后的错误是什么
  • 在 java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305) 在 java.util.concurrent.FutureTask.run(FutureTask.java:137) 在 android.os.AsyncTask $SerialExecutor$1.run(AsyncTask.java:230) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569) at java .lang.Thread.run(Thread.java:856) 引起:libcore.io.ErrnoException:连接失败:ETIMEDOUT(连接超时)
  • 您的服务器实现存在许多问题。特别是,您对 recv() 的使用非常可疑,原因有两个。 1)如果/当客户端发送超过 1K 字节时会发生什么? 2) 如果客户端发送的字节数少于 1K,但通过一次 recv() 调用并没有全部接收到,会发生什么情况?您必须有一个策略/协议,允许服务器“知道”何时收到所有数据。此外,服务器如何“知道”所有/任何客户端何时完成向其发送数据?

标签: python android server client


【解决方案1】:

这是一个用 Python 构建更灵活、更可靠的套接字服务器的想法。

如果您无法确定要读取多少数据,则从套接字读取可能具有挑战性。例如,如果假设没有消息会超过 1K,那么您可能会想 recv(1024) 但这并不可靠。具体来说,客户端可以发送 800 个字节,但服务器可能会在一次调用 recv() 时“看到”更少的字节。

因此,您需要一种协议,使服务器能够准确地知道需要多少数据。

一种方法是对消息使用固定长度的前导码。我们可以利用 pack/unpack 函数(来自 struct 模块)来构建独立于网络的整数,这些整数在实际消息之前发送。服务器知道该前导码(具有固定长度)并且通过解包该值可以执行 recv() 以获得精确的字节数。

以下示例通过实现 echo 进程来利用此范例,服务器在其自己的线程中运行,客户端发送消息,服务器立即回复它首先收到的任何内容.在此示例中,客户端以“终止开关”结束。

我可能会对各种批评敞开心扉,但无论如何:

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 上可能无法正常工作

【讨论】:

    【解决方案2】:

    原因:libcore.io.ErrnoException:连接失败:ETIMEDOUT(连接超时)

    您的客户端尝试使用.readLine() 读取一行。

    但是..您的服务器发送线路了吗?您的服务器发送:

     client.send("K".encode())
    

    (那只是一个字符。为什么不是一个大句子?)

    但无论如何,当字符串以\n结尾时,它只是一行。

    所以改成:

     client.send("Hello World\n".encode())
    

    【讨论】:

    • 我现在看到它能够接收thanks you,但是toast 似乎不起作用,它没有在屏幕上为我打印任何内容。你能帮我解决这个问题吗?
    • 很高兴您的 Android 应用没有崩溃。因为您无法在 Thread 或 doInBackground() 中显示 Toast。实现并使用 onPostExecute() 来显示该 Toast。为此,不要在 doInBackground() 中返回 null,而是返回该消息。
    • 我正在尝试,但它说无法解析符号“响应”,好像尝试后的所有内容都被删除了一样
    • 未删除,但如果您在 try 块之外,则确实不知道响应。好吧,我把它留给你找到解决方案。 :-)。并返回一个字符串。不是 StringBuilder。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-06
    • 2019-08-13
    • 2017-12-29
    • 1970-01-01
    • 2021-08-24
    相关资源
    最近更新 更多