Python服务器向Android客户端发数据并在TextView显示的问题求助
问题分析与解决方案
我帮你梳理出了几个导致功能失效的核心问题,咱们一步步来修正:
1. 最关键的问题:通信协议不匹配
你的Python服务器用的是TCP协议(socket(AF_INET, SOCK_STREAM)),但Android客户端却用了UDP协议(DatagramSocket)。这两种协议完全不兼容,必须统一成同一种才能正常通信。
2. Python服务器的发送对象错误
服务器里你用了监听套接字tcpSerSock.send()来发数据,但实际上应该用和客户端建立连接的通信套接字tcpCliSock——tcpSerSock只负责监听新连接,不负责和具体客户端交互。
3. Python语法与判断逻辑错误
- 你的代码是Python2环境,
print语句需要加括号; - Python2里字符串本身就是字节流,不需要
str.encode(),直接发送字符串即可; - 你当前判断触发发送的条件是
data == ctrCmd[5](对应Connect),但Android发送的是Balls,对应ctrCmd[6],这个判断永远不会触发。
4. Android客户端的协议适配
如果改成TCP协议,客户端需要用Socket而非DatagramSocket来实现面向连接的通信。
修正后的Python服务器代码(TCP)
import apptopi from socket import * from nanpy import (ArduinoApi, SerialManager) apptopi.setup() connection = SerialManager() a = ArduinoApi(connection = connection) ctrCmd = ['Up','Down','Left','Right','Stop','Connect','Balls'] HOST = '' PORT = 21567 BUFSIZE = 1024 ADDR = (HOST,PORT) tcpSerSock = socket(AF_INET, SOCK_STREAM) tcpSerSock.bind(ADDR) tcpSerSock.listen(5) # 设置合理的连接队列长度 print('Waiting for connection') try: while True: tcpCliSock,addr = tcpSerSock.accept() print('...connected from :', addr) try: while True: data = tcpCliSock.recv(BUFSIZE).strip() # 去除首尾空白,避免数据带换行/空格 if not data: break print('Received data from client: ' + data) if data == ctrCmd[0]: apptopi.forw() print('forward') elif data == ctrCmd[1]: apptopi.back() print('backward') elif data == ctrCmd[2]: apptopi.left() print('leftturn') elif data == ctrCmd[3]: apptopi.right() print('rightturn') elif data == ctrCmd[4]: apptopi.stp() print('stop') elif data == ctrCmd[6]: # 匹配Android发送的Balls命令 add = 1 # 如需累加可将变量移至外层循环 tcpCliSock.send(str(add)) # Python2直接发送字符串 print('Sent data to client: ' + str(add)) except Exception as e: print('Client connection error:', e) tcpCliSock.close() except KeyboardInterrupt: apptopi.close() # GPIO.cleanup() # 若未导入GPIO模块请注释此行 tcpSerSock.close() print('Server closed')
修正后的Android客户端代码(TCP)
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mEditTextSendMessage = (EditText) findViewById(R.id.edt_send_message); mTextViewReplyFromServer = (TextView) findViewById(R.id.tv_reply_from_server); btn_collect = (Button) findViewById(R.id.btn_send); btn_collect.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { String message = "Balls"; // 直接发送触发服务器返回数据的命令 sendMessage(message); } }); } private void sendMessage(final String message) { final Handler handler = new Handler(Looper.getMainLooper()); // 确保在主线程更新UI Thread thread = new Thread(new Runnable() { @Override public void run() { Socket socket = null; BufferedReader reader = null; OutputStreamWriter writer = null; String stringData = ""; try { // 替换为你的Python服务器局域网IP socket = new Socket("192.168.1.11", 21567); // 发送数据到服务器,加换行符方便服务器识别结束 writer = new OutputStreamWriter(socket.getOutputStream()); writer.write(message + "\n"); writer.flush(); // 接收服务器返回的数据 reader = new BufferedReader(new InputStreamReader(socket.getInputStream())); stringData = reader.readLine(); } catch (IOException e) { e.printStackTrace(); stringData = "Error: " + e.getMessage(); } finally { try { if (reader != null) reader.close(); if (writer != null) writer.close(); if (socket != null) socket.close(); } catch (IOException e) { e.printStackTrace(); } } final String finalData = stringData; handler.post(new Runnable() { @Override public void run() { String currentText = mTextViewReplyFromServer.getText().toString(); if (!finalData.trim().isEmpty()) { mTextViewReplyFromServer.setText(currentText + "\n" + finalData); } } }); } }); thread.start(); }
额外注意事项
- 确保Android设备和Python服务器在同一局域网,且服务器IP地址正确;
- Android 9及以上需在
AndroidManifest.xml中添加android:usesCleartextTraffic="true"(测试用); - 别忘了在AndroidManifest中申请网络权限:
<uses-permission android:name="android.permission.INTERNET"/>; - 如需持续累加
add的值,要把add变量移到外层循环,否则每次触发都会重置为1。
内容的提问来源于stack exchange,提问作者Mahilum Jm
相关产品推荐
相关产品推荐

