简介
____最近看Gem5,需要用到Linux系统下的一些回馈,为了简化分析,就想要直接把生成的数据文件下载到本地。搜索了几篇博客,大多是讲将文件从客户端发给云服务器的。我自己学习了一下,并且加以修改,写了一个简单的从服务端向客户端反馈文件的程序。
服务端思路:
服务端通过阻塞式接受请求获得连接,建立线程开始处理此请求。通过文件流的方式传输给客户端,这个过程可以放在对客户端发出的一系列请求之后,各位可以自行添加。
客户端思路:
由于本文是由服务端向客户端发文件,且必定需要收到一个文件,所以只需要在线性执行等待接收文件的过程即可,接收完再关闭连接。相对于服务端,客户端通过写入流,将文件保存到指定目录(若不存在则创建目录)的同名文件。
以下为代码实现
服务端源码
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.net.ServerSocket;
import java.net.Socket;
/**
* 文件传输server(由服务器发送)
*
* @author Walskor
* @Date 2020年3月28日
* @version 1.0
*/
public class Transfer_Server extends ServerSocket{
private static final int Server_PORT = 8888; //服务器端口
private ServerSocket server;
public Transfer_Server() throws Exception{
super(Server_PORT);
this.server = this;
}
public static void main(String[] args) {
System.out.println("Server starting...");
try {
Transfer_Server transfer = new Transfer_Server();
transfer.waiting();
if(transfer!=null) {
transfer.close();
}
} catch (Exception e) {
System.out.println("Error: "+ e.getMessage());
}
}
/**
* 等待连接
* @throws Exception
*/
public void waiting() throws Exception{
while(true) {
//当阻塞时接受新的连入请求
Socket client = this.accept();
//并建立新的线程进行处理
new Handler(client);
}
}
}
/**
* 线程处理类
* @author Walskor
*
*/
class Handler implements Runnable{
private String FileURL = null; //文件路径
private Socket socket;
private FileInputStream fileIn;
private DataOutputStream DataOUT;
public Handler(Socket client) {
this.socket = client;
new Thread(this).start();
}
@Override
public void run() {
try {
setFileURL("D:\\DownLoads\\Chrome\\161840230754060.doc ");
sendFile(FileURL); //传输文件
if(socket!=null) {
try {
socket.close();
} catch (Exception e) {
socket = null;
System.out.println("Finally error: "+e.getMessage());
}
}
} catch (Exception e) {
e.printStackTrace();
}
}//end run()
/**
* 向客户端传输文件
* @throws Exception
*/
private void sendFile(String url) throws Exception {
try {
File file = new File(url);
if(file.exists()) {
fileIn = new FileInputStream(file);
DataOUT = new DataOutputStream(socket.getOutputStream());
//文件名和长度
DataOUT.writeUTF(file.getName());
DataOUT.flush();
DataOUT.writeLong(file.length());
DataOUT.flush();
//开始传输文件
System.out.println("=========Start to transfer=========");
byte[] bytes = new byte[1024];
int length = 0;
long progress = 0;
while((length = fileIn.read(bytes, 0, bytes.length)) != -1) {
DataOUT.write(bytes, 0, length);
DataOUT.flush();
progress += length;
System.out.println("| "+(100*progress/file.length()) + "% |");
}
System.out.println();
System.out.println("=====File transferred successfully=====");
}
} catch (Exception e) {
e.printStackTrace();
}finally { //关闭数据流
if(fileIn != null) {
fileIn.close();
}
if(DataOUT != null) {
DataOUT.close();
}
}
}// end sendFile
public void setFileURL(String fileURL) {
FileURL = fileURL;
}
}
客户端源码
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.math.RoundingMode;
import java.net.Socket;
import java.text.DecimalFormat;
/**
* 文件传输Client(由服务器发送)
*
* @author Walskor
* @Date 2020年3月28日
* @version 1.0
*/
public class Transfer_Client extends Socket{
private static final String Server_IP = "localhost"; //服务端IP
private static final int Server_PORT = 8888; //服务端端口号
private Socket server;
private DataOutputStream outputStream;
/**'
* 构造函数
* 与服务器建立连接
* @throws Exception
*/
public Transfer_Client() throws Exception{
super(Server_IP , Server_PORT);
this.server = this;
this.outputStream = new DataOutputStream(
server.getOutputStream());
System.out.println("this cilent[port:"+this.getLocalPort()+"] attach to server successfully");
}
/**
* 发送参数
* @throws Exception
*/
public void send() throws Exception{
outputStream.writeUTF("假装这是一条有用的数据流");
//清空数据流
outputStream.flush();
}
/**
* 接收文件
* @throws Exception
*/
public void load() throws Exception{
Load_File load_File = new Load_File(this);
load_File.get();
System.out.println("end of load");
}
public static void main(String[] args) {
try {
Transfer_Client TC = new Transfer_Client();
TC.send();
TC.load();
//关闭数据流
if(TC.outputStream != null) {
try {
TC.outputStream.close();
} catch (Exception e) {
TC.outputStream = null;
e.printStackTrace();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
class Load_File{
private Socket socket;
public String fileName;
public long fileLength;
private DataInputStream diStream;
private FileOutputStream foStream;
private static DecimalFormat dFormat = null;
static {
dFormat = new DecimalFormat("#0.0");
dFormat.setRoundingMode(RoundingMode.HALF_UP);
dFormat.setMinimumFractionDigits(1);
dFormat.setMaximumFractionDigits(1);
}//设置数字格式,保留一位有效数字
public Load_File(Socket socket) {
this.socket = socket;
}
public void get() {
try {
diStream = new DataInputStream(socket.getInputStream());
//文件名和长度
fileName = diStream.readUTF();
fileLength = diStream.readLong();
File directory = new File("D:\\AAAA");
if(!directory.exists()) {
directory.mkdir();
}
File file = new File(directory.getAbsolutePath() + File.separatorChar + fileName);
foStream = new FileOutputStream(file);
//开始接收文件
byte[] bytes = new byte[1024];
int length = 0;
while((length = diStream.read(bytes, 0, bytes.length)) != -1) {
foStream.write(bytes, 0, length);
foStream.flush();
}
System.out.println("File received [ File Name: "+ fileName +" ] [ Size: " + getFormatFileSize(fileLength) + " ] ===");
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
if(foStream != null) foStream.close();
if(diStream != null) diStream.close();
socket.close();
} catch (Exception e2) {
e2.printStackTrace();
}
}// end try
}// end get
/**
* 格式化文件大小
* @param length
* @return
*/
private String getFormatFileSize(long length) {
double size = ((double) length) / (1 << 30);
if(size >= 1) {
return dFormat.format(size)+"GB";
}
size = ((double) length) / (1 << 20);
if(size >= 1) {
return dFormat.format(size)+"MB";
}
size = ((double) length) / (1 << 10);
if(size >= 1) {
return dFormat.format(size)+"KB";
}
return length+"B";
}
}
运行结果
服务端测试结果:1
客户端测试结果:
如果需要客户端向服务器的文件传输,推荐:
Java Socket实现文件传输
Java socket 简单实现向云服务器传输文件
为了方便演示效果,用了很小的文件 ↩︎