Android 通过Socket向Python发送数据

最近因为课设要求,需要实现从安卓端向Python服务端发送数据,由于之前也没有做过,所以上网找了许多相关文章,之后也解决了几个问题,最后实现了这个需求。以下是相关代码。

Android端:

activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <TextView
        android:id="@+id/textView"
        android:layout_width="match_parent"
        android:layout_height="366dp"
        android:gravity="center" />

    <Button
        android:id="@+id/start"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="开始监听" />

    <Button
        android:id="@+id/stop"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="停止监听" />


</LinearLayout>

MainActivity.java 这个函数的主要功能是将手机作为一个光传感器,获取传感器数据,之后将数据发送给python端。

public class MainActivity extends AppCompatActivity {

    private TextView showLightPower;//用于显示光照强度的文本视图
    private Button start;//按钮,点击开始监听传感器
    private Button stop;//按钮,点击停止监听传感器
    private SensorManager sensorManager;//传感器管理器,用于获取传感器服务,和选择传感器类型
    private Sensor sensor;//传感器对象,储存光线传感器的数据
    private SensorEventListener sensorEventListener;//传感器事件监听器,用于传感器事件的监听

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

        if (android.os.Build.VERSION.SDK_INT > 9) {
            StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
            StrictMode.setThreadPolicy(policy);
        }
      //初始化控件
        InitWidgets();
        //初始化传感器相关,包含传感器管理器和传感器的设定
        InitSensors();
        //设置按钮点击监听器和传感器事件监听器
        setListener();

    }
    /**
     * 函数功能:初始化传感器相关,包含传感器管理器和传感器类型
     */
    private void InitSensors() {
        sensorManager=(SensorManager)getSystemService(SENSOR_SERVICE);//初始化传感器管理器
        sensor=sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);//给传感器初始化类型
    }

    /**
     * 函数功能:通过匿名内部类的方式实现按钮和传感器监听器接口,实现按钮和传感器的监听
     */
    private void setListener(){
        sensorEventListener=new SensorEventListener() {
            /**
             * 函数功能:重写传感器参数改变时实现的方法
             * @param event
             */
            @Override
            public void onSensorChanged(SensorEvent event) {
                String showInfo="";//用于存储传感器的光强信息
                showInfo="光照强度:"+event.values[0]+"勒克斯";
                try {
                    TransferToPython(event.values[0]);
                } catch (IOException e) {
                    e.printStackTrace();
                }
                showLightPower.setText(showInfo);//设置TextView的显示光线传感器光强信息
            }

            /**
             * 当传感器参数精度改变时,可以通过本方法实现
             * @param sensor
             * @param accuracy
             */
            @Override
            public void onAccuracyChanged(Sensor sensor, int accuracy) {

            }
        };
        //设置开始监听按钮被点击时实现注册传感器事件监听器
        start.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                sensorManager.registerListener(sensorEventListener,sensor, SensorManager.SENSOR_DELAY_FASTEST);//注册传感器
            }
        });
        //设置关闭监听按钮被点击时实现取消注册传感器事件监听器
        stop.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                sensorManager.unregisterListener(sensorEventListener);
            }
        });
    }

    /**
     * 函数功能:初始化控件
     */
    private void InitWidgets(){
        //获取textview和button的实例
        showLightPower=(TextView) findViewById(R.id.textView);
        start=(Button) findViewById(R.id.start);
        stop=(Button) findViewById(R.id.stop);

    }

    /*
    * 发送信息
    * */
    private void TransferToPython(Float num) throws IOException {
        System.out.println("发送端启动…………");
         /*
          * 1、创建udp传输的发送端
          2、建立UDP的socket的服务
          3、将要发送的数据封装到数据包中
          4、通过udp的socket服务将数据包发送出去
          5、关闭socket服务
          */

        //udpsocket服务,使用DatagramSocket对象
        DatagramSocket ds=new DatagramSocket(8888);//监听端口
        //将要发送的数据封装到数据包中
        String str = Float.toString(num);
        System.out.println(str);
        //使用DatagramPacket将数据封装到该对象中
        byte[] buf=str.getBytes();
        DatagramPacket dp=
                new DatagramPacket(buf, buf.length, InetAddress.getByName("192.168.2.117"),7789);
        //通过udp的socket服务将数据包发送出去,通过send方法
        ds.send(dp);
        //关闭资源
        ds.close();
    }
	}

注意点1:

在Android 4.0以上,网络连接不能放在主线程上,不然就会报错android.os.NetworkOnMainThreadException。但是4.0下版本可以不会报错。在Android 4.0以上,网络连接不能放在主线程上,不然就会报错android.os.NetworkOnMainThreadException。但是4.0下版本可以不会报错。

解决办法:

在Activity的onCreate()方法中加入这样一段代码,适用于网络请求数据量很小的话,如下

 if (android.os.Build.VERSION.SDK_INT > 9) {
            StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
            StrictMode.setThreadPolicy(policy);
        }

注意点2:

赋予网络通信权限

在AndroidMainfest.xml配置文件中添加以下配置

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

Python端:

import socket
import random
import time
udpsock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

tcpsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

udp_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
tcp_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
localaddr = ("", 7789)
udp_sock.bind(localaddr)
def funget():
    data = udp_sock.recvfrom(1024)
    data = data[0].decode(encoding='utf-8', errors='strict')
    data = str(data.replace("'b'", ''))
    print("接收到的数据:",data)
    return data

if __name__ == '__main__':
    while True:
        data=funget()
        time.sleep(5)

参考文章: https://blog.csdn.net/qq_29477223/article/details/81027716

end

评论