项目中要Android端(客户端)写一个用Socket通信来控制嵌入式设备(穿梭车,穿梭车也是服务器),之间接发的信息都是十六进制的byte[]
另外需要一个TCP调试助手软件 可以百度下载
Demo的效果图:
Demo的代码结构图
写个Client的工具类,想法是写个线程一直循环读取服务器(穿梭车)时时刻刻发过来的数据包,然后写个发送数据包(指令)给穿梭车的线程,也是一直循环但是是处于等待状态,点击发送按钮的时候才唤醒然后执行,再写一个30秒给穿梭车发一次心跳包的线程。工作原理是读消息线程读取到消息后如果不为空就通知观察者,然后获取到读取的数据。代码如下:
TCPClient:
public class TCPClient extends Observable{ private static TCPClient tcp_client=null; private Socket socket; //输入流 private InputStream in; //输出流 private OutputStream out; //要发送的操作指令拼成的byte[] private byte[] sendContent=new byte[0]; //发送线程 private WriteThread writeThread=null; //用来存读取到的数据,观察者可以通过get方法获得 private byte[] byteresult=new byte[0]; public byte[] getByteresult() { return byteresult; } public void setByteresult(byte[] byteresult) { this.byteresult = byteresult; } public WriteThread getWriteThread() { return writeThread; } public void setWriteThread(WriteThread writeThread) { this.writeThread = writeThread; } public byte[] getSendContent() { return sendContent; } public void setSendContent(byte[] sendContent) { this.sendContent = sendContent; } public static synchronized TCPClient instance(String ip,int port){ if(tcp_client==null){ tcp_client=new TCPClient(ip,port); } return tcp_client; } public TCPClient(String ip,int port){ if(socket==null){ try { //初始化Socket socket=new Socket(ip,port); socket.setKeepAlive(true); //初始化输入流 in=socket.getInputStream(); //初始化输出流 out=socket.getOutputStream(); //创建socket连接后就开启接收数据线程 new ReadThread().start(); //创建socket连接后就开启发送数据的线程,一直在等待着被唤醒,点击发送按钮唤醒一次 writeThread=new WriteThread(); //开启发送心跳包的线程30秒发送一次心跳包 new HeartPackageThread().start(); } catch (UnknownHostException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } /** * 接收数据线程 * @author cxj * */ class ReadThread extends Thread{ @Override public void run() { // TODO Auto-generated method stub super.run(); try { while(true){ //一次读取1024个字节 byte[] b = new byte[1024]; int len=0; while((len=in.read(b))!=-1){ //得到读取到的有效长度数据 byte [] readDataLength=Arrays.copyOfRange(b, 0, len); if(0!=readDataLength.length){ byteresult=readDataLength; //通知观察者 setChanged(); //唤醒观察者 notifyObservers(); } } } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } } /** * 发送数据线程(一直开启,处于wait状态,要发送数据的时候唤醒) * @author cxj * */ public class WriteThread{ Thread write=null; HandleThread handleThread=null; String flag=""; WriteThread(){ if(null==write){ this.getHandleThreadInstance(); } } Thread getHandleThreadInstance(){ if(null==write){ if(null==handleThread){ handleThread=new HandleThread(); } write=new Thread(handleThread); write.start(); } return write; } class HandleThread implements Runnable{ @Override public void run() { // TODO Auto-generated method stub try { while(true){ synchronized (flag) { flag.wait(); Thread.sleep(500); //发送数据 out.write(getSendContent()); } } } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); }catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } //执行发送线程、唤醒 public void excute(){ synchronized (flag) { flag.notify(); } } } /** * 发送心跳包的线程 * @author cxj * */ class HeartPackageThread extends Thread{ @Override public void run() { super.run(); try { while(true){ //自己根据项目心跳包的格式发送(这里随便发了个数组) byte[] content=new byte[]{0x01,0x02}; out.write(content); //30秒发一次心跳包 Thread.sleep(30*1000); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } 观察者代码如下:
Watcher:
/** * 观察者类 * @author cxj * */ public class Watcher implements Observer{ private static Watcher watcher=null; //用来存接收到的数据,观察者被唤醒后外界可以通过get方法得到这个数据 public byte[] result=new byte[0]; public byte[] getResult(){ return result; } //读取数据线程接收到数据 在观察者的Update方法里面进行set赋值 public void setResult(byte[] result){ this.result=result; } public static synchronized Watcher instance(Observable o){ if(null==watcher){ watcher=new Watcher(o); o.addObserver(watcher); } return watcher; } public Watcher(Observable o){ o.addObserver(this); } @Override public void update(Observable o, Object arg) { //进行赋值 this.setResult(((TCPClient)o).getByteresult()); } } IpandPort类用来放些全局的变量:/** * 放全局的变量 * @author cxj * */ public class IpAndPort { //IP public static String IP="10.12.200.202"; //端口号 public static int PORT=1234; //TCPClient(被观察者) public static TCPClient tcp_client; //观察者 public static Watcher watcher; } xml布局: <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context="${relativePackage}.${activityClass}" > <TextView android:id="@+id/tv_showreceivedata" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/hello_world" /> <EditText android:id="@+id/et_sendcontent" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="50dp"/> <Button android:id="@+id/btn_send" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="20dp" android:text="发送"/> </LinearLayout> MainActivity代码: /** * * @author cxj * */ public class MainActivity extends Activity implements OnClickListener{ private TextView tv_showreceivedata; private EditText et_sendcontent; private Button btn_send; //接收到的数据处理后,观察者返回的 private byte[] resultByte=new byte[0]; //空的数组 用来把数组初始化 private byte[] initByte=new byte[0]; //接收成功 msg.what private final int RECEIVE_SUCCESS=0x01; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); } private Handler handler=new Handler(){ public void handleMessage(Message msg) { switch (msg.what) { case RECEIVE_SUCCESS: // tv_showreceivedata.setText(msg.obj.toString()); tv_showreceivedata.setText(Arrays.toString((byte[]) msg.obj)); break; } }; }; private void initView(){ tv_showreceivedata=(TextView) findViewById(R.id.tv_showreceivedata); et_sendcontent=(EditText) findViewById(R.id.et_sendcontent); btn_send=(Button) findViewById(R.id.btn_send); btn_send.setOnClickListener(this); //初始化Client initClient(); } /** * 初始化Client */ private void initClient(){ new Thread(new Runnable() { @Override public void run() { //创建Socket IpAndPort.tcp_client=TCPClient.instance(IpAndPort.IP, IpAndPort.PORT); //初始化观察者 IpAndPort.watcher=Watcher.instance(IpAndPort.tcp_client); while(true){ while(0==resultByte.length){ try { Thread.sleep(500); //观察者得到的数据 resultByte=IpAndPort.watcher.getResult(); } catch (InterruptedException e) { e.printStackTrace(); } } Message msg=handler.obtainMessage(); //接收成功 msg.what=RECEIVE_SUCCESS; msg.obj=resultByte; handler.sendMessage(msg); //观察者的TLV用完后,置空 IpAndPort.watcher.setResult(initByte); //置空 resultByte=initByte; } } }).start(); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.btn_send: String inputContent=et_sendcontent.getText().toString(); byte[] sendByte=inputContent.getBytes(); //设置发送内容 IpAndPort.tcp_client.setSendContent(sendByte); //发送线程执行 IpAndPort.tcp_client.getWriteThread().excute(); break; } } }
最后别忘了加上网络权限
<uses-permission android:name="android.permission.INTERNET" />