Java通过Socket传输文件以及判断文件传输完成的方法

释放双眼,带上耳机,听听看~!

 絮叨

本人学生,往前一年左右的时间用在了Java上

都说写博客、随笔是百利一害的事情-->一害是费时间

近期也是在此申请开通了博客

此篇也算是开博第一篇,所以絮叨一下

——————————————————————————————————————————————————————

问题发现与解决

今天在写Socket的文件传输

程序涉及到Socket、线程、文件操作、流等

目标是Client可以向Server提交文件名

然后Server进行响应-->文件存在则传输,不存在则回复文件不存在的消息

因为想要完成多次文件传输,所以把方法块放进了循环

于是希望所有打开的资源,像InputStream, OutputStream,这些可以再运行过程中一直打开, 直到程序结束才关闭

 

——————————————————————————————————————————————————————

文件传输用的是 DataInputStream 中的 read(byte[] b, int off, int len) 和 DataOutputStream 中的 write(byte[] b, int off, int len)

 

 

 

JavaDoc 地址: 

https://docs.oracle.com/javase/8/docs/api/java/io/DataInputStream.html

https://docs.oracle.com/javase/8/docs/api/java/io/DataOutputStream.html

简单描述

DataInputStream 和 DataOutputStream 是字节流 可以视为-->他们操作的对象是每字节的编码-->机器认识而我不认识的东西

相对应的Writer和Reader 是字符流 他们操作的是将字节编码转化为字符的我能看懂的东西

所以在传输文件的时候使用字节流是更为合适的选择

——————————————————————————————————————————————————————

网上有关文件传输的代码大多是这个样子

通过(FileInputStream) fileInput 从文件读取,并通过(DataOutputStream) out 发送:

1         while((length = fileInput.read(bytes)) != -1) {
2             out.write(bytes, 0, length);
3             out.flush();
4         }

通过(DataInputStream) in 读取数据,并通过(FileOutputStream) fileOutput 写入文件

1         while((length = in.read(bytes, 0, bytes.length)) != -1) {
2             fileOutput.write(bytes, 0, length);
3             fileOutput.flush();
4         }

这两段代码没有问题,都是可以运行的

我的问题出现在接收文件数据的时候,文件数据已经发送完毕,但是程序没有跳出循环

其症结是while()中的判断条件是要 length = -1 才会跳出循环

可以通过上方贴出来的JavaDoc的截图看到-1表示的读取到流的结尾

但是想要让它读取到流的结尾 是要发送方关闭流

在发送方发送完成后需要有类似这样一句 out.close()

执行out.close() 实际上它所包装的socket也随之关闭了

也就是说整条连接都断了 这不是我想要的

我想要的是发送完一个 程序还能够继续响应我从Client发送来的消息

于是需要引入新的判断条件 让接收方知道它想要的文件已经传输完毕

——————————————————————————————————————————————————————

我找到的一个简单的方法是 利用文件的length

传输文件之前,在Server检查文件名是否存在,向Client反馈的时候,将文件的length也发送过去

这样就可在接收文件的时候对本地文件的length和传输过来的length进行比较

从而判断文件传输是否完成

 

 1     private static void getBytes(String fileName, long fileLength) throws IOException {
 2         File file = new File(fileName);
 3         FileOutputStream f = new FileOutputStream(file);
 4         byte[] bytes = new byte[1024];
 5         int length = 0;
 6         while(true) {
 7             length = in.read(bytes, 0, bytes.length);
 8             f.write(bytes, 0, length);
 9             f.flush();
10             /*
11              * when fileLength equals to length of local file, it
12              * represents the downloading is finished
13              */
14             if(fileLength == file.length()) break;
15         }
16         f.close();
17     }

 

 

 

 ——————————————————————————————————————————————————————

 

代码

下面是我所写的Socket文件传输的代码

Server

在Server端循环监听绑定端口

在listenRequest()中为每个新连接进来的socket新建一个线程

以此来并发响应每个对应Client的请求

  1 import java.io.DataInputStream;
  2 import java.io.DataOutputStream;
  3 import java.io.File;
  4 import java.io.FileInputStream;
  5 import java.io.IOException;
  6 import java.net.ServerSocket;
  7 import java.net.Socket;
  8 import java.util.logging.Level;
  9 import java.util.logging.Logger;
 10 
 11 public class Server {
 12 
 13     
 14     private static ServerSocket server;
 15     private static Socket socket;
 16     private static final int port = 123456;
 17     private static Logger logger;
 18     
 19     static{
 20         logger = Logger.getLogger(\"Server\");
 21         logger.setLevel(Level.INFO);
 22     }
 23     
 24     public static void main(String[] args) throws IOException {
 25         //create server with port
 26         server = new ServerSocket(port);
 27         logger.info(\"Server Starts\");
 28         while(true) {
 29             //listen server and bind socket when accept a connection
 30             socket = server.accept();
 31             //record incoming connections
 32             logger.info(\"Get connection from \" + socket.getRemoteSocketAddress());
 33             listenRequest(socket);
 34         }
 35     }
 36 
 37     /**
 38      * create a new thread for socket.<br>
 39      * listen input from socket<br>
 40      * process requests and give responses to client.
 41      * @param socket the specific socket that connects to the server
 42      */
 43     private static void listenRequest(Socket socket) {
 44         /*
 45          * create a new thread for this socket so that it 
 46          * can be responsible for this socket only
 47          */
 48         new Thread(new Runnable(){
 49             DataInputStream in;
 50             DataOutputStream out;
 51             boolean status;
 52             
 53             @Override
 54             public void run() {
 55                 try {
 56                     logger.info(\"Start Listening Socket Input\");
 57                     /* 
 58                      * create DataInputStream and DataOutputStream objects to get
 59                      * the stream of socket
 60                      */
 61                     in = new DataInputStream(socket.getInputStream());
 62                     out = new DataOutputStream(socket.getOutputStream());
 63                     status = true;
 64                     while(status) {
 65                         processInput();
 66                     }
 67                 } catch (IOException e) {
 68                     e.printStackTrace();
 69                 }
 70             }
 71 
 72             /**
 73              * process requests from client and give response respectively
 74              * @throws IOException
 75              */
 76             private void processInput() throws IOException {
 77                 String content = in.readUTF();
 78                 String[] command = content.split(\":\");
 79                 String fileName = null;
 80                 switch(command[0]) {
 81                 case \"FILE_TRANSFER_REQUEST\":
 82                     /* 
 83                      * structure of FILE_REQUEST should be:
 84                      * @COMMAND:@FILENAME
 85                      */
 86                     logger.info(\"Get File Request From \" + socket.getRemoteSocketAddress());
 87                     fileName = command[1];
 88                     fileTransferResponse(fileName);
 89                     break;
 90                 case \"FILE_BYTES_REQUEST\":
 91                     /*
 92                      * structure of FILE_BYTES_REQUEST
 93                      * @Command:@FileName
 94                      */
 95                     fileName = command[1];
 96                     logger.info(\"Get File Bytes Request From \" + socket.getRemoteSocketAddress());
 97                     fileBytesResponse(fileName);
 98                     break;
 99                 case \"DISCONNECT\":
100                     logger.info(\"Get Disconnect From \" + socket.getRemoteSocketAddress());
101                     stop();
102                     break;
103                     default:
104                         break;
105                 }
106                 
107             }
108 
109             /**
110              * close relevant resources and change status to 
111              * false to end this thread
112              * @throws IOException
113              */
114             private void stop() throws IOException {
115                 in.close();
116                 out.close();
117                 socket.close();
118                 status = false;
119             }
120 
121             /**
122              * send file bytes(raw data) to client 
123              * @param fileName name of file
124              * @throws IOException
125              */
126             private void fileBytesResponse(String fileName) throws IOException {
127                 File file = new File(fileName);
128                 FileInputStream fileInput = new FileInputStream(file);
129                 byte[] bytes = new byte[1024];
130                 int length = 0;
131                 while((length = fileInput.read(bytes)) != -1) {
132                     out.write(bytes, 0, length);
133                     out.flush();
134                 }
135                 logger.info(\"File Transfer Finished\");
136                 fileInput.close();
137             }
138 
139             private void fileTransferResponse(String fileName) throws IOException {
140                 File file = new File(fileName);
141                 StringBuffer response = new StringBuffer();
142                 /* 
143                  * if file does not exist, response to the client
144                  * with error message
145                  */
146                 if(!file.exists()) {
147                     //make sure there is nothing in response
148                     response.setLength(0);
149                     /* 
150                      * structure of FILE_NOT_EXISTS should be:
151                      * @COMMAND:@MESSAGE
152                      */
153                     response.append(\"FILE_NOT_EXISTS:\");
154                     response.append(\"The file \\\"\" + fileName+ \"\\\" your request does not exist.\");
155                     out.writeUTF(response.toString());
156                     out.flush();
157                 }else {
158                     /* 
159                      * structure of FILE_EXISTS should be;
160                      * @Command:@FileName:@FileLength
161                      */
162                     response.setLength(0);
163                     response.append(\"FILE_EXISTS:\");
164                     response.append(fileName+\":\");
165                     response.append(file.length());
166                     out.writeUTF(response.toString());
167                     out.flush();
168                 }
169             }
170             
171         }).start();
172     }
173     
174 
175 
176 }

 

Client

Client中不需要多线程 因此一个主线程完成所有工作

  1 import java.io.DataInputStream;
  2 import java.io.DataOutputStream;
  3 import java.io.File;
  4 import java.io.FileOutputStream;
  5 import java.io.IOException;
  6 import java.io.PrintStream;
  7 import java.net.Socket;
  8 import java.util.Scanner;
  9 import java.util.logging.Level;
 10 import java.util.logging.Logger;
 11 
 12 public class Client {
 13 
 14     private static Socket socket;
 15     private static final int port = 123456;
 16     private static final String host = \"***********\";
 17     private static Logger logger;
 18     private static PrintStream display;
 19     private static DataOutputStream out;
 20     private static DataInputStream in;
 21     private static Scanner sc;
 22     
 23     static{
 24         logger = Logger.getLogger(\"Client\");
 25         logger.setLevel(Level.INFO);
 26         display = System.out;
 27         sc = new Scanner(System.in);
 28     }
 29     public static void main(String[] args) {
 30         try {
 31             /* create a new object of Socket and try to connect to
 32              * the server with host and port
 33              */
 34             socket = new Socket(host, port);
 35             
 36             //logger.info(\"Connect to Server \"+ host + \" with Port \"+ port);
 37             out = new DataOutputStream(socket.getOutputStream());
 38             in = new DataInputStream(socket.getInputStream());
 39             while(true) {
 40                 welcomeInterface(display, sc);
 41             }
 42         } catch (IOException e) {
 43             e.printStackTrace();
 44         }
 45     }
 46     /**
 47      * An interface that instruct users to interact with this program
 48      * @param display system out stream
 49      * @param sc system input stream
 50      * @throws IOException
 51      */
 52     private static void welcomeInterface(PrintStream display, Scanner sc) throws IOException {
 53         display.println();
 54         for(int i = 0; i < 15; i++) {
 55             display.append(\"#\");
 56         }
 57         display.append(\" Welcome To Week6Client \");
 58         for(int i = 0; i < 15; i++) {
 59             display.append(\"#\");
 60         }
 61         display.println();
 62         display.println();
 63         display.printf(\"%5s%-30s\", \" \", \"Please Enter The File Name: \");
 64         String fileName = sc.nextLine();
 65         display.println();
 66         fileRequest(fileName);
 67     }
 68 
 69     /**
 70      * send file request to server, and process responses of this request
 71      * from server.
 72      * @param fileName the name of file that expect to download
 73      * @throws IOException
 74      */
 75     private static void fileRequest(String fileName) throws IOException {
 76         StringBuffer content = new StringBuffer();
 77         /*
 78          * structure of FILE_REQUEST:
 79          * @command:@fileName
 80          */
 81         content.append(\"FILE_TRANSFER_REQUEST:\");
 82         content.append(fileName);
 83         out.writeUTF(content.toString());
 84         out.flush();
 85         //logger.info(\"Send File Request to Server\");
 86         // after send request to server, waiting for response from server
 87         String[] response = in.readUTF().split(\":\");
 88         //logger.info(\"Get Response From Server: \" + response[0]);
 89         switch(response[0]) {
 90         case \"FILE_EXISTS\":
 91             fileName = response[1];
 92             File file = new File(fileName);
 93             /*
 94              * structure of FILE_EXISTS:
 95              * @Command:@FileName:@FileLength
 96              */
 97             if(file.exists()) {
 98                 display.printf(\"%5s%s\", \" \", \"File \\\"\" +fileName + \"\\\" exists in current director.\\n\");
 99                 display.printf(\"%5s%s\", \" \", \"Do you want to overrid it? \\n\");
100                 display.printf(\"%5s%s\", \" \", \"Y/y -> Override, Other -> Cancel\\n\");
101                 display.printf(\"%5s\", \" \");
102                 if(!sc.nextLine().toLowerCase().equals(\"y\")) break;
103                 else {
104                     file.delete();
105                     file.createNewFile();
106                 }
107             } 
108             content.setLength(0);
109             content.append(\"FILE_BYTES_REQUEST:\");
110             content.append(fileName);
111             out.writeUTF(content.toString());
112             display.printf(\"%5s%-30s%s\", \"\",  \"Downloading \", fileName+\"\\n\");
113             long fileLength = Long.parseLong(response[2]);
114             getBytes(fileName, fileLength);
115             display.printf(\"%5s%-20s\", \"\",  \"Download Done\\n\");
116             break;
117         case \"FILE_NOT_EXISTS\":
118             display.printf(\"%5s%-50s\", \"\", response[1]);
119             break;
120             default:
121                 break;
122         }
123         display.println();
124         display.printf(\"%5s%s\", \" \", \"Do you want to continue? \\n\");
125         display.printf(\"%5s%s\", \" \", \"Y/y -> Continue, Other -> Quit \\n\");
126         display.printf(\"%5s\", \"\");
127         /*
128          * if user enter other character, call stop() to close relevant
129          * resources and end this process
130          */
131         if(!sc.nextLine().toLowerCase().equals(\"y\")) {
132             display.println();
133             display.println();
134             stop();
135         }
136         display.println();
137         display.println();
138 
139     }
140 
141     /**
142      * close relevant resources and call System.exit(int status) to 
143      * end this process
144      * @throws IOException
145      */
146     private static void stop() throws IOException {
147         out.writeUTF(\"DISCONNECT\");
148         out.close();
149         in.close();
150         sc.close();
151         socket.close();
152         System.exit(0);
153     }
154 
155     /**
156      * Receive bytes from server. Once the length of local file is same
157      * as server\'s, transfer ends.
158      * @param fileName the name of file that is going to operate
159      * @param fileLength the length of file on server
160      * @throws IOException
161      */
162     private static void getBytes(String fileName, long fileLength) throws IOException {
163         File file = new File(fileName);
164         FileOutputStream f = new FileOutputStream(file);
165         byte[] bytes = new byte[1024];
166         int length = 0;
167         while(true) {
168             length = in.read(bytes, 0, bytes.length);
169             f.write(bytes, 0, length);
170             f.flush();
171             /*
172              * when fileLength equals to length of local file, it
173              * represents the downloading is finished
174              */
175             if(fileLength == file.length()) break;
176         }
177         f.close();
178     }
179 
180 }

 

 

 

 第一次写东西,没什么经验,如有错误、问题请指出

如需讨论 也可发邮件给我哈

email: ancientcoinli@gmail.com

 

 

 

 

 

 

 

——————————————————————————————————————————————————————

 

人已赞赏
随笔日记

MongoDB 日志切割三种方式

2020-11-9 4:19:48

随笔日记

C#之委托

2020-11-9 4:19:50

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索