簡體   English   中英

為什么我無法從 tcp 服務器得到響應?

[英]Why I cannot get response from the tcp server?

我有(基於 ESP32 的)設備,其中包括實現 TCP 服務器。 我可以向它發送 JSON 格式的消息以更改其中的一些控件。

我希望能夠通過我的 Android 手機控制此設備。 我為它寫了一個應用程序,但我有一個問題——我的 Android 應用程序沒有得到 ESP32 設備的任何響應。 我在 Python 中為測試編寫了簡單的腳本。 第一個是客戶端,它向 ESP32 發送消息。 第二個實現 tcp 服務器,這樣我就可以將我的 Android 應用程序連接到它並檢查響應是否到達。 兩項測試都可以正常工作。

我的 Android 代碼有什么問題嗎? 我不能確定這是否不是 ESP32 設備故障,但請先檢查我的 Android 代碼 - 從 ESP32 的 C 代碼制作 MCVE 更難。

這是我的 Android 應用程序的 MCVE:

MainActivity.java:

package com.example.tcpclienttest;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;

public class MainActivity extends AppCompatActivity {

    String TAG = "******** INFO ********";

    Socket tcpSocket;
    InetAddress IP;
    int tcpPort = 12345;
    PrintWriter mBufferOut;
    BufferedReader mBufferIn;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Button button = this.findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                new Thread(new Runnable() {
                    public void run() {
                        // try twice in case of tcp error
                        if (SendSetStateCommandTaskFunction()) {
                            Log.i(TAG, "Retrying SendSetStateCommandTask function");
                            SendSetStateCommandTaskFunction();
                        }
                    }
                }).start();

            }
        });
    }

    boolean SendSetStateCommandTaskFunction() {

        boolean retry = false;



        String request_data = "'{\"cmd\":\"set_controls\", \"data\":{\"controls\":{\"name1\":5}}}'";

        try {
            IP = InetAddress.getByName("192.168.1.66");
            if (tcpSocket == null) {
                Log.i(TAG, "Creating new tcp socket");
                tcpSocket = new Socket(IP, tcpPort);
                tcpSocket.setSoTimeout(3000);
                //sends the message to the server
                mBufferOut =
                        new PrintWriter(
                                new BufferedWriter(
                                        new OutputStreamWriter(tcpSocket.getOutputStream())), true);

                //receives the message which the server sends back
                mBufferIn =
                        new BufferedReader(
                                new InputStreamReader(tcpSocket.getInputStream()));
            } else
                Log.i(TAG, "Tcp socket already created");
            if (!tcpSocket.isConnected()) {
                Log.i(TAG, "Connecting to ip addr");
                SocketAddress sockaddr = new InetSocketAddress(IP, tcpPort);
                tcpSocket.connect(sockaddr);
            } else
                Log.i(TAG, "Already connected");

            String in_message;

            mBufferOut.println(request_data);
            mBufferOut.flush();

            in_message = mBufferIn.readLine();

            if (in_message == null) {
                Log.i(TAG, "Received empty message");
                return false;
            }

            Log.i(TAG, in_message);
        } catch (IOException e) {
            Log.e(TAG, "ERROR: " + e.getMessage());
            e.printStackTrace();
            tcpSocket = null;
            retry = true;
        }

        Log.i(TAG, "Finishing SendSetStateCommandTask function");
        return retry;
    }
}

AndroidManifest.xml:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.tcpclienttest">

    <uses-permission android:name="android.permission.INTERNET"/>

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

main_activity.xml:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Send"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

Python 客戶端:

import socket
import json

TCP_IP = "192.168.1.66"
TCP_PORT = 12345

print("TCP target IP:", TCP_IP)
print("TCP target port:", TCP_PORT)

sock = socket.socket(socket.AF_INET, # Internet
                     socket.SOCK_STREAM) # TCP
sock.connect((TCP_IP, TCP_PORT))

MESSAGE = str.encode('{"cmd":"set_controls", "data":{"controls":{"name1":6}}}')

print("message:", MESSAGE)

sock.send(MESSAGE)

data = sock.recv(1024)  # buffer size is 1024 bytes
json_data = json.loads(data.decode("ascii"))
print("received message:")
print(json.dumps(json_data, indent=4))

Python 服務器:

#!/usr/bin/env python

import socket

TCP_IP = ''
TCP_PORT = 12345
BUFFER_SIZE = 1024

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((TCP_IP, TCP_PORT))
s.listen(1)

conn, addr = s.accept()
print('Connection address:', addr)
while 1:
    data = conn.recv(BUFFER_SIZE)
    if not data:
        break
    print("received data:", data)
    conn.send(data)  # echo
conn.close()

點擊SEND按鈕后,來自 app lanuch 的控制台日志:

I/ViewRootImpl: jank_removeInvalidNode all the node in jank list is out of time
V/AudioManager: playSoundEffect   effectType: 0
    querySoundEffectsEnabled...
I/******** INFO ********: Creating new tcp socket
I/******** INFO ********: Already connected
E/******** INFO ********: ERROR: Read timed out
W/System.err: java.net.SocketTimeoutException: Read timed out
W/System.err:     at java.net.SocketInputStream.socketRead0(Native Method)
        at java.net.SocketInputStream.socketRead(SocketInputStream.java:119)
W/System.err:     at java.net.SocketInputStream.read(SocketInputStream.java:176)
        at java.net.SocketInputStream.read(SocketInputStream.java:144)
        at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:288)
W/System.err:     at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:351)
        at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:180)
W/System.err:     at java.io.InputStreamReader.read(InputStreamReader.java:184)
        at java.io.BufferedReader.fill(BufferedReader.java:172)
W/System.err:     at java.io.BufferedReader.readLine(BufferedReader.java:335)
        at java.io.BufferedReader.readLine(BufferedReader.java:400)
        at com.example.tcpclienttest.MainActivity.SendSetStateCommandTaskFunction(MainActivity.java:93)
W/System.err:     at com.example.tcpclienttest.MainActivity$1$1.run(MainActivity.java:44)
        at java.lang.Thread.run(Thread.java:784)
I/******** INFO ********: Finishing SendSetStateCommandTask function
I/******** INFO ********: Retrying SendSetStateCommandTask function
    Creating new tcp socket
I/******** INFO ********: Already connected
E/******** INFO ********: ERROR: Read timed out
W/System.err: java.net.SocketTimeoutException: Read timed out
W/System.err:     at java.net.SocketInputStream.socketRead0(Native Method)
W/System.err:     at java.net.SocketInputStream.socketRead(SocketInputStream.java:119)
        at java.net.SocketInputStream.read(SocketInputStream.java:176)
W/System.err:     at java.net.SocketInputStream.read(SocketInputStream.java:144)
        at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:288)
        at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:351)
W/System.err:     at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:180)
        at java.io.InputStreamReader.read(InputStreamReader.java:184)
W/System.err:     at java.io.BufferedReader.fill(BufferedReader.java:172)
        at java.io.BufferedReader.readLine(BufferedReader.java:335)
W/System.err:     at java.io.BufferedReader.readLine(BufferedReader.java:400)
        at com.example.tcpclienttest.MainActivity.SendSetStateCommandTaskFunction(MainActivity.java:93)
        at com.example.tcpclienttest.MainActivity$1$1.run(MainActivity.java:46)
W/System.err:     at java.lang.Thread.run(Thread.java:784)
I/******** INFO ********: Finishing SendSetStateCommandTask function

該問題可能與響應末尾缺少換行符有關。 添加它並沒有立即幫助,但在服務器中進行了更多更改后,Android 應用程序開始能夠獲得響應。 添加換行符后,我無法確定問題到底出在哪里。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM