项目中要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" />