Client类:
public static void main(String[] args) throws IOException {
Socket socket = new Socket("127.0.0.1",10010);
// 网络字节输入流,用来获取从服务器中传过来的数据(字节)
InputStream in = socket.getInputStream();
// 网络字节输出流,用来获取向服务器中传输的数据
OutputStream out = socket.getOutputStream();
// 本地输入流,使用转换流,如果服务器传的是字符,则使用转换流将字节转换成字符
BufferedReader br = new BufferedReader(new InputStreamReader(in));
// 打印流,PrintStream中的write可以发送字节,println可以发送字符。
PrintStream ps = new PrintStream(out);
// 首先读取文件名字
File file = new File("C:\\Users\\chenqingxv\\Pictures\\鞠婧祎.jpg");
// 再将文件名字先传给服务器
ps.println(file.getName());
// 先不着急往下写,暂停接收消息,防止数据的丢失
/*
为什么不着急往下继续读取本地文件:如果不利用readLine的阻塞特性,则输出流(打印流)就会将文件名字以及文件内容一起存入内存中,关于缓冲流,
底层会一次性从硬盘读取一定数量一个固定长度的字符数组后再由readLine读取到第一个“\r\n”结束,也就是在服务器端读文件名字时,
服务器只readLine了一次读取了文件名字,第一个数组中“\r\n”之后的数据就丢失了。之后服务器再用字节流(in.read(bytes))读文件内容的字符数时就有丢失。
所以在客户端上传文件名字之后,先用一个readLind方法的特性阻塞一下,防止继续读取,待服务器发送“接收完成”的提示后再继续读取文件中内容,就不会在有丢失。
*/
String information = br.readLine();
System.out.println(information);
// 使用本地输入流读取文件
FileInputStream fis = new FileInputStream("C:\\Users\\chenqingxv\\Pictures\\鞠婧祎.jpg");
// 设置缓冲数组
byte[] bytes = new byte[1024*8];
int len;
while ((len = fis.read(bytes))!= -1){
// 使用网络输出流写到服务器中
ps.write(bytes,0,len);
}
// 给服务器一个结束标记,告诉服务器,文件已经传输完毕
socket.shutdownOutput();
// 接收服务器传送过来的提示字符
String s = br.readLine();
System.out.println(s);
fis.close();
socket.close();
}
Server类:
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(10010);
//线程池的创建
ThreadPoolExecutor pool = new ThreadPoolExecutor(2, 5, 30, TimeUnit.SECONDS, new ArrayBlockingQueue<>(6));
// 服务器循环接收客户端的链接请求
while (true) {
Socket socket = serverSocket.accept();
ThreadFile threadFile = new ThreadFile(socket);
pool.submit(threadFile);
}
Runnable继承类:
private Socket socket;
public ThreadFile(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
InputStream in = null;
OutputStream out = null;
String name= null;
FileOutputStream fileOutputStream = null;
// 本地输入流,使用转换流(转换成字符流)
try {
// 网络字节输入流,用来获取从客户端中传过来的数据(字节)
in = socket.getInputStream();
// 网络字节输出流,用来获取从客户端中传输的数据
out = socket.getOutputStream();
// 接收首先传过来的文件名字
PrintStream ps = new PrintStream(out);
BufferedReader br = new BufferedReader(new InputStreamReader(in));
name = br.readLine();
// 接收名字结束,向客户端发送一个消息
ps.println("可以开始了");
// 使用UUID类随机一个名字
// 使用本地输出流向文件中写入数据
fileOutputStream = new FileOutputStream("day14\\upload\\"+ UUID.randomUUID().toString()+"_"+name);
byte[] bytes = new byte[1024*8];
int len;
while ((len = in.read(bytes))!=-1){
fileOutputStream.write(bytes,0,len);
}
// 传输完成后给客户端一个提示
ps.println("上传完成");
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
socket.close();
fileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}