【问题标题】:Java client doesn't send whole message to python server?Java客户端不会将整个消息发送到python服务器?
【发布时间】:2019-01-30 11:34:14
【问题描述】:

我正在 android studio 中编写一个与 python 服务器通信的程序。我试图发送一条长消息(以 base64 编码的 mp3 文件 - 大约 10k 字节)。问题是当我检查我在服务器中收到的内容时,我得到的字节数少于 10k。

有人知道怎么解决吗?

提前致谢。

记录消息并将其放入base64:

// Record audio from user in mp3 format
                    MediaRecorder recorder = new MediaRecorder();
                    recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
                    recorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
                    recorder.setOutputFile(Environment.getExternalStorageDirectory()
                                           .getAbsolutePath() + "/messageRecord.mp3");
                    recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
                    recorder.prepare();
                    recorder.start();

                    TimeUnit.SECONDS.sleep(5);
                    recorder.stop();

                    File file = new File(Environment.getExternalStorageDirectory()
                                         .getAbsolutePath() + "/messageRecord.mp3");
                    int size = (int) file.length();
                    byte[] bytes = new byte[size];
                    BufferedInputStream buf = new BufferedInputStream(new FileInputStream(file));
                    buf.read(bytes, 0, bytes.length);
                    buf.close();
                    String content = Base64.encodeToString(bytes, Base64.DEFAULT);

                    // Prepare audio message request
                    JSONObject sendRecordReq = new JSONObject();
                    sendRecordReq.put("code", Codes.SPEECH_TO_TEXT_CODE);
                    sendRecordReq.put("src_phone", ChatScreen.this.srcPhone);
                    sendRecordReq.put("dst_phone", ChatScreen.this.dstPhone);
                    sendRecordReq.put("content", content);

                    // Send message request
                    ChatScreen.this.client.send(sendRecordReq);

我如何发送它:

//In class client
    public void send(JSONObject request) {
        this.outgoingMessages.addConversationFlow(request); //Send request
    }
//In class OutgoingMessages
    public void run() {
        try {
            while (true) {
                while(!this.conversationFlow.isEmpty()) {
                    JSONObject msgToSend = this.conversationFlow.remove();
                    String strRequest = msgToSend.toString();
                    this.out.write(Integer.toString(strRequest.length()).getBytes()); //Sends message size
                    this.out.write(strRequest.getBytes()); //Sends message
                }
            }
        }
        catch (Exception e) {
            System.out.println(e);
        }
    }

服务器:

while True:
            # Receiving data size from client
            message_size = int(client_socket.recv(MAX_SIZE_LEN))

            # Receiving data from the client
            client_message = client_socket.recv(message_size)
            print client_message
            # Add message to messages queue with client's socket
            MESSAGES_QUEUE.append((client_socket, client_message))

编辑: "message_size" 值是正确的(14806 - 应该在下一行中接收到的消息的大小)但它仍然没有全部接收到。

编辑2: 我想通了,我在答案中发布解决方案

【问题讨论】:

    标签: java android python python-2.7 sockets


    【解决方案1】:

    您的 java 代码正在使用不可能工作的协议发送数据。

    如果输入的 JSON 对象是字符串“a”,那么你会发送这个:

    3"a"
    

    如,4 个字节:51、34、97、34。

    python 端不知道“这是数据有多长”部分何时结束。

    我假设您打算发送的内容大致如下:

    00, 00, 00, 03, 34, 97, 34.
    

    换句话说:4个字节包含一个网络端发送的整数值和长度,然后是那么多字节。

    另外,不要打电话给.getBytes();将字符串转换为字节时,应始终明确指定编码。 JSON 在定义上或多或少是 UTF-8,因此,请改为调用 .getBytes("UTF-8")

    注意:要替换您的“发送长度”代码,请参阅Convert integer into byte array (Java)

    【讨论】:

    • 我将长度的发送改为:this.out.write(String.format("%010d", strRequest.length()).getBytes());服务端获取长度后读取10个字节,现在可以了吗?
    • 另一个问题,当我执行 getBytes("UTF-8") 时,应该是在将文件转换为字节数组时还是在发送之前?还是两者兼而有之?
    【解决方案2】:

    所以问题不在于文件的长度或其他任何东西。问题是 python 中的 recv 函数会获取一些字节,但由于某种原因代码继续,所以它没有得到整个消息。

    解决方案是添加一个在收到指定的整个长度之前不会继续的函数。我在下一篇文章中找到了解决方案: Python Socket Receive Large Amount of Data

    我也会添加代码:

    将 recv 函数替换为 recvall(socket, size)。这不是我的代码,它由 Adam Rosenfield 发布并由 Hedde van der Heide 编辑。

    def recvall(sock, n):
        # Helper function to recv n bytes or return None if EOF is hit
        data = b''
        while len(data) < n:
            packet = sock.recv(n - len(data))
            if not packet:
                return None
            data += packet
        return data
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-10-17
      • 1970-01-01
      • 2017-04-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-09-11
      相关资源
      最近更新 更多