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);
}
}