Reputation: 870
I am trying to write a text file to multiple sockets, using one program. The code used to write the text file over is as follows:
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;
}
}
Then, on the server side (for all three servers), I use the following thread, which evaluates to the else if(req.equals("write")){
code block:
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;
}
}
For some reason, when I write, the entire file does not go through to the other side. Rather, I miss somewhere around the first 100 bytes of the file. For example, if I write the Lorem Ipsum text, I will be missing somewhere around the first sentence.
Does anyone know why this is happening? I tried nearly everything, but I cannot seem to fix the issue
Upvotes: 0
Views: 61
Reputation: 123280
You first create a BufferedReader bin
and use it to read a single line for the command. But, this does not mean that only this line is read from the input stream. Instead more bytes are read but the BufferedReader bin
only returns the first line of these bytes, the rest is kept inside the buffer of the BufferedReader (that's why the name!).
Later you try to read the payload and instead of using the reader bin
you already have you create a new one reader
and read from this. This way you ignore any bytes already buffered in bin
- which means that you are missing bytes.
Upvotes: 2
Reputation: 24869
Your code has very many problems. It's of very poor quality, and you shouldn't be surprised that it doesn't work correctly. I would recommend to read a good beginner's book about Java and something about OOP in general. To name just a few problems:
try/finally
/try-with-resources
, which means that your streams may remain open forever if an exception occurs.PrintWriter
which is a very inefficient way of outputting data, and worse, you use println
to print each byte on a single line for whatever reason.while (i < 20000) ++i;
.Now to your question. The effect you see is because you don't read your data in a consistent way on the server side. Instead of encapsulating your protocol into a class you randomly create various helper objects to read your data. Look at this, for example:
InputStream in = client.getInputStream();
BufferedReader bin = new BufferedReader(new InputStreamReader(in));
String ex = bin.readLine();
What did you just do here? You created a buffered reader, which then (surprisingly) buffered some data to read a line. Of course it buffered more than just one line, that's how buffering works. At this point you should have forgotten about the in
object and only used bin
to read. That would be consistent. In fact, I'd write these lines as
BufferedReader bin = new BufferedReader(new InputStreamReader(
client.getInputStream()));
String ex = bin.readLine();
Just to be safe. But then you do
InputStream in2 = client.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(in2));
That is, you access the same stream directly, bypassing the previously created buffered reader. Of course the new reader picks up where the last reader stopped, which can be anywhere depending on the buffer size, buffering strategy and how many data was read by the previous reader.
To fix this:
PrintWriter
unless you're actually printing something for someone to read through a pipe or tail
.close()
calls in finally
blocks or use try-with-resources.Upvotes: 1