需求:两端以TCP方式建立连接,分片传输文件;
思路:本端将大文件切片,并将文件名称、分片、文件大小、文件MD5、分片内容等信息,封装成一个对象,将对象转为字节数组,以字节流传输到对端;对端接收到字节数组后,转转为对象,再交给业务层处理数据;
接收线程:ReceiveTcpThread
package com.jzsg.ferry.thread;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
public class ReceiveTcpThread implements Runnable {
/**
* logger
*/
private static final Logger logger = LoggerFactory.getLogger(ReceiveTcpThread.class);
private final Socket s;
public ByteArrayInputStream bis = null;
public int num;
public ReceiveTcpThread(Socket s) {
this.s = s;
}
@SuppressWarnings("InfiniteLoopStatement")
@Override
public void run() {
try {
InputStream in = s.getInputStream();
logger.info("接收线程已启动");
DataInputStream dis = new DataInputStream(in);
logger.info("接收线程已启动");
while (true) {
int length = dis.readInt();
byte[] buf = new byte[length];
int bufSize = 2048;
int pos = 0;
int read = 0;
if (length < bufSize) {
read = dis.read(buf,pos,length);
} else {
while(true) {
int can = dis.available();
if (can > bufSize) {
read = dis.read(buf,pos,bufSize);
} else {
read = dis.read(buf,pos,can);
break;
}
pos = pos + read;
}
}
//交给业务层处理buf数组
logger.info("接收数据:" + Arrays.toString(buf));
}
} catch (IOException e) {
logger.error("socket异常:" + e.getMessage());
}
}
}
SendTcpThread 发送线程:
package thread;
import com.jzsg.common.pool.BussinessThreadPool;
import common.Converter;
import model.Student;
import org.apache.commons.lang3.ArrayUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import pool.FerryToolThreadPool;
import service.HandleDataService;
import util.PropertyUtil;
import java.io.*;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.concurrent.ConcurrentLinkedQueue;
public class SendTcpThread implements Runnable {
private static final Logger logger = LoggerFactory.getLogger(SendTcpThread.class);
public String destIp = PropertyUtil.getProperty("DEST_IP");
public Socket socket;
public OutputStream out = null;
public DataOutputStream dos = null;
protected volatile ConcurrentLinkedQueue<byte[]> dataQueue = new ConcurrentLinkedQueue<>();
public Socket getSocket() {
return socket;
}
public void setSocket(Socket socket) {
this.socket = socket;
}
@Override
@SuppressWarnings("InfiniteLoopStatement")
public void run() {
try {
int port = 9002;
//建立客户端Socket
InetSocketAddress endpoint = new InetSocketAddress(destIp , port);
socket = new Socket();
//连接服务器
socket.connect(endpoint);
setSocket(socket);
out = socket.getOutputStream();
//发送字节数组
dos = new DataOutputStream(out);
while (true) {
byte[] data = dataQueue.poll();
logger.info("dataQueue:" + dataQueue.size());
if (null == data || data.length <= 0) {
//没有发送数据则等待
toWait(dataQueue, 0);
} else {
logger.info("发送端的数据长度:" + data.length);
//发送字节数组长度
dos.writeInt(data.length);
dos.write(data);
dos.flush();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
} catch (IOException e) {
logger.error("socket连接异常", e);
FerryToolManager.getInstance().closeSendThread();
}
}
}
ListenerThread 监听线程:
package thread;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import pool.FerryToolThreadPool;
import state.HandleData;
import util.PropertyUtil;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class ListenerThread implements Runnable {
/**
* logger
*/
private static final Logger logger = LoggerFactory.getLogger(ListenerThread.class);
/**
* serverSocket
*/
private ServerSocket serverSocket = null;
//暴露接口,给业务层实现及调用;
private final HandleData handleData;
public ListenerThread(HandleData handleData) {
this.handleData = handleData;
}
@Override
@SuppressWarnings("InfiniteLoopStatement")
public void run() {
try{
int port = 9003;
serverSocket = new ServerSocket(port);
while(true){
//获取客户端Socket
Socket s = serverSocket.accept();
ReceiveTcpThread receiveTcpThread = new ReceiveTcpThread(s, handleData);
FerryToolManager.getInstance().add(receiveTcpThread);
FerryToolThreadPool.execute(receiveTcpThread);
}
} catch (IOException e) {
logger.info("监听线程启动异常",e);
}
}
}