android 网络连接2:Scoket

Scoket用于在两个应用程序之间相互通信 android端主要要编写四个类,scoket管理类,通讯工具类,以及一个接收线程和一个发送线程来实现scoket通讯


package com.example.test;

import java.io.DataOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;

import android.util.Log;
/**
 * Socket客户端
 * 
 * @author 爱吃鱼的cat
 * @date 2015年1月30日 下午1:58:25
 */
public class SocketClient 
{
	private final String		TAG					= "SocketClient";
	/**
	 * 连接超时时间 30秒
	 */
	private final int 			mConnTimeout 		= 30*1000;
	public 	Socket 				mClientSocket 		= null;
	private InputStream 		mRecvFd;
	private OutputStream 		mOutputStream;
	private DataOutputStream 	mSendFd;
	
	/**
	 *  连接服务器
	 * @param serverIP
	 * @param nServerPort
	 * @return
	 * @author 爱吃鱼的cat
	 * @date 2015年1月30日 下午2:34:54
	 */
	public boolean connect(String serverIP, int nServerPort) 
	{
		try
		{
			Log.i(TAG, "服务器地址为: " + serverIP + ":" + nServerPort);
			InetSocketAddress isa = new InetSocketAddress(serverIP, nServerPort);
			mClientSocket = new Socket();
			mClientSocket.connect(isa, mConnTimeout);
		}
		catch(Exception e)
		{
			e.printStackTrace();
			mClientSocket = null;
			return false;
		}
		
		try
		{
			// 数据不作缓冲,立即发送 
			mClientSocket.setTcpNoDelay(true);
			// socket关闭时,立即释放资源 
			mClientSocket.setSoLinger(true, 0);
			mClientSocket.setKeepAlive(true);
			// 高可靠性和最小延迟传输 
			mClientSocket.setTrafficClass(0x04|0x10);

			if(mRecvFd != null)
			{
				mRecvFd.close();
				mRecvFd = null;
			}
			if(mOutputStream != null)
			{
				mOutputStream.close();
				mOutputStream = null;
			}
			if(mSendFd != null)
			{
				mSendFd.close();
				mSendFd = null;
			}
			// 建立数据流 
			mRecvFd = mClientSocket.getInputStream();
			mOutputStream = mClientSocket.getOutputStream();
			//将字符流转化成字节流进行传输
			//字符流-->DataOutputStream--> mOutputStream--> 字节流-->网络传输
			mSendFd = new DataOutputStream(mOutputStream);
		}
		catch(Exception e)
		{
			e.printStackTrace();
			try 
			{
				mClientSocket.close();
			}
			catch(Exception ee) 
			{
				ee.printStackTrace();
			}
			mClientSocket = null;
			return false;
		}
		return true;
	}
	
	/**
	 *  关闭与服务器的连接
	 * 
	 * @author 爱吃鱼的cat
	 * @date 2015年1月30日 下午2:35:02
	 */
	public void close() 
	{
		try
		{
			// 关闭输入流
			if(mSendFd != null) 
			{
				mSendFd.close();
				mSendFd = null;
			}
		}
		catch(Exception e) 
		{
			e.printStackTrace();
		}
		
		try
		{
			// 关闭输出流
			if(mRecvFd != null) 
			{
				mRecvFd.close();
				mRecvFd = null;
			}
		}
		catch(Exception e) 
		{
			e.printStackTrace();
		}
		
		try
		{
			// 关闭套接字
			if(mClientSocket != null) 
			{
				mClientSocket.close();
				mClientSocket = null;
			}
		}
		catch(Exception e) 
		{
			e.printStackTrace();
		}
		Log.i(TAG, "socket关闭成功!");
	}
	
	/** 
	 * 发送数据
	 * @param sendArray
	 * @return
	 * @author 爱吃鱼的cat
	 * @date 2015年1月30日 下午2:35:11
	 */
	public boolean send(byte[] sendArray) 
	{
		if(null == mClientSocket) 
		{
			Log.e(TAG, "当前未连接到服务器!");
			return false;
		}
		if(null == mSendFd)
		{
			Log.e(TAG, "当前输出流为空!");
			return false;
		}
		
		try
		{
			mSendFd.write(sendArray);
			mSendFd.flush();
			Log.i(TAG, "socket发送数据成功!");
			return true;
		}
		catch(Exception e) 
		{
			e.printStackTrace();
			return false;
		}
	}
	/**
	 * 接收数据
	 * @param RecvArray
	 * @return
	 * @throws Exception
	 * @author 爱吃鱼的cat
	 * @date 2015年1月30日 下午2:35:33
	 */
	public int read(byte[] RecvArray) throws Exception 
	{
		if(mClientSocket.isClosed() == false)
		{
			mClientSocket.setSoTimeout(1000*10);
			return mRecvFd.read(RecvArray);
		}
		return 0;
	}
	
	/**
	 *  获取套接字句柄
	 * @return
	 * @author 爱吃鱼的cat
	 * @date 2015年1月30日 下午2:36:06
	 */
	public Socket getClientSocket() 
	{
		return mClientSocket;
	}
	
	/**
	 *  设置套接字句柄
	 * @param socket
	 * @author 爱吃鱼的cat
	 * @date 2015年1月30日 下午2:36:10
	 */
	public void setClientSocket(Socket socket) 
	{
		this.mClientSocket = socket;
	}
}

package com.example.test;

import java.io.IOException;
import java.util.ArrayList;
import android.util.Log;
import com.sunnada.cumini.pack.InData;
import com.sunnada.cumini.pack.OutData;
import com.sunnada.cumini.pack.PacketManager;
/**
 * Socket缓存类
 * 
 * @author 爱吃鱼的cat
 * @date 2015年1月30日 下午2:08:59
 */
public class SocketBuffer 
{
	private static final String		TAG								= "SocketBuffer";
	private SocketClient 			mClientSocket;
	public static boolean 			mClientStart 					= false;
    
	// socket连接及发送和接收线程池,设为static类型,目的是所有对象实例共用一个
	public static SendThread 		mSendThread;
	public static RecvThread 		mRecvThread;
	
	//IP地址
	private String				mStrServerIP;
	//端口号
	private int				mServerPort;
	//是否已经连接
	private boolean 			mIsConnected 					= false;
	//重新连接的次数
	public int 				mReConnCount 					= 0;
	// 重置3G网络的次数
	public int 				mResetModemCount 				= 0;				

	// 发送和接收队列
	private ArrayList<byte[]> 		mInputArray 			= new ArrayList<byte[]>();
	private ArrayList<byte[]> 		mOutArray 			= new ArrayList<byte[]>();
	
	
	/**
	 *  设置连接状态
	 * @param connectStatus
	 * @author 爱吃鱼的cat
	 * @date 2015年1月30日 下午2:23:08
	 */
	public void setConnectStatus(boolean connectStatus) 
	{
		mIsConnected = connectStatus;
	}
	
	/**
	 *  建立socket连接并启动发送和接收线程
	 * @param strServerIP
	 * @param nServerPort
	 * @return
	 * @author 爱吃鱼的cat
	 * @date 2015年1月30日 下午2:23:18
	 */
	public synchronized boolean start(String strServerIP, int nServerPort) 
	{
		try 
		{
			mStrServerIP = strServerIP;
			mServerPort = nServerPort;
			
			/**
			 *  是否需要重新启动线程
			 */
			boolean bool_reTrhead = false;
			if (mClientSocket == null) 
			{
				mClientSocket = new SocketClient();
				bool_reTrhead = true;
			}
			//判断是否需要重新连接
			if (mClientSocket.getClientSocket() == null || 
					mClientSocket.getClientSocket().isConnected() == false || 
					mClientSocket.getClientSocket().isClosed() == true) 
			{
				mIsConnected = mClientSocket.connect(strServerIP, nServerPort);
				if(mIsConnected == false) 
				{
					mClientSocket = null;
					return false;
				}
				bool_reTrhead = true;
			}
			
			if (bool_reTrhead) 
			{
				mIsConnected = true;
				mClientStart = true;
				mSendThread = new SendThread(this);
				mSendThread.start();
				mRecvThread = new RecvThread(this);
				mRecvThread.start();
			}
			Log.i(TAG, "socket连接成功");
		} 
		catch (Exception e)
		{
			e.printStackTrace();
			mIsConnected = false;
		}
		return mIsConnected;
	}
	
	/**
	 *  重新建立socket连接,注意这里不重启线程
	 * @return
	 * @author 爱吃鱼的cat
	 * @date 2015年1月30日 下午2:30:38
	 */
	public synchronized boolean restartConn() 
	{
		// 由于加了同步锁,因此在这里需要判断一次是否已经连接完毕
		if(mIsConnected == true)
		{
			Log.v(TAG, "设备已经重连网络, 在此不再重连");
			return true;
		}

		try 
		{
			if(mClientSocket == null) 
			{
				mClientSocket = new SocketClient();
			}
			if(mClientSocket.getClientSocket() != null)
			{
				mClientSocket.getClientSocket().close();
			}
			
			try 
			{
				mClientSocket.connect(mStrServerIP, mServerPort);
				this.emptyReadBuff();
				this.emptySendBuff();
				
				mReConnCount = 0;
				mResetModemCount = 0;
				Log.i(TAG, "重连平台成功!");
				mIsConnected = true;
			}
			catch (Exception e) 
			{
				e.printStackTrace();
				mReConnCount++;
				mIsConnected = false;
			}
		}
		catch (Exception e) 
		{
			e.printStackTrace();
			mIsConnected = false;
		}
		return mIsConnected;
	}

	/**
	 *  停止socket连接,以及线程池
	 * @return
	 * @throws IOException
	 * @throws InterruptedException
	 * @author 爱吃鱼的cat
	 * @date 2015年1月30日 下午3:07:46
	 */
	public int stop()
	{
		try 
		{
			if (null != mClientSocket) 
			{
				mIsConnected = false;
				mClientStart = false;
				
				// 把指针清空
				if (mSendThread != null)
				{
					mSendThread = null;
				}
				if (mRecvThread != null)
				{
					mRecvThread = null;
				}
				mClientSocket.close();
				mClientSocket = null;
				return 0;
			} 
			return -1;
		}
		catch(Exception e) 
		{
			e.printStackTrace();
			return 1;
		}
	}
	
	/**
	 *  将数据包加到发送队列
	 * @param indata 发送信息格式的封装类
	 * @return
	 * @author 爱吃鱼的cat
	 * @date 2015年1月30日 下午3:08:44
	 */
	public boolean addSendBuff(InData indata) 
	{
		//主命令单元,子命令单元
		String cmd = indata.getId()+indata.getSubid();
		removeSameUnitInRecvBuff(cmd);
		
		byte[] szPacketOut = PacketManager.pack(indata);
		if(null == szPacketOut) 
		{
			return false;
		}
		addSendBuff(szPacketOut);
		return true;
	}
	
	public void addSendBuff(byte[] in) 
	{
		if(in != null) 
		{
			mInputArray.add(in);
		}
	}

	protected boolean addRecvBuff(byte[] outData) 
	{
		mOutArray.add(outData);
		return true;
	}

	public int getSendListCount() 
	{
		return mInputArray.size();
	}

	public int getRecvListCount() 
	{
		return mOutArray.size();
	}

	protected byte[] getSendBuff(int position) 
	{
		return mInputArray.get(position);
	}

	protected boolean removeSendBuff(byte[] inputData) 
	{
		return mInputArray.remove(inputData);
	}
	
	public OutData getRecvBuff(int argID) 
	{
		byte[] out = mOutArray.get(argID);
		this.removeRecvBuff(out);
		return PacketManager.Unpack(out);
	}
	
	/**
	 *  删除接收队列中过期的命令消息
	 * @param strCmdID
	 * @author 爱吃鱼的cat
	 * @date 2015年1月30日 下午3:35:32
	 */
	public void removeSameUnitInRecvBuff(String strCmdID) 
	{
		int t_size = mOutArray.size();
		if(t_size <= 0) 
		{
			return;
		}
		
		for (int i = 0; i < t_size; i++) 
		{
			byte[] out = mOutArray.get(i);
			
			OutData t = PacketManager.Unpack_2(out);
			if (strCmdID.equalsIgnoreCase(t.getId() + t.getSubid())) 
			{
				this.removeRecvBuff(out);
				Commen.printhax(out, out.length, "删除过时同命令消息", 'e');
				i--;
				t_size--;
			}
		}
	}
	
	public int getOrderBuffID(String strCmdID) 
	{
		int t_size = mOutArray.size();
		if (t_size <= 0) 
		{
			return -1;
		}
		
		for (int i = 0; i < t_size; i++) 
		{
			byte[] out = mOutArray.get(i);
			OutData t = PacketManager.Unpack_2(out);
			
			if (strCmdID.equalsIgnoreCase(t.getId() + t.getSubid())) 
			{
				return i;
			}
		}
		return -1;
	}

	protected boolean removeRecvBuff(byte[] outData) 
	{
		return mOutArray.remove(outData);
	}
	
	/**
	 *  清空发送队列
	 * 
	 * @author 爱吃鱼的cat
	 * @date 2015年1月30日 下午2:20:47
	 */
	public void emptySendBuff() 
	{
		mInputArray.clear();
	}
	
	/**
	 *  清空接收队列
	 * 
	 * @author 爱吃鱼的cat
	 * @date 2015年1月30日 下午2:20:53
	 */
	public void emptyReadBuff() 
	{
		mOutArray.clear();
	}
	
	// 获取套接字句柄
	public SocketClient getClientSocket() 
	{
		return mClientSocket;
	}
	
	// 获取连接状态
	public boolean getConnectStatus() 
	{
		return mIsConnected;
	}
	
	
}


package com.example.test;


import android.os.SystemClock;
import android.util.Log;

public class SendThread extends Thread 
{
	private static final String 		TAG = "socket发送";
	private SocketBuffer 				mSocketBuffer;
	private SocketClient 				mSocketClient;
	
	public SendThread(SocketBuffer socketBuffer) 
	{
		mSocketBuffer = socketBuffer;
		mSocketClient = socketBuffer.getClientSocket();
	}
	
	public void runs()
	{
		super.run();
		Log.d(TAG, "socket发送线程启动...");
		
		while(SocketBuffer.mClientStart) 
		{
			if(!mSocketBuffer.getConnectStatus()) 
			{
				mSocketBuffer.restartConn();
				//这种sleep方式不会被Thread.interrupt()所打断
				SystemClock.sleep(2000);
		    	continue;
			}
			
			if(mSocketBuffer.getSendListCount() <= 0) 
			{
				SystemClock.sleep(200);
				continue;
			}
			
			try
			{
				// 发送数据
				byte[] sendData = mSocketBuffer.getSendBuff(0);
				mSocketClient.send(sendData);
				// 从发送队列里移除数据包
				mSocketBuffer.removeSendBuff(sendData);
				Log.e(TAG, "消息密文发送结束, 待发送消息个数:" + (mSocketBuffer.getSendListCount()));
			}
			catch(Exception e) 
			{
				Log.e(TAG, "数据发送错误, 当前buffer中的待发送消息个数:" + mSocketBuffer.getSendListCount());
				mSocketBuffer.setConnectStatus(false);
				// 
				if(SocketBuffer.mClientStart == false)
				{
					break;
				}
				SystemClock.sleep(200);
				continue;
			}
		}
		Log.d(TAG, "socket发送线程退出");
	}
}

package com.example.test;

import java.net.SocketTimeoutException;

import android.os.SystemClock;
import android.util.Log;

public class RecvThread extends Thread 
{
	private static final String	TAG				= "socket接收";
	//开始标识
	private static final byte 	START_FLAG 		= 0x7E;
	//结束标识
	private static final byte 	END_FLAG 		= 0x7F;
	//最多接收字节
	private static final int 	MAX_RECV_LEN 	= 2*1024;
	
	private SocketBuffer 		mSocketBuffer;
	private SocketClient 		mSocketClient;
	private byte[] 				mRecvArray 		= new byte[MAX_RECV_LEN];
	private int 				mRecvArrayPos 	= 0;
	
	public RecvThread(SocketBuffer socketBuffer) 
	{
		mSocketBuffer = socketBuffer;
		mSocketClient = socketBuffer.getClientSocket();
	}
	
	public void runs() 
	{
		super.run();
		Log.d(TAG, "socket接收线程启动...");
		
		while (SocketBuffer.mClientStart) 
		{
			if(!mSocketBuffer.getConnectStatus()) 
			{
				SystemClock.sleep(500);
		    	continue;
			}
			
			// 先判断
			if(mSocketClient.getClientSocket() == null || mSocketClient.getClientSocket().isClosed()) 
			{
				Log.e(TAG, "网络连接异常, 准备重连");
				mSocketBuffer.setConnectStatus(false);
		    	SystemClock.sleep(500);
		    	continue;
			}
			
			try 
			{
				byte[] recvArray = new byte[1024];
				int readLen = mSocketClient.read(recvArray);
				if (readLen > 0) 
				{
					Log.e(TAG, "本次数据接收长度为: " + readLen);
					for (int i=0; i<readLen; i++) 
					{
						if ((recvArray[i] == START_FLAG)) 
						{
							newRecvBuff();
							setRecvByte(recvArray[i]);
						}
						else if ((recvArray[i] == END_FLAG)&& (mRecvArrayPos != 0)) 
						{
							setRecvByte(recvArray[i]);
							addRecvBuff(mRecvArray, mRecvArrayPos);
						} 
						else if (mRecvArrayPos != 0) 
						{
							setRecvByte(recvArray[i]);
						}
						else
						{
							
						}
					}
				}
				else if(readLen == -1)
				{
					Log.e(TAG, "数据接收错误");
					if(SocketBuffer.mClientStart == false)
					{
						mSocketBuffer.setConnectStatus(false);
						break;
					}
					SystemClock.sleep(200);
					continue;
				}
				else
				{
					// 如果没有消息,则间隔200毫秒收一次
					SystemClock.sleep(200);
				}
			}
			catch (Exception e) 
			{
				// 数据接收超时
				if(e instanceof SocketTimeoutException) 
				{
					continue;
				}
				else
				{
					e.printStackTrace();
					Log.e(TAG, "数据接收异常");
					mSocketBuffer.setConnectStatus(false);
				}
			}
		}
		Log.d(TAG, "socket接收线程退出");
	}
	
	private void setRecvByte(byte t) 
	{
		mRecvArray[mRecvArrayPos] = t;
		mRecvArrayPos++;
	}

	private void newRecvBuff() 
	{
		mRecvArray = new byte[MAX_RECV_LEN];
		mRecvArrayPos = 0;
	}

	private void addRecvBuff(byte[] t_RecvArray, int len) 
	{
		byte out[] = new byte[len];
		System.arraycopy(t_RecvArray, 0, out, 0, len);
		mSocketBuffer.addRecvBuff(out);
	}
}



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值