通过:Android 接收 Python Socket 消息

0 投票
1 回答
2227 浏览
提问于 2025-04-18 04:24

我正在开发一个安卓应用,它通过一个套接字连接到一个用Python写的服务器。安卓应用会发送一张图片到服务器,然后期待服务器返回一条文本消息,接着它会更新一个TextView来显示收到的消息。

发生的情况是:服务器成功接收了图片并发送回了一条消息。但不知为何,这条消息在安卓应用上没有显示出来。

我搞不清楚,是因为应用没有收到这条消息?还是收到了,但在显示消息时出现了错误?

这是服务器的代码(server.py):

from socket import *

HOST = "x.x.x.x" #replaced with the server's IP
PORT = 6000
s = socket(AF_INET, SOCK_STREAM)
s.bind((HOST, PORT))
s.listen(1)
conn, addr = s.accept()
print "Connected by: " , addr
while True:
    data = conn.recv(40960)
    with open('image.jpg', 'wb') as file:
       file.write(data)
    reply = raw_input("Reply: ")
    conn.sendall(reply)
conn.close() 

这是安卓应用代码的一部分:

static TextView msgReceived;

    public void onClickSend(View view) {

        Thread t = new Thread(new Runnable(){

            String imgPath = "/mnt/sdcard/Pictures/0001.jpg";

            @Override
            public void run() {
                try {
                    Socket s = new Socket("x.x.x.x", 6000); //create socket

                    //---- SEND IMAGE TO SERVER ---//
                    FileInputStream fis = new FileInputStream(imgPath); //read image as bytes
                    byte [] buffer1 = new byte [fis.available()]; //create buffer that will hold the bytes
                    fis.read(buffer1); //read file contents to the buffer

                    ObjectOutputStream oos = new ObjectOutputStream(s.getOutputStream()); //create the object to be sent
                    oos.writeObject(buffer1); //send the contents of the buffer to the socket
                    oos.close();

                    //---- RECEIVE TEXT FROM SERVER ---//
                    tempIn = new ObjectInputStream(s.getInputStream());
                        Message clientmessage = Message.obtain();                    
                        ObjectInputStream ois = new ObjectInputStream(tempIn);
                        String strMessage = (String)ois.readObject();
                        System.out.println(strMessage);
                        clientmessage.obj = strMessage;

                        mHandler.sendMessage(clientmessage);

                        ois.close();

                    s.close();

                } catch (UnknownHostException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                } //catch (ClassNotFoundException e) {
                    //e.printStackTrace();
                //}
            }

        });

        t.start();
    }

    Handler mHandler = new Handler(){
        @Override
        public void handleMessage(Message msg){
            Display(msg.toString());
        }
    };

    public void Display(String serverMsg){
        msgReceived = (EditText) findViewById(R.id.msgReceived);
        msgReceived.setText(serverMsg);
        //Toast.makeText(getBaseContext(), serverMsg, Toast.LENGTH_SHORT).show();
    }

我觉得问题出在安卓的Java代码上,因为server.py在用一个测试的client.py时运行得很好(也就是说,它成功接收了图片,发送了回复,客户端也完美接收到了)。

还有一点,在我排查问题时,我尝试用一个普通字符串(不是从服务器收到的那条)来更新TextView,结果也没有成功!所以这可能表明问题出在更新的部分。

我非常感谢任何帮助,提前谢谢大家。我对安卓开发和Java非常陌生。

1 个回答

1

你的问题有两个方面:

  1. 你在把图片写入套接字后,立刻调用了 oos.close()。我发现这样会抛出一个 SocketException: Socket is closed 的错误。根据这个回答:Android: Socket is closed,关闭与套接字相关的流会同时关闭那个套接字,这样你就无法从中读取服务器的响应了。所以,把 oos.close() 移到最后,在你完成读取后再关闭。

  2. 我对你的代码做了这个修改后,仍然抛出了 StreamCorruptedException 的错误。根据这个回答:StreamCorruptedException: invalid type code: AC,这个错误是因为你使用了两个 ObjectInput/OutputStreams。我不太确定怎么只用一个,除非你采用我之前建议的修改。我重新调整了你的代码,变成了下面这样,这在我的系统上使用你的 Python 服务器代码是可以工作的。

    // Write to socket
    ObjectOutputStream oos = new ObjectOutputStream(s.getOutputStream()); //create the object to be sent
    oos.writeObject(buffer1); //send the contents of the buffer to the socket    
    oos.flush();
    
    // Read from socket
    BufferedReader input = new BufferedReader(new InputStreamReader(s.getInputStream()));
    StringBuilder response = new StringBuilder();
    String line;
    while ((line = input.readLine()) != null)
        response.append(line);
    Message clientmessage = Message.obtain();
    clientmessage.obj = response.toString();
    mHandler.sendMessage(clientmessage);
    oos.close();
    input.close();
    s.close();
    

顺便提一下,你在代码顶部定义了 UI 元素 msgReceivedTextView,但在代码底部却把它转换成了 EditView。我遇到了 ClassCastException 的错误,直到我把它们改成一致的,所以要小心。

撰写回答