Android socket常见疑问总结



最近做Android客户端与物联网通信,总结一下.

本文将给出一种比较实用的框架,一个线程负责读取服务器的消息,一个线程向服务器发送消息。然后在一些常见疑惑上给出解释和一些其他值得一看的资料。


一、认识socket
什么是socket,在移动端我们通常使用http来访问服务器,因为http为弱连网(手机你懂得,要是2哥的网,哎……),http和socket的最大区别就是http为一次性请求,客户端请求一次服务器应答一次,而socket将保持与服务器的链接。socket多应用于强连网的情况下,比如聊天室等等。关于socket的详细讲解可以参见http://blog.csdn.net/siobhan/article/details/4277380,有比较详细的讲解,在此不再赘述。


二、利用socket进行通信
socket名称为套接字即IP+端口号,什么是端口?可以这么理解IP是网络上唯一识别你电脑的id,而端口是在你电脑上识别应用的id。所以在创建是有Socket s = new Socket("192.168.1.1",3000);创建一个socket信道,当你拿到socket的对象后便可以得到IO流进行数据的读写操作了。这里需要说明和将解的地方是,socket的数据传输是终端与服务端商定好的,在传输接收数据时,按商量好的数据形式读写,如你传一个string过来,我接收时也转换为string。下面程序为socket数据的线程类。

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;

import android.os.Handler;
import android.os.Looper;
import android.os.Message;
//此类实现Runable接口,实现run方法,注意在run方法中又起了一个线程
public class SocketThread implements Runnable {
	public  Handler revUIHandler; // 接受UI消息的handler
	private Handler handler;  //接收到服务器的消息后向UI发送消息的handler
	
	OutputStream os;
	InputStream in;
	
	public SocketThread(Handler handler){
		this.handler = handler;
	}
	
	@Override
	public void run() {
		try {  //此处可以定义一个常量IP,和端口,以便更改
			Socket socket = new Socket(Data.IP,Data.PORT);
			os = socket.getOutputStream();
			//br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
			in = socket.getInputStream();
			
			new Thread(){
				@Override
				public void run() {
					byte[] data = new byte[1024];
					int byteread = 0;
					try {
						while((byteread = in.read(data))!=-1){
							
							Message msg = new Message();
							msg.what=0x123;
							msg.obj = data;
							handler.sendMessage(msg);
						}
					} catch (IOException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				};
			}.start();
			//子线程handler的处理,固定形式------------
			Looper.prepare();
			revUIHandler = new Handler(){
				public void handleMessage(Message msg) {
					if(msg.what ==0x456){
						try {
							os.write((byte[])msg.obj);
						} catch (IOException e) {
							e.printStackTrace();
						}
					}
					
				};
			};
			
			Looper.loop();
<span style="white-space:pre">			</span>//---------------------------------------
		} catch (UnknownHostException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		
	}
}
上面程序中的run方法中又新开了一个线程,这个线程用于一直接收服务器的消息。这里的初学者容易费解的是while()方法,难道该线程在一直死循环?或者该线程读取一次数据while就跳出了,线程也就结束了,哪来一直接收服务器消息呢? 这里要明确的是read()方法的作用,read为阻塞读,也就是在没有检查到服务器发来数据时read方法将阻塞该线程,而有消息时将一次读取data数组这么长的数据,并执行一次while循环。由此可以看出read方法的使用必须放在子线程中。java文件读写可以参见http://blog.csdn.net/smartcat86/article/details/4085739/。当然有人会问这样的线程该如何结束,非阻塞socket编程http://blog.csdn.net/chjttony/article/details/7181427。

下面是UI线程类

public class MainActivity extends Activity {
	
	byte[] data;
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		handler = new Handler(){
			@Override
			public void handleMessage(Message msg) {
				if(msg.what==0x123){
					data = (byte[])msg.obj;
				}
			}
		};
		
		SocketThread socketThread = new SocketThread(handler);
		new Thread(socketThread).start();  //可以使用socketThread.revUIHandler   来向服务器发送消息
     }
}


三、关于数据的转换

有时我们规定传输的数据中有几个字节的头,而我们在收发消息时通常用byte数组来传输,这时就存在数据的转换问题,如int如何转换为byte数组:

/** 
 * int值转成4字节的byte数组 
 * @param num 
 * @return 
 */  
public static byte[] int2byteArray(int num) {  
    byte[] result = new byte[4];  
    result[0] = (byte)(num >>> 24);//取最高8位放到0下标  
    result[1] = (byte)(num >>> 16);//取次高8为放到1下标  
    result[2] = (byte)(num >>> 8); //取次低8位放到2下标   
    result[3] = (byte)(num );      //取最低8位放到3下标  
    return result;  
}  <pre name="code" class="java">/** 
 * 将4字节的byte数组转成int值 
 * @param b 
 * @return 
 */  

public static int toInt(byte[] bRefArr) {  //byte数组转换为int
    int iOutcome = 0;
    byte bLoop;

    for (int i = 0; i < bRefArr.length; i++) {
        bLoop = bRefArr[i];
        iOutcome += (bLoop & 0xFF) << (8 * i);
    }
    return iOutcome;
}

在程序中要转换的地方调用此静态方法即可。



上述如有错误还请各位看官不吝赐教。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值