一.TCP传输数据
1.TCP和UDP的区别
UDP是无连接的, 指定地址和端口后就可以发送, 数据不安全, 速度快.
TCP是面向连接的, 区分客户端和服务端, 数据安全.
2.上传文件
服务端:
0.创建upload文件夹
1.创建ServerSocket, 在循环中等待和客户端请求, 每收到一个请求, 开启一条新线程.
5.获取输入输出流
7.接收文件名, 接收文件大小, 判断upload文件夹中该文件是否存在
8.如果存在, 发送提示消息到客户端, 服务端return
9.如果不存在, 发送提示消息到客户端
13.接收客户端传输数据, 从Socket中读取数据, 写出到文件中
客户端:
2.创建BufferedReader, 从键盘接收一个文件路径, 验证是否合法
3.创建Socket, 连接服务端
4.获取输入输出流
6.将文件名发送到服务端, 将文件大小发送到服务端
10.接收提示消息, 判断是否存在
11.如果存在, 在客户端打印提示, return
12.如果不存在, 开始上传, 从文件中读取, 写出到Socket中
二.telnet使用
1.设置回显
telnet - 回车
set localecho - 回车
quit - 回车
2.使用
telnet 地址 端口 - 回车
ctrl + ] - 回车
输入数据
注意:
telnet是逐个字符发送的, 输入一个字符就发送一个字符
三.多线程文件上传及断点续传
源代码:
客户端Client
package cn.base24.tcp;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;
import java.net.UnknownHostException;
/*
* 版本v2.0:(add:断点续传)
* 使用TCP传输文件的客户端:
*/
public class FileUploadClient2 {
public static void main(String[] args) {
FileInputStream fi = null;
Socket socket = null;
try {
socket = new Socket("192.168.1.106", 6789);
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
BufferedReader brReadKey = new BufferedReader(new InputStreamReader(System.in));
PrintStream ps = new PrintStream(socket.getOutputStream());
File file = getFile(brReadKey); //验证输入的路径
ps.println(file.getName()); //传输文件名和文件大小,以确定是否需要断点续传
ps.println(file.length());
String line = br.readLine(); //接收服务端返回的数据
long lengthDest = 0;
long skipNum = 0; //记录需要跳过的字节数
if("文件已存在.请不要重复上传!".equals(line)) { //若文件完整且重复,返回是-文件已存在.请不要重复上传!
System.out.println("文件已存在.请不要重复上传!");
return;
} else {
lengthDest = Integer.parseInt(line); //将返回的数据,转换
if(lengthDest != file.length()) { //比较大小是否一样,不一样则将服务器端的大小作为需要跳过的字节数
skipNum = lengthDest; //若是0,则表示服务器端没有该文件,则跳过的数目就是0
}
}
System.out.println( skipNum ==0 ? "开始上传..." : "断点续传...");
fi = new FileInputStream(file.toString());
OutputStream out = socket.getOutputStream();
int len = 0;
byte[] b = new byte[1024];
fi.skip(skipNum); //跳过字节数
while((len= fi.read(b))!=-1) {
out.write(b, 0, len);
}
System.out.println(skipNum ==0 ? "上传成功!" : "断点续传结束!");
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if(fi != null)
fi.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if(socket != null)
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/*
* 从键盘接收源文件的路径,保证输入的文件路径正确
*/
private static File getFile(BufferedReader brReadKey) throws IOException {
String line =null;
File file = null;
System.out.println("请输入需要上传的文件路径:");
while(true) {
line = brReadKey.readLine();
file = new File(line);
if(!file.exists()) {
System.out.println("文件不存在!请输入需要上传的文件路径:");
} else if(file.isDirectory()) {
System.out.println("暂不支持上传文件夹功能!请输入需要上传的文件路径:");
} else{
break;
}
}
return file;
}
}
服务端Server:
package cn.base24.tcp;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.Date;
/*
* 版本v2.0:(add:断点续传) ---<注意: 若是断点续传,则应该是追加数据!!!!!!!!!!!>
* 使用TCP传输文件的服务端:
*/
public class FileUploadServer2 {
public static void main(String[] args) {
ServerSocket serverSocket = null;
final File dir = new File("upload");
dir.mkdir();
try {
serverSocket = new ServerSocket(6789);
while(true) {
final Socket socket = serverSocket.accept();
new Thread() {
public void run() {
FileOutputStream out = null;
try {
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintStream ps = new PrintStream(socket.getOutputStream());
String fileName = br.readLine(); //接收数据为: 文件名和文件大小;
//返回数据为文件的大小,若存在返回实际大小,不存在则返回0
long lengthSrc = Long.parseLong(br.readLine());
boolean flag = false; //标记是否是续传文件,true为续传,false为正常传输
File file = new File(dir, fileName); //Modify: 如文件已存在,再检查文件大小是否一致
if( file.exists() ) { //若大小不一致,返回文件大小,以便客户端直接跳过已传输部分
if(file.length()==lengthSrc) {
ps.println("文件已存在.请不要重复上传!");
return;
}
else {
ps.println( file.length() );
flag = true;
}
} else {
ps.println(0);
}
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String time = sdf.format(new Date());
String ip = socket.getInetAddress().getHostAddress();
long start = System.currentTimeMillis();
System.out.println(ip +"上传: <"+file.getName() + ">文件, 在" + time + ( flag ? " 断点续传..." : " 开始上传..."));
InputStream in = socket.getInputStream();
if(flag) {
out = new FileOutputStream(file, true); //注意: 若是断点续传,则应该是追加数据!!!!!!!!!!!
} else {
out = new FileOutputStream(file);
}
int len = 0;
byte[] b = new byte[1024];
while((len= in.read(b))!=-1) {
out.write(b, 0, len);
}
time = sdf.format(new Date());
long end = System.currentTimeMillis();
System.out.println(ip +"上传: <" + file.getName() + ">文件, 在" + time + ( flag ? " 续传完成, 耗时: " : " 上传完成, 耗时: ") + (end -start) +"毫秒");
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if(out != null) {
out.close();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if(socket != null) {
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}.start();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if(serverSocket != null)
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}