需求:每一个客户端启动后都可以给服务器上传一个文件,服务器接收到文件后保存到一个upload目录中。可以同时接收多个客户端的文件上传。
分析:
(1)服务器端要“同时”处理多个客户端的请求,那么必须使用多线程,每一个客户端的通信需要单独的线程来处理。
(2)服务器保存上传文件的目录只有一个upload,而每个客户端给服务器发送的文件可能重名,所以需要保证文件名的唯一。我们可以使用“时间戳”作为文件名,而后缀名不变
(3)客户端需要给服务器上传文件名(含后缀名)以及文件内容。而文件名是字符串,文件内容不一定是纯文本的,因此选择DataOutputStream和DataInputStream。
客户端的实例代码:
1 import java.io.BufferedReader;
2 import java.io.DataOutputStream;
3 import java.io.File;
4 import java.io.FileInputStream;
5 import java.io.InputStream;
6 import java.io.InputStreamReader;
7 import java.io.OutputStream;
8 import java.net.Socket;
9 import java.util.Scanner;
10
11 public class Client {
12 public static void main(String[] args) throws Exception {
13 // (1)连接服务器
14 Socket socket = new Socket("192.168.54.68", 8888);
15
16 Scanner input = new Scanner(System.in);
17
18 //(2)从键盘输入文件的路径和名称
19 System.out.print("请选择要上传的文件:");
20 String path = input.nextLine();
21 File file = new File(path);
22
23 OutputStream out = socket.getOutputStream();
24 DataOutputStream dos = new DataOutputStream(out);//用它的目的是为了既可以单独传一个字符串,又可以写字节内容
25
26 //先发送文件名(含后缀名)
27 dos.writeUTF(file.getName());//单独发一个字符串
28
29 //还需要一个IO流,从文件读取内容,给服务器发过去
30 FileInputStream fis = new FileInputStream(file);
31
32 //(3)把文件内容给服务器传过去,类似与复制文件
33 byte[] data = new byte[1024];
34 while(true){
35 int len = fis.read(data);
36 if(len==-1){
37 break;
38 }
39 dos.write(data, 0, len);
40 }
41 socket.shutdownOutput();
42
43 //(4)接收服务器返回的结果
44 InputStream is = socket.getInputStream();
45 InputStreamReader isr = new InputStreamReader(is);//把字节流转成字符流
46 BufferedReader br = new BufferedReader(isr);
47 String result = br.readLine();
48 System.out.println(result);
49
50 //(5)关闭
51 fis.close();
52 input.close();
53 socket.close();
54 }
55 }
服务器端的实例代码
1 import java.net.ServerSocket;
2 import java.net.Socket;
3
4 public class Server {
5 public static void main(String[] args) throws Exception{
6 //服务器在8888端口号监听数据
7 @SuppressWarnings("resource")
8 ServerSocket server = new ServerSocket(8888);
9
10 while(true){
11 //(2)等待连接
12 //这句代码执行一次,意味着一个客户端连接
13 Socket accept = server.accept();
14
15 FileUploadThread ft = new FileUploadThread(accept);
16 ft.start();
17 }
18 }
19 }
服务器端处理每一个客户端上传文件的线程类代码:
1 import java.io.DataInputStream;
2 import java.io.FileNotFoundException;
3 import java.io.FileOutputStream;
4 import java.io.IOException;
5 import java.io.InputStream;
6 import java.io.OutputStream;
7 import java.io.PrintStream;
8 import java.net.Socket;
9 import java.text.SimpleDateFormat;
10 import java.util.Date;
11
12 public class FileUploadThread extends Thread{
13 private Socket socket;
14 private String dir = "upload/";
15
16 public FileUploadThread(Socket socket) {
17 super();
18 this.socket = socket;
19 }
20
21 public void run(){
22 FileOutputStream fos = null;
23 try {
24 InputStream is = socket.getInputStream();
25 DataInputStream dis = new DataInputStream(is);
26
27 //读取文件名(含后缀名)
28 String filename = dis.readUTF();
29 //截取后缀名
30 String ext = filename.substring(filename.lastIndexOf("."));
31 //生成时间戳
32 SimpleDateFormat sf = new SimpleDateFormat("yyyyMMddHHmmssSSS");
33 filename = sf.format(new Date());
34 //用新文件路径构建文件输出流
35 fos = new FileOutputStream(dir + filename + ext);
36 //接收文件内容
37 byte[] data = new byte[1024];
38 while(true){
39 int len = is.read(data);
40 if(len==-1){
41 break;
42 }
43 fos.write(data, 0, len);
44 }
45
46 //返回结果
47 OutputStream out = socket.getOutputStream();
48 PrintStream ps = new PrintStream(out);
49 ps.println(filename + ext + ":已上传完毕");
50 } catch (FileNotFoundException e) {
51 e.printStackTrace();
52 } catch (IOException e) {
53 e.printStackTrace();
54 }finally{
55 try {
56 fos.close();
57 socket.close();
58 } catch (IOException e) {
59 e.printStackTrace();
60 }
61 }
62 }
63 }