我正在尝试使用一个程序将文本文件写入多个套接字。用于编写文本文件的代码如下:
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文本,我会在第一句话的某处丢失。
有谁知道为什么会这样?我几乎尝试了所有东西,但我似乎无法解决问题
答案 0 :(得分:2)
首先创建一个BufferedReader bin
并使用它来读取命令的单行。但是,这并不意味着只从输入流中读取此行。相反,读取更多字节,但BufferedReader bin
仅返回这些字节的第一行,其余的保留在缓冲读取器的缓冲区内(这就是名称的原因!)。
稍后您尝试阅读有效负载,而不是使用阅读器bin
,而是已经创建了一个新的reader
并从中读取。这样就可以忽略bin
中已经缓冲的任何字节 - 这意味着你缺少字节。
答案 1 :(得分:1)
您的代码存在很多问题。质量非常差,你不应该对它无法正常工作感到惊讶。我建议你阅读一本关于Java的初学者书和一般的OOP。仅举几个问题:
try/finally
/ try-with-resources
,这意味着如果发生异常,您的流可能会永远保持打开状态。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));
也就是说,您可以绕过先前创建的缓冲读取器直接访问相同的流。当然,新的阅读器会在最后一个阅读器停止的地方找到,这可以是任何地方,具体取决于缓冲区大小,缓冲策略以及前一个阅读器读取的数据量。
解决此问题:
PrintWriter
,除非您实际打印的内容供某人阅读管道或tail
。close()
个来电置于finally
个区块或使用try-with-resources。