一、实验要求
1、在客户端,用户选择本地的某个文件,并发送到服务器端。在服务器端,接收客户端传输的数据流,并按 IP 地址保存在服务器端(文件名重复的,可以覆盖)。2、如果传输过程中服务器端发现客户端断开,服务器端应删除文件,并在屏幕上提示,如“ IP:1.2.3.4发来 abcd.txt 文件过程中失去连接。”。如果客户端发现服务器端不工作,客户端应有提示“服务器 1.2.3.5:62345 失去连接”。
Java实现 Windows Socket编程 UDP实现大文件的传输参考:
http://blog.csdn.net/qq_24874985/article/details/71305799
二、C/S嵌套字面向TCP的传输流程
![](https://img-blog.csdn.net/20170506232143779?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMjQ4NzQ5ODU=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
三、具体源码
1、Server端
package indi.tangkai.internet.tcp;
import java.net.*;
import java.io.*;
public class Server extends Thread {
private String dir;// 文件保存路径,在main函数中设置
private int port;// Socket服务器的端口
public Server(String dir, int port) {
this.dir = dir;
this.port = port;
}
@SuppressWarnings("resource" )
@Override
public void run()
{
Socket socket = null;
DataInputStream input = null;//这里将socket监听到的数据流作为数据的输入流
DataOutputStream fileOut = null;//文件输出流
DataOutputStream ack = null;//作为对client数据传输成功的响应
int bufferSize = 8192;
byte[] buf = new byte[bufferSize];//数据存储
long donelen = 0;//传输完成的数据长度
long filelen = 0;//文件长度
try{
System.out.println("等待连接");
ServerSocket listen = new ServerSocket(port);//设置端口监听器,在监听到客户端之前,一直堵塞
do{
socket = listen.accept();
System.out.println("客户端"+ socket.getInetAddress() +"已连接");
//将socket数据作为数据输入流
input = new DataInputStream(
new BufferedInputStream(socket.getInputStream()));
//以客户端的IP地址作为存储路径
String fileDir = dir + "\\" + socket.getInetAddress().toString().substring(1, socket.getInetAddress().toString().length());;
File file = new File(fileDir);
//判断文件夹是否存在,不存在则创建
if(!file.exists())
{
file.mkdir();
}
String fileName = input.readUTF();//读取文件名
//设置文件路径
String filePath = fileDir + "\\" + fileName;
file = new File(filePath);
if(!file.exists())
{
file.createNewFile();
}
fileOut = new DataOutputStream(
new BufferedOutputStream(new FileOutputStream(file)));
filelen = input.readLong();//读取文件长度
System.out.println("文件的长度为:" + filelen + "\n");
System.out.println("开始接收文件!" + "\n");
ack = new DataOutputStream(socket.getOutputStream());
while (true) {
int read = 0;
if (input != null) {
read = input.read(buf);
ack.writeUTF("OK");//结束到数据以后给client一个回复
}
if (read == -1) {
break;
}
donelen += read;
// 下面进度条本为图形界面的prograssBar做的,这里如果是打文件,可能会重复打印出一些相同的百分比
System.out.println("文件接收了" + (donelen * 100 / filelen)
+ "%\n");
fileOut.write(buf, 0, read);
}
if(donelen == filelen)
System.out.println("接收完成,文件存为" + file + "\n");
else
{
System.out.printf("IP:%s发来的%s传输过程中失去连接\n",socket.getInetAddress(),fileName);
file.delete();
}
ack.close();
input.close();
fileOut.close();
}while(true);
}catch (Exception e) {
System.out.println("接收消息错误" + "\n");
e.printStackTrace();
return;
}
}
public static void main(String[] args) {
Server server = new Server("E:\\test\\download\\tcp\\", 8880);
server.start();
}
}
2、client端
package indi.tangkai.internet.tcp;
import java.net.*;
import java.io.*;
public class Client
{
// 上传的文件保存路径,可在main中修改
private String dir;
// socket服务器地址和端口号
private String host;
private int port;
public Client(String dir, String host, int port)
{
this.dir = dir;
this.host = host;
this.port = port;
}
public void uploadFile(String fileName)
{
Socket socket = null;
DataInputStream input = null;//文件输入流
DataOutputStream output = null;
DataInputStream getAck = null;//获得服务器的ACK
int bufferSize = 8192;
byte[] buf = new byte[bufferSize];//数据存储
try{
socket = new Socket(host, port);//设置socket,并进行连接connect
// 选择进行传输的文件
File file = new File(dir + fileName);
System.out.println("文件长度:" + (int) file.length());
input = new DataInputStream(new FileInputStream(dir + fileName));
output = new DataOutputStream(socket.getOutputStream());//将socket设置为数据的传输出口
getAck = new DataInputStream(socket.getInputStream());//设置socket数据的来源
//将文件名传输过去
output.writeUTF(file.getName());
output.flush();
//将文件长度传输过去
output.writeLong((long) file.length());
output.flush();
int readSize = 0;
while(true)
{
if(input != null)
{
readSize = input.read(buf);
}
if(readSize == -1)
break;
output.write(buf, 0, readSize);
if(!getAck.readUTF().equals("OK"))
{
System.out.println("服务器"+ host + ":" + port + "失去连接!");
break;
}
}
output.flush();
// 注意关闭socket链接哦,不然客户端会等待server的数据过来,
// 直到socket超时,导致数据不完整。
input.close();
output.close();
socket.close();
getAck.close();
System.out.println("文件传输完成");
}catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args)
{
Client client=new Client("E:\\test\\upload\\","127.0.0.1",8880);
client.uploadFile("test.rar");
}
}
四、代码运行结果示例图
1、server端
2、client端