2016-05-12 4 views
0

Я пытаюсь написать текстовый файл для нескольких сокетов, используя одну программу. Код, используемый для написания текстового файла через это выглядит следующим образом:TCP не пишет полный файл?

import java.io.*; 
import java.net.*; 

public class Server { 
    public static void main(String args[]) throws Exception{ 
     String servers[] = {"127.0.0.1","127.0.0.1","127.0.0.1"}; 
     int[] ports = {4525, 4003,3621}; 
     String fileName = "example"; 

     for(int i = 0; i < servers.length; i++){ 
      getFile(fileName, InetAddress.getByName(servers[i]), ports[i], "1"); 
     } 
    } 
    public static void getFile(String fileName, InetAddress ia, int port, String vers) throws Exception{ 
     Socket myServers = new Socket(ia, port); 
     PrintWriter pwSoc = new PrintWriter(myServers.getOutputStream(), true); 
     pwSoc.println(fileName + " " + "write " + vers); 
     InputStream is = null; 
     int i =0; 
     while(i < 20000){ 
      i++; 
     } 
     int c; 
     try{ 
      is = new FileInputStream(fileName + ".txt"); 
     } 
     catch(Exception e){ 
      System.out.println("Error. This file is not found"); 
      return; 
     } 
     while ((c = is.read()) != -1) { 
      pwSoc.println((char)c); 
      pwSoc.flush(); 
     } 
     pwSoc.close(); 
     is.close(); 
     pwSoc.close(); 
     return; 
    } 
} 

Затем на стороне сервера (для всех трех серверов), я использую следующий поток, который оценивает в else if(req.equals("write")){ блок коды:

import java.io.*; 
import java.net.*; 
import java.util.StringTokenizer; 
public class ServerRequestThread implements Runnable{ //Server 1 
    Socket client; 
    File[] files; 
    VersionInfo vi; 
    public ServerRequestThread(Socket s, VersionInfo vi) throws Exception{ 
     this.client = s; 
     String filePath = new File(".").getCanonicalPath(); 
     this.files = new File(filePath).listFiles(); 
     this.vi = vi; 
    } 

    public void run() { 
     String req = "", reversedString = ""; 
     try { 
      while(true){ 
       InputStream in = client.getInputStream(); 
       BufferedReader bin = new BufferedReader(new InputStreamReader(in)); 
       String ex = bin.readLine(); 
       StringTokenizer st = new StringTokenizer(ex, " "); 
       String fileName = st.nextToken(); 
       if(fileName.equals("done")){ 
        return; 
       } 
       else if(fileName.equals("fileList")){ 
        String returnList = showFiles(files).trim(); 
        PrintWriter pout = new PrintWriter(client.getOutputStream(), true); 
        pout.println(returnList); 
        pout.close(); 
       } 
       else if(fileName.equals("filecatchup")){ 
        PrintWriter pout = new PrintWriter(client.getOutputStream(), true); 
        pout.println(vi.printHash()); 
        pout.close(); 
       } 
       else{ 
        req = st.nextToken(); 
       } 
       if(req.equals("read")){ 
        PrintWriter pout = new PrintWriter(client.getOutputStream(), true); 
        int c; 
        InputStream is = null; 
        try{ 
         is = new FileInputStream(fileName + ".txt"); 
        } 
        catch(Exception e){ 
         pout.println("File could not be found"); 
         return; 
        } 
        while ((c = is.read()) != -1) { 
         pout.println((char)c); 
        } 
        pout.close(); 
        return; 
       } 
       else if(req.equals("write")){ 
        if(st.hasMoreTokens()){ 
         String vers = st.nextToken(); 
         vi.updateHash(fileName, Integer.parseInt(vers)); 
         System.out.println("The file " + fileName + " was updated (via remote update) to v." + vers); 
        } 
        else{ 
         vi.updateFile(fileName); 
         System.out.println("The file " + fileName + " was updated to v." + vi.getFile(fileName)); 
        } 

        InputStream in2 = client.getInputStream(); 
        BufferedReader reader = new BufferedReader(new InputStreamReader(in2)); 
        reversedString = reader.readLine(); 


        PrintWriter out = new PrintWriter(fileName + ".txt"); 
        while(reversedString != null){ 
         //cont+=reversedString; 
         out.print(reversedString); 
         reversedString = reader.readLine(); 
        } 
        reader.close(); 
        out.close(); 
        return; 
       } 
      } 
     } catch (Exception e) {} 
    } 
    public String showFiles(File[] files) throws Exception { 
     String ret = ""; 
     //System.out.println("Path: " + new File(".").getCanonicalPath()); 
     for (File file : files) { 
      if (file.isDirectory()) { 
       //System.out.println("Directory: " + file.getName()); 
       showFiles(file.listFiles()); // Calls same method again. 
      } else { 
       if(file.getName().toLowerCase().endsWith(".txt")){ 
        ret+= " " + file.getName(); 
       } 
      } 
     } 
     return ret; 
    } 

} 

По какой-то причине, когда я пишу, весь файл не переходит на другую сторону. Скорее, я пропускаю где-то около первых 100 байт файла. Например, если я напишу текст Lorem Ipsum, я буду отсутствовать где-то вокруг первого предложения.

Кто-нибудь знает, почему это происходит? Я пробовал почти все, но я не могу исправить проблему.

ответ

2

Сначала создайте BufferedReader bin и используйте его для чтения одной строки для команды. Но это не означает, что только строка считывается из входного потока. Вместо этого считывается больше байтов, но BufferedReader bin возвращает только первую строку этих байтов, остальная часть хранится внутри буфера Буферизованный читатель (вот почему имя!).

Позже вы попытаетесь прочитать полезную нагрузку, а вместо использования читателя bin вы уже создали новый reader и читаете об этом. Таким образом, вы игнорируете любые байты, уже буферизированные в bin, что означает, что вам не хватает байтов.

+0

Это была именно та проблема, которую я только что обнаружил. Спасибо за помощь! – svsav

1

У вашего кода очень много проблем. Это очень плохое качество, и вы не должны удивляться, что он работает неправильно. Я бы рекомендовал прочитать книгу хорошего новичка о Java и вообще о ООП. Для того, чтобы назвать только несколько проблем:

  • Вы не используете try/finally/try-with-resources, что означает, что ваши потоки могут оставаться открытыми навсегда, если происходит исключение.
  • Вы, кажется, не distinguish between characters and bytes, что является основным источником непрекращающихся неприятностей. В вашем случае вы читаете байты, а затем записываете их как символы. Возьмите файл UTF-8 с символами, отличными от ASCII, и вы немедленно их разломете (буквально в байты).
  • Вы злоупотребляете PrintWriter, что является очень неэффективным способом вывода данных, и хуже того, вы используете println для печати каждого байта по одной строке по любой причине.
  • Вы используете магический код, который не имеет четко определенной цели, например while (i < 20000) ++i;.

Теперь на ваш вопрос. Эффект, который вы видите, заключается в том, что вы не читаете свои данные согласованным образом на стороне сервера. Вместо того, чтобы инкапсулировать ваш протокол в класс, вы произвольно создаете различные вспомогательные объекты для чтения ваших данных. Посмотрите на это, например:

  InputStream in = client.getInputStream(); 
      BufferedReader bin = new BufferedReader(new InputStreamReader(in)); 
      String ex = bin.readLine(); 

Что вы здесь делали? Вы создали буферизированный считыватель, который затем (на удивление) забуферировал некоторые данные для чтения строки. Конечно, он буферизует больше, чем одну строку, вот как работает буферизация. На этом этапе вы должны были забыть о объекте in и использовать только bin для чтения. Это будет последовательным. Фактически, я бы написал эти строки как

  BufferedReader bin = new BufferedReader(new InputStreamReader(
                 client.getInputStream())); 
      String ex = bin.readLine(); 

Просто, чтобы быть в безопасности. Но тогда вы делаете

   InputStream in2 = client.getInputStream(); 
       BufferedReader reader = new BufferedReader(new InputStreamReader(in2)); 

То есть вы получаете доступ к одному потоку напрямую, минуя ранее созданный буферный считыватель. Конечно, новый читатель забирает, где остановился последний читатель, который может быть где угодно в зависимости от размера буфера, стратегии буферизации и количества данных, которые читал предыдущий читатель.

Чтобы это исправить:

  • инкапсулировать протокол в отдельный класс или классы, может быть.
  • Прочитайте ваши данные последовательно, используя один буферный считыватель.
  • Do не использовать PrintWriter, если вы на самом деле не печатаете что-то для чтения кому-либо через трубу или tail.
  • Указать кодировку явно читателю. Выберите один и придерживайтесь его. UTF-8 является хорошим выбором для сетевых протоколов.
  • Положите close() звонки в finally блоки или используйте try-with-resources.
Смежные вопросы