繁体   English   中英

通过TCP / IP从Droid发送恒定速率的数据流

[英]Sending a constant rate data stream from Droid via TCP/IP

在学习Java / Android开发的过程中,我遇到了很多障碍。 主要是因为我对线程/进程之间的线程和通信不是很了解。 我正在尝试将IMU数据从android设备流式传输到计算机上的python应用程序。 只要传感器值发生变化,传感器侦听器就会将当前值保存到变量中,以供网络处理程序访问。

反过来,网络处理程序应该在计时器上运行,以大约33Hz的固定速率发送值和当前时间戳(也许有点快?好吧,我愿意接受低至10Hz的速度,但是不比这慢)。 无论如何,当我对此进行测试时,我可以在计算机界面上看到数据并不是以每秒30的稳定速度接近,而是以激增的速度出现,有时甚至一秒钟都没有出现,并且总体上在累积相当延迟(即值越晚,它们进入的延迟就越多)。 我知道网络中可能存在一些可变性和一些滞后,但是我至少希望总体速度至少是正确的,即,我发送的时间越长,情况就不会越来越糟。

考虑到这些设备都在通用的wifi网络上,并且我能够流传输1080p视频而没有wifi上的任何滞后,我非常有信心该协议应该能够每30ms处理一次64字节的字符串而不会遇到麻烦。 为了消除将传感器读取器视为问题源,我制作了一个最小的工作示例,该示例仅每30ms发送一次字符串,而没有读取任何传感器。 我基本上从各种stackoverflow帖子中获得了这段代码,并对其进行了修改,直到它或多或少地满足了我的要求。 问题是网络接口在AsynchronousTask中运行,我不确定如何在启动后访问它。 我的理论是浪费资源来为每个新数据包打开一个新的套接字,但是我不确定如何在后台打开一次套接字,然后在计时器上将值传递给它并告诉它发送。

这是我测试的基本活动:

package com.jamesdoesntlikejava.motionlearning15;

import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;
import java.util.Timer;
import java.util.TimerTask;


public class SendValuesActivity extends ActionBarActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_send_values);
        // creating timer task, timer
        final Timer timer = new Timer();
        TimerTask taskNew = new TimerTask() {
            @Override
            public void run() {
                int counter = 0;
                int numsteps = 333;
                String params[] = new String[2];
                if (counter < numsteps) {
                    params[0] = "192.168.1.33";
                    long currentTime = System.currentTimeMillis();
                    params[1] = Long.toString(currentTime)+"blablabla";
                    new ServerCommunicationTask().execute(params);
                    counter++;
                } else  {
                    timer.cancel();
                    timer.purge();
                }
            }
        };
        // scheduling the task at fixed rate delay
        Toast.makeText(this, "Sending Values in 1s...", Toast.LENGTH_SHORT).show();
        timer.scheduleAtFixedRate(taskNew,1000,30);
    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_send_values, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }
}

这是进行网络连接的类:

package com.jamesdoesntlikejava.motionlearning15;

import android.os.AsyncTask;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.net.UnknownHostException;

public class ServerCommunicationTask extends AsyncTask<String, Void, String> {

    public final static int TCP_SERVER_PORT = 13337;
    // params are 0: the target IP and 1: the message to send.
    @Override
    protected String doInBackground(String[] params) {

        String TCP_SERVER_IP = params[0];
        try {
            Socket s = new Socket(TCP_SERVER_IP, TCP_SERVER_PORT);
            BufferedWriter out = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
            //send output msg
            String outMsg = params[1];
            out.write(outMsg);
            out.flush();
            //close connection
            s.close();
        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return "success";
    }

    @Override
    protected void onPostExecute(String response) {
    }
}

在装有Android 5.1的Moto G LTE(第一代更新)上运行。 任何提示表示赞赏,谢谢!

可以使用Thread来代替AsyncTask并始终打开新连接。

import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.ArrayList;

public class ServerCommunicationThread extends Thread {

    public final static int TCP_SERVER_PORT = 13337;

    private ArrayList<String> mMessages = new ArrayList<>();
    private String mServer;

    private boolean mRun = true;

    public ServerCommunicationThread(String server) {
        this.mServer = server;
    }

    @Override
    public void run() {

        while (mRun) {
            Socket s = null;
            try {
                s = new Socket(mServer, TCP_SERVER_PORT);
                BufferedWriter out = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));

                while (mRun) {
                    String message;

                    // Wait for message
                    synchronized (mMessages) {
                        while (mMessages.isEmpty()) {
                            try {
                                mMessages.wait();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                        // Get message and remove from the list
                        message = mMessages.get(0);
                        mMessages.remove(0);
                    }

                    //send output msg
                    String outMsg = message;
                    out.write(outMsg);
                    out.flush();
                }

            } catch (UnknownHostException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                //close connection
                if (s != null) {
                    try {
                        s.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    public void send(String message) {
        synchronized (mMessages) {
            mMessages.add(message);
            mMessages.notify();
        }
    }

    public void close() {
        mRun = false;
    }
}

您可以在连接打开的情况下保持线程运行,并在需要时发送消息。

ServerCommunicationThread thread = new ServerCommunicationThread("192.168.1.33");
thread.start();
...
thread.send("blablabla");
...
thread.send("blablabla");
...
thread.close();

请注意,此代码未经测试。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM