-
Notifications
You must be signed in to change notification settings - Fork 0
Simple ftp #6
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Simple ftp #6
Changes from all commits
e2aef0e
dcf65e9
dde6fce
77dd862
2d6c595
5ecf6c0
43de3ac
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| group 'ru.spbau.dkaznacheev' | ||
| version '1.0-SNAPSHOT' | ||
|
|
||
| apply plugin: 'java' | ||
|
|
||
| sourceCompatibility = 1.8 | ||
|
|
||
| repositories { | ||
| mavenCentral() | ||
| } | ||
|
|
||
| dependencies { | ||
| testCompile group: 'junit', name: 'junit', version: '4.12' | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,89 @@ | ||
| package ru.spbau.dkaznacheev.simpleftp; | ||
|
|
||
| import java.io.*; | ||
| import java.net.ConnectException; | ||
| import java.net.Socket; | ||
| import java.net.UnknownHostException; | ||
| import java.util.Scanner; | ||
|
|
||
| public class Client { | ||
|
|
||
| /** | ||
| * Downloads a file from sever | ||
| * @param in inputstream of a socket | ||
| * @param name name of the file | ||
| */ | ||
| private static void receiveFile(DataInputStream in, String name) throws IOException{ | ||
| long length = in.readLong(); | ||
| if (length == 0) { | ||
| System.out.println("No such file"); | ||
| return; | ||
| } | ||
| try (FileOutputStream out = new FileOutputStream(simpleName(name))) { | ||
| byte[] buffer = new byte[4096]; | ||
| long remaining = length; | ||
| int read; | ||
| while ((read = in.read(buffer, 0, (int) Math.min(buffer.length, remaining))) > 0) { | ||
| remaining -= read; | ||
| out.write(buffer); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Returns simple file name of the filepath. | ||
| * @param path path to file | ||
| * @return filename | ||
| */ | ||
| private static String simpleName(String path) { | ||
| return new File(path).getName(); | ||
| } | ||
|
|
||
| public static void main(String[] args) { | ||
| try ( | ||
| Socket socket = new Socket("127.0.0.1", 8080); | ||
| PrintWriter out = new PrintWriter(socket.getOutputStream(), true); | ||
| DataInputStream in = new DataInputStream(socket.getInputStream()); | ||
| Scanner stdIn = new Scanner(System.in) | ||
| ) { | ||
| ResponseCode fromServer; | ||
| String fromUser; | ||
| boolean exit = false; | ||
| while (!exit) { | ||
| fromUser = stdIn.nextLine(); | ||
| if (fromUser != null) { | ||
| out.println(fromUser); | ||
| } | ||
| fromServer = ResponseCode.values()[in.readInt()]; | ||
| switch (fromServer) { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Предлагаю воспользоваться технологиями ООП и вынести логику клиента в отдельный класс, отделив ее от работы с консольным вводом-выводом. |
||
| case CLOSE_CONNECTION: { | ||
| exit = true; | ||
| break; | ||
| } | ||
| case INVALID_COMMAND: { | ||
| System.out.println("Invalid command"); | ||
| break; | ||
| } | ||
| case FOLDER_DESCRIPTION: { | ||
| FolderDescription description = FolderDescription.read(in); | ||
| description.print(); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Я бы предпочел, чтобы |
||
| break; | ||
| } | ||
| case FILE_SEND: { | ||
| String[] parts = fromUser.split(" "); | ||
| receiveFile(in, parts[1]); | ||
| break; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| } catch (UnknownHostException e) { | ||
| System.err.println("Unknown host"); | ||
| } catch (ConnectException e) { | ||
| System.err.println("Connection refused"); | ||
| } catch (IOException e) { | ||
| e.printStackTrace(); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| group 'ru.spbau.dkaznacheev' | ||
| version '1.0-SNAPSHOT' | ||
|
|
||
| apply plugin: 'java' | ||
|
|
||
| sourceCompatibility = 1.8 | ||
|
|
||
| repositories { | ||
| mavenCentral() | ||
| } | ||
|
|
||
| dependencies { | ||
| testCompile group: 'junit', name: 'junit', version: '4.12' | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,111 @@ | ||
| package ru.spbau.dkaznacheev.simpleftp; | ||
|
|
||
| import java.io.*; | ||
| import java.net.ServerSocket; | ||
| import java.net.Socket; | ||
| import java.net.SocketException; | ||
|
|
||
| import static ru.spbau.dkaznacheev.simpleftp.ResponseCode.*; | ||
|
|
||
| /** | ||
| * Simple FTP server that can handle multiple clients and send files over sockets. | ||
| */ | ||
| public class Server { | ||
|
|
||
| /** | ||
| * Sends file over ServerSocket's DataOutputStream. | ||
| * @param name filename | ||
| * @param out output stream | ||
| */ | ||
| private static void sendFile(String name, DataOutputStream out) throws IOException{ | ||
| File file = new File(name); | ||
| if (!file.exists()) { | ||
| out.writeLong(0); | ||
| return; | ||
| } | ||
| out.writeLong(file.length()); | ||
| byte[] buffer = new byte[4096]; | ||
| int read; | ||
| try (FileInputStream in = new FileInputStream(file)) { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. То же самое про IOUtils |
||
| while ((read = in.read(buffer)) > -1) { | ||
| out.write(buffer, 0, read); | ||
| } | ||
| } | ||
|
|
||
| } | ||
|
|
||
| /** | ||
| * Client handler, runs in a separate thread as long as there is a connectin with a client. | ||
| */ | ||
| private static class FTPThread extends Thread { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Вместо наследования потока правильней передать в конструктор реализацию Runnable. |
||
|
|
||
| /** | ||
| * Socket f server-client connection | ||
| */ | ||
| private Socket socket; | ||
|
|
||
| public FTPThread(Socket socket) { | ||
| this.socket = socket; | ||
| } | ||
|
|
||
| @Override | ||
| public void run() { | ||
| try ( | ||
| DataOutputStream out = new DataOutputStream(socket.getOutputStream()); | ||
| BufferedReader in = new BufferedReader( | ||
| new InputStreamReader(socket.getInputStream())) | ||
| ) { | ||
| String inputLine; | ||
| while ((inputLine = in.readLine()) != null) { | ||
| if (inputLine.equals("0")) { | ||
| out.writeInt(CLOSE_CONNECTION.ordinal()); | ||
| break; | ||
| } | ||
|
|
||
| String[] parts = inputLine.split(" "); | ||
| if (parts.length != 2) { | ||
| out.writeInt(INVALID_COMMAND.ordinal()); | ||
| continue; | ||
| } | ||
| String command = parts[0]; | ||
| String path = parts[1]; | ||
|
|
||
| if (command.equals("1")) { | ||
| FolderDescription description = FolderDescription.describeFolder(path); | ||
| out.writeInt(FOLDER_DESCRIPTION.ordinal()); | ||
| description.write(out); | ||
| } else if (command.equals("2")) { | ||
| out.writeInt(FILE_SEND.ordinal()); | ||
| sendFile(path, out); | ||
| } else { | ||
| out.writeInt(INVALID_COMMAND.ordinal()); | ||
| } | ||
| } | ||
| socket.close(); | ||
| } catch (SocketException e) { | ||
| System.out.println("Goodbye"); | ||
| } | ||
| catch (IOException e) { | ||
| System.err.println("IOException on thread " + Thread.currentThread().getName()); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| public static void main(String[] args) { | ||
| ServerSocket serverSocket; | ||
| try { | ||
| serverSocket = new ServerSocket(8080); | ||
| } catch (IOException e) { | ||
| System.err.println("Error creating server"); | ||
| return; | ||
| } | ||
| while (true) { | ||
| try { | ||
| Socket clientSocket = serverSocket.accept(); | ||
| new FTPThread(clientSocket).start(); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Вообще, ручное создание потоков инстансов |
||
| } catch (IOException e) { | ||
| System.err.println("Exception on client connecting"); | ||
| } | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| group 'ru.spbau.dkaznacheev.simpleftp' | ||
| version '1.0-SNAPSHOT' | ||
|
|
||
| apply plugin: 'java' | ||
|
|
||
| sourceCompatibility = 1.8 | ||
|
|
||
| repositories { | ||
| mavenCentral() | ||
| } | ||
|
|
||
| dependencies { | ||
| testCompile group: 'junit', name: 'junit', version: '4.12' | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| #Wed May 30 23:52:07 MSK 2018 | ||
| distributionBase=GRADLE_USER_HOME | ||
| distributionPath=wrapper/dists | ||
| zipStoreBase=GRADLE_USER_HOME | ||
| zipStorePath=wrapper/dists | ||
| distributionUrl=https\://services.gradle.org/distributions/gradle-3.5-rc-2-bin.zip |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Вместо этого лучше воспользоваться IOUtils из common-io
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Пока -1
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
попробовал IOUtils.copy, получилось удобно, но, к сожалению, так можно передать только один файл, а потом стрим нужно закрыть, соответственно, придется закрывать соединение. Поискал способы передавать файлы, не закрывая стрим, рекомендуют мой старый способ. Поэтому оставляю старый
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Не очень понял, какой стрим должен закрыться
https://commons.apache.org/proper/commons-io/javadocs/api-2.5/org/apache/commons/io/IOUtils.html#copy(java.io.InputStream,%20java.io.OutputStream)
Здесь вроде про это не написано и в коде реализации я не вижу ничего про закрытие
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Как IOUtils.copy на клиенте поймёт, что приём файла закончился?
Возможно, можно отправлять размер файла, но copy просто считывает входной стрим до конца, а копирования стольки-то байт я не нашёл.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Кажется вот это подходит https://commons.apache.org/proper/commons-io/javadocs/api-2.5/org/apache/commons/io/IOUtils.html#copyLarge(java.io.InputStream,%20java.io.OutputStream,%20long,%20long)