Android端的Socket通信TCP协议Demo

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



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值