第一次使用socket进行文件传输,也踩了不少的小坑,不起眼但是会导致出现错误,记录一下踩坑经历。
1、application.yml文件路径设置为List集合
file:
files[0]:
sendPath: F:\fileTest\plmail\YWSQ
receivePath: F:\fileTest\ecar\YWSQ
suffix: _ok.txt
files[1]:
sendPath: F:\fileTest\plmail\FGYD
receivePath: F:\fileTest\ecar\FGYD
suffix: _ok.txt
2、创建一个实体类存放配置,方便调用
关于@ConfigurationProperties的用法参考:https://www.cnblogs.com/lihaoyang/p/10223339.html
@Data
public class AddrInfo {
private String sendPath;
private String receivePath;
private String suffix;
}
@Data
@Component
@ConfigurationProperties(prefix = "file")
public class ECarConfig {
private List<AddrInfo> files;
}
3、socket的客户端。服务器上如果开了防火墙,只允许特定端口访问的时候,需要设置端口复用,因为每一次访问都是socket动态分配端口,会被防火墙拦截。
package gdems.com.transfer.ecar.config;
import com.alibaba.fastjson.JSON;
import gdems.com.transfer.ecar.TransParameter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import java.io.*;
import java.net.InetSocketAddress;
import java.net.Socket;
/**
* @Auther:zjt
* @Description:socket客户端
*/
public class ECarClient extends Socket {
private static final Logger logger = LoggerFactory.getLogger(ECarClient.class);
private Socket socket;
private FileInputStream fileInputStream;
private DataOutputStream dataOutputStream;
@Value("${local.port}")
private int outPort;
//创建客户端,并指定接收的服务端IP和端口号
public ECarClient(String serverIp, int port) {
this.socket = new Socket();
try {
//socket设置端口复用
this.socket.setReuseAddress(true);
this.socket.bind(new InetSocketAddress(outPort));
this.socket.connect(new InetSocketAddress(serverIp, port));
} catch (IOException e) {
e.printStackTrace();
try {
this.socket.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
logger.info("成功连接服务端=====IP:" + serverIp + "端口号:" + port);
}
private ECarClient() throws IOException {
}
public boolean sendFile(File file, String receiveAddr) throws IOException {
try {
fileInputStream = new FileInputStream(file);
dataOutputStream = new DataOutputStream(socket.getOutputStream());
DataInputStream dataInputStream = new DataInputStream(socket.getInputStream());
//文件名、大小属性等
/*
省略部分:
1、获取文件上级目录
2、获取文件夹名称
3、最终获取后缀
*/
dataOutputStream.writeUTF(JSON.toJSONString(new TransParameter(suffix, file.getName(), receiveAddr)));
dataOutputStream.flush();
dataOutputStream.writeLong(file.length());
dataOutputStream.flush();
//开始传输文件
logger.info("======== 开始传输文件 ========");
//分包传送,最后判断传输的大小是否与文件大小相同,以此来判断是否传输结束
byte[] bytes = new byte[1024];
int length = 0;
boolean responseCode = false;
while ((length = fileInputStream.read(bytes, 0, bytes.length)) != -1) {
dataOutputStream.write(bytes, 0, length);
dataOutputStream.flush();
}
//需要释放socket的输出流,以便之后接收服务端的数据回传
socket.shutdownOutput();
String response = dataInputStream.readUTF();
//服务端回传的接收状态,可在服务端自行修改回传的内容
if (!"".equals(response)) {
responseCode = "OK".equals(response);
}
return responseCode;
} catch (Exception e) {
e.printStackTrace();
logger.info("客户端文件传输异常============" + e);
return false;
} finally {
fileInputStream.close();
dataOutputStream.close();
}
}
}
4、socket的服务端。
package gdems.com.transfer.ecar.config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
/**
* @Auther:zjt
* @Date: 2021/9/7 17:43
* @Description:socket服务端
*/
@Component
public class ECarFileServer implements Runnable {
private static final Logger logger = LoggerFactory.getLogger(ECarFileServer.class);
private static int SERVER_PORT = 9111; // 服务端端口
private static ServerSocket server;
private String url;
public ECarFileServer() {
try {
if (server == null) {
server = new ServerSocket(SERVER_PORT);
}
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("========ServerSocket:" + server.toString());
}
public ECarFileServer(String url) {
this.url = url;
}
@Override
public void run() {
try {
while (true) {
logger.info("=========端口号:" + SERVER_PORT + "等待连接 ========");
Socket socket = server.accept();
//这里的run是一个方法,不是线程的启动
new ECarTransfer(socket).run();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
package gdems.com.transfer.ecar.config;
import com.alibaba.fastjson.JSON;
import gdems.com.transfer.ecar.TransParameter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
/**
* @Auther:
* @Date: 2021/9/23 16:55
* @Description:
*/
public class ECarTransfer implements Runnable {
private static final Logger logger = LoggerFactory.getLogger(ECarFileServer.class);
private Socket socket;
private DataInputStream dataInputStream;
private DataOutputStream dataOutputStream;
private FileOutputStream fileOutputStream;
public ECarTransfer(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
logger.info("ip" + socket.getInetAddress() + "已连接");
dataInputStream = new DataInputStream(socket.getInputStream());
dataOutputStream = new DataOutputStream(socket.getOutputStream());
String content = dataInputStream.readUTF();
TransParameter transParameter = JSON.parseObject(content, TransParameter.class);
//传输文件地址后缀(省略)
//根据文件路径和文件的后缀,匹配(省略)
fileOutputStream = new FileOutputStream(file);
logger.info("======== 开始接收文件 ========");
byte[] bytes = new byte[1024];
int length = 0;
while ((length = dataInputStream.read(bytes, 0, bytes.length)) != -1) {
fileOutputStream.write(bytes, 0, length);
fileOutputStream.flush();
}
dataOutputStream.writeUTF("OK");
logger.info("======== 文件接收成功 [File Name:" + transParameter.getFileName() + "] ");
}
} catch (Exception e) {
logger.info("ECarServer is error ===== " + e);
e.printStackTrace();
} finally {
try {
if (fileOutputStream != null)
fileOutputStream.close();
if (dataInputStream != null)
dataInputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
@Data
@EqualsAndHashCode
@NoArgsConstructor
public class TransParameter implements Serializable {
private String suffix;
private String fileName;
private String receiveAddr;
public TransParameter(String suffix,String fileName,String receiveAddr) {
this.suffix = suffix;
this.fileName = fileName;
this.receiveAddr = receiveAddr;
}
}
5、编写一个配置类便于启动客户端和服务端
package gdems.com.transfer.ecar.controller;
import gdems.com.transfer.ecar.config.AddrInfo;
import gdems.com.transfer.ecar.config.ECarClient;
import gdems.com.transfer.ecar.config.ECarConfig;
import gdems.com.transfer.ecar.util.FileUtil;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RestController;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
/**
* @Auther:zjt
* @Date: 2021/9/8 16:40
*
*/
@Component
@EnableScheduling
@Slf4j
public class ECarTrafficController {
//服务器ip
@Value("${receiver.address}")
private String receiverAddress;
//服务器port
@Value("${socket.port}")
private int socketPort;
//定时器是否开启
@Value("${trafficTimerOpen}")
private boolean trafficTimerOpen;
@Autowired
private ECarConfig eCarConfig;
@Scheduled(cron = "${scheduled.cron}")
public void pushFile() {
if (trafficTimerOpen) {
numberPlateApplication();
}
}
public void numberPlateApplication() {
try {
for (AddrInfo addrInfo : eCarConfig.getFiles()) {
String sendPath = addrInfo.getSendPath();
String receivePath = addrInfo.getReceivePath();
String suffix = addrInfo.getSuffix();
//连接上本地服务器,获取文件
File[] fileArray = FileUtil.getFileArray(sendPath);
ArrayList<File> resultFiles = new ArrayList<>(Arrays.asList(fileArray));
resultFiles.removeIf(f -> !f.getName().endsWith(suffix));
if (resultFiles.size() > 0) {
log.info("开始推送===== " + sendPath + " 文件");
for (File file : fileArray) {
//调用socket文件流传送文件
ECarClient eCarClient = new ECarClient(receiverAddress, socketPort);
boolean isTrans = eCarClient.sendFile(file, receivePath);
if (isTrans) {
boolean delete = file.delete();
log.info(file.getAbsolutePath() + "删除" + delete);
}
}
} else {
log.info("===== " + sendPath + " 暂无数据推送=====");
}
}
} catch (IOException e) {
log.info("TRAFFIC push files to EMS is IOException: " + e.getMessage());
} catch (Exception e) {
log.info("TRAFFIC push files to EMS is Exception: " + e.getMessage());
}
}
}
网友评论