树莓派与Android客户端进行socket通信
16lz
2021-01-26
首先,需要对树莓派进行配置,使其成为AP热点,这里我用的树莓派3B自带wifi蓝牙模块,树莓派3B作AP热点的方法具体参考https://blog.csdn.net/u014271612/article/details/53766627这篇文章,但配置过程中会遇到一些小问题,比如在输入 git clone https: //github.com/oblique/create_ap 这条命令时会提示需要帐号密码,而我的做法是直接上github将这个项目的zip压缩文件下载下来拷贝到我的树莓派中,然后再进行下面操作,后面还有一个问题 ,在 sudo create_ap wlan0eth0 热点名 密码 这行密码中wlan0eth0 应该在中间加一个空格,即 sudo create_ap wlan0 eth0 热点名 密码 至此树莓派作为AP热点配置成功。 下面进入主题,树莓派与android客户端之间的通信我采用socket来实现,树莓派上我写了一个python脚本作为服务器,android作为客户端
首先,上一下效果图:
Android客户端:
树莓派服务器端:
树莓派上的python脚本如下:
import socketimport timeimport sysHOST_IP = "192.168.12.1" #我的树莓派作为AP热点的ip地址HOST_PORT = 7654 #端口号print("Starting socket: TCP...")socket_tcp = socket.socket(socket.AF_INET, socket.SOCK_STREAM) #创建socketprint("TCP server listen @ %s:%d!" %(HOST_IP, HOST_PORT) )host_addr = (HOST_IP, HOST_PORT)socket_tcp.bind(host_addr) #绑定我的树莓派的ip地址和端口号socket_tcp.listen(1)#listen函数的参数是监听客户端的个数,这里只监听一个,即只允许与一个客户端创建连接while True:print ('waiting for connection...')socket_con, (client_ip, client_port) = socket_tcp.accept() #接收客户端的请求print("Connection accepted from %s." %client_ip)socket_con.send("Welcome to RPi TCP server!") #发送数据while True:data=socket_con.recv(1024) #接收数据if data: #如果数据不为空,则打印数据,并将数据转发给客户端print(data)socket_con.send(data)socket_tcp.close()
注:上述代码注释是后期加上去的,可以将代码中的注释去掉再运行。
接下来是Android客户端代码:
1、XML布局文件
<?xml version="1.0" encoding="utf-8"?>
2、Activity.java
package lh.wifidemo.ui.activity;import android.os.Handler;import android.support.v7.app.ActionBarActivity;import android.os.Bundle;import android.view.View;import android.widget.Button;import android.widget.EditText;import android.widget.TextView;import java.io.BufferedReader;import java.io.BufferedWriter;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader;import java.io.OutputStream;import java.io.OutputStreamWriter;import java.io.PrintWriter;import java.net.Socket;import lh.wifidemo.R;public class Device_Control_Activity extends ActionBarActivity { private EditText et_send; private Button bt_send; private TextView tv_recv; private String send_buff=null; private String recv_buff=null; private Handler handler = null; Socket socket = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_device__control_); initView(); handler = new Handler(); //单开一个线程来进行socket通信 new Thread(new Runnable() { @Override public void run() { try { socket = new Socket("192.168.12.1" , 7654); if (socket!=null) { System.out.println("###################"); while (true) { //循环进行收发 recv(); send(); } } else System.out.println("socket is null"); } catch (IOException e) { e.printStackTrace(); } } }).start(); send(); } private void recv() { //单开一个线程循环接收来自服务器端的消息 InputStream inputStream = null; try { inputStream = socket.getInputStream(); } catch (IOException e) { e.printStackTrace(); } if (inputStream!=null){ try { byte[] buffer = new byte[1024]; int count = inputStream.read(buffer);//count是传输的字节数 recv_buff = new String(buffer);//socket通信传输的是byte类型,需要转为String类型 System.out.println(recv_buff); } catch (IOException e) { e.printStackTrace(); } } //将受到的数据显示在TextView上 if (recv_buff!=null){ handler.post(runnableUi); } } //不能在子线程中刷新UI,应为textView是主线程建立的 Runnable runnableUi = new Runnable() { @Override public void run() { tv_recv.append("\n"+recv_buff); } }; private void send() { bt_send.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { new Thread(new Runnable() { @Override public void run() { send_buff = et_send.getText().toString(); //向服务器端发送消息 System.out.println("------------------------"); OutputStream outputStream=null; try { outputStream = socket.getOutputStream(); } catch (IOException e) { e.printStackTrace(); } if(outputStream!=null){ try { outputStream.write(send_buff.getBytes()); System.out.println("1111111111111111111111"); outputStream.flush(); } catch (IOException e) { e.printStackTrace(); } } } }).start(); } }); } private void initView() { et_send = (EditText) findViewById(R.id.et_send); bt_send = (Button) findViewById(R.id.bt_send); tv_recv = (TextView) findViewById(R.id.tv_recv); }}
这里有几个地方需要特别注意:
1、创建socket时需要开一个子线程,而不能直接在主线程中完成,否则会报错
2、当接收来自树莓派服务器的消息时,需要刷新TextView,而刷新TextView的操作不能直接在子线程中完成,需要用Handler来实现,否则会报错,提示view只能由源线程来更改
整个项目需要先启动树莓派,然后手机连上树莓派的WIFI热点,如果想要查看树莓派的输出信息,则可以利用window的远程桌面连接树莓派,也可以用putty这个软件进行命令行控制,当然,有条件的完全可以用HDMI接口给你的树莓派连一个显示器
更多相关文章
- SpringBoot 2.0 中 HikariCP 数据库连接池原理解析
- 一句话锁定MySQL数据占用元凶
- android使用AIDL跨进程通信(IPC)
- flutter 持久化存储-----数据库sqflite
- AndroidStudio 优秀的第三方数据库 GreenDao
- java做服务器,android做客户端,实现数据传输
- Android入门:深入学习理解 Handler HandlerThread AsyncQueryHan
- Android(安卓)基于DataBinding的通用RecyclerView Adapter
- Android学习整理- 9- 实时更新UI-Handler