Пытаюсь отправлять любой файл по TCP с моего клиента (на мобильном устройстве) на консольный сервер (на компьютере).
Подключение, отправка, получение, по-моему, происходят нормально, однако есть проблема с записью данных в файл.
Например, музыка в него записывается несколько раз, а у картинки записывается только одна "линия".
Я подозреваю, что проблема где-то в цикле, но не могу понять точно.
Код сервера, в котором происходит получение байтов из сокета и запись в файл:
String fileName;
int size;
try {
size = sInput.readInt();
fileName = sInput.readUTF();
try {
FileOutputStream fos = new FileOutputStream("C:\\Users\\admin\\Downloads\\FileSenderDownload\\" + fileName);
byte[] buffer = new byte[size];
int receivedBytes = 0;
while (true) {
if (receivedBytes == -1)
break;
receivedBytes = input.read(buffer);
System.out.println(receivedBytes);
fos.write(buffer, 0, buffer.length);
}
System.out.println("Запись");
} catch (IOException ex) {
ex.printStackTrace();
}
} catch (Exception e) {
e.printStackTrace();
}
Код клиента для отправки файла:
try {
DataOutputStream out = new DataOutputStream(socket.getOutputStream());
ObjectOutputStream output= new ObjectOutputStream(socket.getOutputStream());
output.writeInt((int)sendingFile.length());
output.flush();
System.out.println("File size" + sendingFile.length());
output.writeUTF(sendingFile.getName());
output.flush();
System.out.println("File name" + sendingFile.getName());
FileInputStream input = new FileInputStream(sendingFile);
int size = (int)sendingFile.length();
byte[] buffer = new byte[size];
int receivedBytes;
while(true) {
receivedBytes = input.read(buffer);
if (receivedBytes == -1) {
break;
}
if (receivedBytes > 0) {
out.write(buffer, 0, receivedBytes);
out.flush();
}
}
input.close();
out.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
Как исправить этот код?
Проблемы в цикле while (true)
на сервере:
receivedBytes = input.read(buffer);
должно быть до проверки if (receivedBytes == -1)
.fos.write
указывать количество считанных байтов, а не длину буфера: fos.write(buffer, 0, receivedBytes);
В итоге цикл выглядит так:
while (true)
{
receivedBytes = input.read(buffer);
if (receivedBytes == -1)
break;
totalCount += receivedBytes;
fos.write(buffer, 0, receivedBytes);
}
И по поводу кода в целом: использование try-with-resources
и констант помогает улучшить код:
Клиент:
public void send(File sendingFile)
{
try (Socket socket = new Socket(SERVER_ADDRESS, PORT);
ObjectOutputStream output = new ObjectOutputStream(socket.getOutputStream());
FileInputStream input = new FileInputStream(sendingFile))
{
output.writeInt((int)sendingFile.length());
output.writeUTF(sendingFile.getName());
byte[] buffer = new byte[BUFFER_SIZE];
int readCount;
while ((readCount = input.read(buffer)) != -1)
{
output.write(buffer, 0, readCount);
}
}
catch (IOException e)
{
e.printStackTrace();
}
}
Сервер:
private void get(Socket socket)
{
try (ObjectInputStream sInput = new ObjectInputStream(socket.getInputStream()))
{
int size = sInput.readInt();
String fileName = sInput.readUTF();
try (FileOutputStream fos = new FileOutputStream(FILES_DIRECTORY + fileName))
{
byte[] buffer = new byte[BUFFER_SIZE];
int receivedBytes = 0;
while (receivedBytes < size)
{
int readCount = sInput.read(buffer);
if (readCount == -1)
{
break;
}
receivedBytes += readCount;
fos.write(buffer, 0, readCount);
}
}
catch (IOException e)
{
e.printStackTrace();
}
}
catch (IOException e)
{
e.printStackTrace();
}
}
Если через одно socket-соединение всегда будет передаваться только один файл, то на сервере можно не заморачиваться с подсчетом количества полученных байтов и сделать по аналогии с клиентом:
try (FileOutputStream fos = new FileOutputStream(FILES_DIRECTORY + fileName))
{
byte[] buffer = new byte[BUFFER_SIZE];
int readCount;
while ((readCount = sInput.read(buffer)) != -1)
{
fos.write(buffer, 0, readCount);
}
}
При таком допущении код можно упростить ещё больше с использованием Files.copy
:
Клиент:
public void send(File sendingFile)
{
try (Socket socket = new Socket(SERVER_ADDRESS, PORT);
ObjectOutputStream output = new ObjectOutputStream(socket.getOutputStream()))
{
output.writeUTF(sendingFile.getName());
Path path = sendingFile.toPath();
Files.copy(path, output);
}
catch (IOException e)
{
e.printStackTrace();
}
}
Сервер:
private void get(Socket socket)
{
try (ObjectInputStream sInput = new ObjectInputStream(socket.getInputStream()))
{
String fileName = sInput.readUTF();
Path path = Paths.get(FILES_DIRECTORY + fileName);
Files.copy(sInput, path, StandardCopyOption.REPLACE_EXISTING);
}
catch (IOException e)
{
e.printStackTrace();
}
}
Кофе для программистов: как напиток влияет на продуктивность кодеров?
Рекламные вывески: как привлечь внимание и увеличить продажи
Стратегії та тренди в SMM - Технології, що формують майбутнє сьогодні
Выделенный сервер, что это, для чего нужен и какие характеристики важны?
Современные решения для бизнеса: как облачные и виртуальные технологии меняют рынок
Такой вопрос, как открыть Emojii keyboard программно? Например, при нажатии на кнопку, сразу должна открываться часть клавиатуры с emoji
Я хочу использовать эту библиотеку, похоже что пользоваться ей очень удобно, но я не понимаю как поместить свой логотип в верхнюю часть Drawer'a...
Пытаюсь реализовать простую задачу - пост какого-либо сообщения на стену в социальных сетяхНаткнулся на данную библиотеку ScribeJava