Android-Socket通信
Socket通信的应用
编写一个Socket连接的工具类SocketConnect,其中handle是用来传递连接状态的。
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketTimeoutException;
import android.os.Handler;
/**
* @author ${M.xang} 创建时间:2018-5-28 上午9:51:14 类描述 : socket连接类
*/
public class SocketConnect {
private static SocketConnect socketConnect;
private Socket socket;
private Handler mHandler;
private OutputStream out = null;
private InputStream in = null;
/** 接收tcp数据 */
private byte[] dataReceive = null;
private boolean isConnect = false;// 服务端连接是否已经建立
private boolean receiveFlag = true;// 接收数据线程标记
/**
* 获取单例
* @return
*/
public static SocketConnect getInit() {
if (socketConnect == null) {
socketConnect = new SocketConnect();
}
return socketConnect;
}
private SocketConnect() {
receiveFlag = true;
}
public Socket getSocket() {
return socket;
}
public byte[] getDataReceive() {
return dataReceive;
}
public void setDataReceive(byte[] dataReceive) {
this.dataReceive = dataReceive;
}
/**
* Socket是否连接标记
* @return
*/
public boolean getConnectState() {
return isConnect;
}
/**
* 在每进入一个Activity后,要先传送本界面使用的Handler类型实例
* @param mainHandler
*/
public void setHandler(Handler mainHandler) {
mHandler = mainHandler;
}
/**
* 建立服务器连接
*
* @param IP
* String IP地址
* @param port
* int 端口号
*/
public void setConnect(final String IP, final int port) {
new Thread(new Runnable() {
@Override
public void run() {
try {
closeSocket();
if (socket == null) {
socket = new Socket();
socket.connect(new InetSocketAddress(IP, port), 15000);
Thread.sleep(50, 0); // 实际中刚连上后发数据需要一定延时 确保双方链接初始化完成
}
if (out == null) {
out = new DataOutputStream(socket.getOutputStream());
}
if (in == null) {
in = new DataInputStream(socket.getInputStream());
}
isConnect = true;
mHandler.sendEmptyMessage(AppData.LAN_CONNECT); // 将标题颜色设为绿色
receiveFlag = true;
Thread.sleep(50);
receiveData();// 接收线程
} catch (SocketTimeoutException se) {
// 超时,红色点闪烁
mHandler.obtainMessage(AppData.LAN_TIME_OUT).sendToTarget();
} catch (IOException e) {
// 网络中断连接,红色点闪烁
mHandler.obtainMessage(AppData.LAN_INPERRUPT).sendToTarget();
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
/**
* 关闭socket
*/
public void closeSocket() {
try {
if (in != null) {
in.close();
in = null;
}
if (out != null) {
out.close();
out = null;
}
if (socket != null) {
socket.close();
socket = null;
}
isConnect = false;
receiveFlag = false;
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 发送数据
* @param controlId
* @param IP
* @param data
*/
public void sendData(final int controlId, final byte[] IP, final byte[] data) {
new Thread(new Runnable() {
public void run() {
try {
byte[] temp = SocketUtil.getInit().makePocket(controlId, IP, data);
if (out != null) {
out.write(temp);
out.flush();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
/**
* 接收数据线程
*/
public void receiveData() {
new Thread(new Runnable() {
public void run() {
try {
while (receiveFlag) {
if (isConnect) {
Thread.sleep(20);
if (in != null) {
if (in.available() > 0) {
Thread.sleep(100);
int backLength = in.available();
dataReceive = new byte[backLength];
int len = 0;
while (len < backLength) {
len += in.read(dataReceive, len, backLength - len);
}
setDataReceive(dataReceive);
MainActivity.ProcessReceievData();// 接收到的数据返回到mainActivity处理
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
}
在Activity中的调用:
首先获取Socket对象,如果没有建立连接,则打开连接线程,建立Socket连接。
/**
* 建立Socket连接
*/
private void initSocket() {
ip = SPUtil.getIP();
port = SPUtil.getPort();
socketConnect = SocketConnect.getInit();// 获取Socket单例对象
socketConnect.setHandler(mainHandler);
if (!socketConnect.getConnectState()) {
// 如果Socket没有连接
connectThread();
}
// TODO 心跳包 68 17 20 30 20 40 02 68 00 00 99 16
heartThread();
}
connectThread():开辟个线程建立连接
/**
* 建立服务器Socket连接
*/
private void connectThread() {
new Thread(new Runnable() {
public void run() {
try {
socketConnect.setConnect(ip, port);
Thread.sleep(3000);
if (socketConnect.getConnectState()) {
mainHandler.sendEmptyMessage(AppData.LAN_CONNECT); // 将标题颜色设为绿色
localIp = SystemUtil.getIP(MainActivity.this);
} else {
mainHandler.sendEmptyMessage(6); // 将标题颜色设为红色
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
heartThread():心跳,每5秒发送一次心跳包,没有接收到服务端返回的心跳应答数据,三次没接收到则进行重新建立连接。
/**
* 开启心跳包的线程
*/
private void heartThread() {
new Thread(new Runnable() {
int heartCount = 0;// 接收心跳的等待次数,一次5秒
public void run() {
try {
while (true) {
Thread.sleep(1000);
if (heartCount == 3) {
connectThread();// 重新建立Socket连接
heartCount = 0;
heartFlag = true;
heartThread();
break;
}
if (socketConnect.getSocket() != null) {
// Log.w("心跳包数据", "-----发送心跳数据=-----" + heartCount);
SocketUtil.getInit().sendHeartData(localIp);// 发送心跳数据
}
if (heartFlag) {
heartCount = 0;
if (socketConnect.getConnectState()) {
mainHandler.sendEmptyMessage(AppData.LAN_CONNECT); // 将标题设为绿色
} else {
mainHandler.sendEmptyMessage(6); // 将标题颜色设为红色
}
} else {
mainHandler.sendEmptyMessage(6); // 将标题颜色设为红色
}
heartCount++;
heartFlag = false;
Thread.sleep(4000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
mainHandler:用来展示连接状态
/**
* 网络连接提示语
*/
private Handler mainHandler = new Handler() {
public void handleMessage(Message msg) {
switch (msg.what) {
case AppData.LAN_CONNECT:
// MyToast.showToast(MainActivity.this, "连接成功!");
img.setImageDrawable(getResources().getDrawable(R.drawable.blue));// 连接成功,蓝色点闪烁
break;
case AppData.LAN_TIME_OUT:
connectThread();// 连接服务器
MyToast.showToast(MainActivity.this, "连接超时!");
img.setImageDrawable(getResources().getDrawable(R.drawable.red));// 连接超时,红色点闪烁
break;
case AppData.LAN_INPERRUPT:
MyToast.showToast(MainActivity.this, "连接异常,请检查网络连接!");
img.setImageDrawable(getResources().getDrawable(R.drawable.red));// 连接异常,红色点闪烁
break;
case 6:// 连接断开(心跳包不正常),将标题设为红色
img.setImageDrawable(getResources().getDrawable(R.drawable.red));// 连接异常,红色点闪烁
break;
default:
break;
}
};
};