[英]Why I cannot get response from the tcp server?
I have (ESP32 based) device that among other things implements TCP server.我有(基于 ESP32 的)设备,其中包括实现 TCP 服务器。 I can send to it messages in JSON format to change some controls in it.我可以向它发送 JSON 格式的消息以更改其中的一些控件。
I want to be able to control this device from my Android phone.我希望能够通过我的 Android 手机控制此设备。 I wrote an app for it, but I have a problem - my Android app doe not get any response from ESP32 device.我为它写了一个应用程序,但我有一个问题——我的 Android 应用程序没有得到 ESP32 设备的任何响应。 I wrote for tests simple scripts in Python.我在 Python 中为测试编写了简单的脚本。 First one is a client, that sends messages to ESP32.第一个是客户端,它向 ESP32 发送消息。 Second one implements tcp server, so that I can connect my Android app to it and check if response arrives.第二个实现 tcp 服务器,这样我就可以将我的 Android 应用程序连接到它并检查响应是否到达。 Both tests works fine.两项测试都可以正常工作。
Is there anything wrong in my Android code?我的 Android 代码有什么问题吗? I cannot be sure if it is not ESP32 device fault, but please first check my Android code - it is harder to make MCVE from C code for ESP32.我不能确定这是否不是 ESP32 设备故障,但请先检查我的 Android 代码 - 从 ESP32 的 C 代码制作 MCVE 更难。
Here is my Android app's MCVE:这是我的 Android 应用程序的 MCVE:
MainActivity.java: 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: 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: 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 client: 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 server: 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()
Console log from the app lanuch, after clicking SEND
button:点击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
The problem was probably related to lack of new line character at the end of the response.该问题可能与响应末尾缺少换行符有关。 Adding it didn't help instantly, but after some more changes in the server, Android app started to be able to get the response.添加它并没有立即帮助,但在服务器中进行了更多更改后,Android 应用程序开始能够获得响应。 I cannot tell what exactly was the problem after adding the new line character.添加换行符后,我无法确定问题到底出在哪里。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.