java实现TCP客户端,连接成功后自动接收服务端的数据,数据包以AABB开头CCDD结尾
支持断开重连
package com.data.thread;
import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
import org.apache.log4j.Logger;
/**
* socket线程,客户端接收服务端数据,包以AABB开头CCDD结尾
*
* @author ls
*/
public class SocketThread extends Thread {
Logger logger = Logger.getLogger(SocketThread1.class.getName());
public boolean isRun = false;
public boolean isWork = false;
@Override
public void run() {
while (isRun) {
try {
sleep(1000L);
} catch (InterruptedException ex) {
return;
}
String hostname = "127.0.0.1"; // 服务器的地址
int port = 9090; // 服务器的端口号
InputStream inputStream = null;
DataInputStream dataInputStream = null;
Socket socket = null;
BufferedInputStream in = null;
try {
socket = new Socket(hostname, port);
socket.setSoTimeout(60000);
in = new BufferedInputStream(socket.getInputStream());
byte[] buffer = new byte[4096]; // 较大的缓冲区以减少读取次数
byte[] packetBuilder = new byte[0]; // 用于构建当前数据包的缓冲区
while (isWork) {
int bytesRead = in.read(buffer);
if (bytesRead == -1) {
break; // 远程主机已关闭连接
}
// 将新读取的数据添加到packetBuilder中
byte[] tempPacket = new byte[packetBuilder.length + bytesRead];
System.arraycopy(packetBuilder, 0, tempPacket, 0, packetBuilder.length);
System.arraycopy(buffer, 0, tempPacket, packetBuilder.length, bytesRead);
packetBuilder = tempPacket;
// 查找数据包
int startIndex = -1;
int endIndex = -1;
// 查找开始标记(AABB)
for (int i = 0; i <= packetBuilder.length - 4; i++) {
if (packetBuilder[i] == (byte) 0xAA && packetBuilder[i + 1] == (byte) 0xBB) {
startIndex = i;
break;
}
}
// 如果找到了开始标记,则查找结束标记(CCDD)
if (startIndex != -1) {
for (int i = startIndex + 2; i <= packetBuilder.length - 2; i++) {
if (packetBuilder[i] == (byte) 0xCC && packetBuilder[i + 1] == (byte) 0xDD) {
endIndex = i + 1; // 包括结束标记
break;
}
}
}
// 如果找到了完整的数据包,则处理它
if (startIndex != -1 && endIndex != -1) {
byte[] packet = new byte[endIndex - startIndex + 1];
System.arraycopy(packetBuilder, startIndex, packet, 0, packet.length);
logger.info("Received packet: " + bytesToHex(packet));
//todo:将数据放入缓存,用于数据处理
// 移除已处理的数据包,只保留剩余的数据
if (endIndex < packetBuilder.length) {
// endIndex 之后的长度是剩余数据的长度
int remainingLength = packetBuilder.length - endIndex;
// 如果剩余长度大于0,则创建新的数组并复制剩余数据
if (remainingLength > 0) {
byte[] newPacketBuilder = new byte[remainingLength];
System.arraycopy(packetBuilder, endIndex, newPacketBuilder, 0, remainingLength);
packetBuilder = newPacketBuilder;
} else {
// 如果没有剩余数据,则清空packetBuilder
packetBuilder = new byte[0];
}
} else {
// 如果endIndex正好是packetBuilder的末尾,那么也没有剩余数据
packetBuilder = new byte[0];
}
}
}
} catch (IOException e) {
logger.error("socket连接失败:" + e);
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException ex) {
logger.error(ex);
}
}
if (dataInputStream != null) {
try {
dataInputStream.close();
} catch (IOException ex) {
logger.error(ex);
}
}
if (socket != null) {
try {
socket.close();
} catch (IOException ex) {
logger.error(ex);
}
}
}
}
}
// 字节数组转换为十六进制字符串
private static String bytesToHex(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
sb.append(String.format("%02X ", b));
}
return sb.toString();
}
/**
* 停止采集
*/
public void stopCol() {
isRun = false;
isWork = false;
this.interrupt();
}
}