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

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

反过来网络处理程序应该在一个计时器上运行,以33Hz的或多或少的固定速率发送值和当前时间戳(可能有点快?嗯,我愿意接受10Hz的慢速,但是不比那慢)。 无论如何,当我测试这个时,我可以在计算机界面上看到数据几乎没有以每秒30的稳定速度进入,而是出现激增,有时甚至根本不会出现,并且整体累积相当延迟(即值越晚,它们进入的延迟越多)。 我知道网络中可能存在一些差异和一些滞后,但我至少会喜欢总体速度至少是正确的,即它不会变得越来越糟,我发送的时间越长。

考虑到这些设备都在一个普通的wifi网络上,并且我能够在没有任何延迟的情况下通过wifi传输1080pvideo,我相信该协议应该能够每30ms处理一个64字节的字符串而不会出现麻烦。 为了消除传感器读取器作为问题源,我做了一个最小的工作示例,它每30ms只发送一个字符串,没有任何传感器读数。 我基本上从各种stackoverflowpost中获取了这些代码,并对其进行了修改,直到它或多或少做了我想要的。 问题是网络接口在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 { 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(更新的第1代)上运行。 任何提示都表示赞赏,谢谢!

您可以使用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 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(); 

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