【问题标题】:Java socket receives byte array where each byte is 0Java套接字接收字节数组,其中每个字节为0
【发布时间】:2023-04-10 16:06:01
【问题描述】:

我正在制作一个程序,它接受一个文件,并通过套接字将它发送到客户端。客户端接收它并将其保存到文件中。这就是它应该做的。

但是不知何故,客户端接收到的字节数组只包含 0 个字节,所以我的输出文件是空的。这是代码:

服务器:

try {
        serverSocket=new ServerSocket(7575);
        serverSocket.setSoTimeout(1000000);
        System.out.println("serverSocket created.");
    } catch (IOException ex) {
        Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
        System.out.println("Error in creating new serverSocket on port 7575");
    } 

    for(int i=0;i<array.length;i++)
        System.out.println(array[i]);

    Socket socket=null;
    try {
        System.out.println("Waiting for client...");
        socket=serverSocket.accept();
        System.out.println("Client accepted.");
    } catch (IOException ex) {
        Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
    }
    PrintWriter outWriter=null;
    DataOutputStream outputStream=null;
    OutputStream os=null;
    BufferedOutputStream bos=null;
    try {
        os=socket.getOutputStream();
        outputStream=new DataOutputStream(os);
        outWriter=new PrintWriter(socket.getOutputStream());
        bos=new BufferedOutputStream(socket.getOutputStream());
        System.out.println("Server streams created.");
    } catch (IOException ex) {
        Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
    }
    System.out.println("sending name "+name);
    outWriter.println(name);
    outWriter.flush();

    outWriter.println(array.length);
    outWriter.println("array.length"+array.length);
    outWriter.flush();

    try {
        os.write(array);
        os.flush();
    } catch (IOException ex) {
        Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
        System.out.println("couldnt send array of bytes");
    }



    try {
        os.close();
       outputStream.close();

        socket.close();
    } catch (IOException ex) {
        Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
    }

客户:

public class Client implements Runnable {
private Socket socket;
private String folderPath;

public Client(String p)
{
    folderPath=p;
}

@Override
public void run() 
{
    try {
        System.out.println("Client connecting to localhost on 7575 port...");
        socket=new Socket("localhost", 7575);
    } catch (IOException ex) {
        Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
    }

    BufferedReader reader=null;
    BufferedInputStream bis=null;
    InputStream input=null;
    DataInputStream in=null;
    try {
        System.out.println("creating streams");
        reader=new BufferedReader(new InputStreamReader(socket.getInputStream()));
        input=socket.getInputStream();
        in=new DataInputStream(input);
        bis=new BufferedInputStream(socket.getInputStream());
        System.out.println("streams created!");
    } catch (IOException ex) {
        Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
    }
    String name="";
    int size=0;
    String s="32";
    try {
        name=reader.readLine();
        s=reader.readLine();
    } catch (IOException ex) {
        Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
    }
    if(s!=null)
    size=Integer.parseInt(s);
    System.out.println("name: "+name);
    System.out.println("size: "+size);

    byte [] arr=new byte[size];
    try {
        input.read(arr);
    } catch (IOException ex) {
        Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
        System.out.println("couldnt read the byte array");
    }

    for(int i=0;i<arr.length;i++)
        System.out.println(arr[i]);

    FileOutputStream fos=null;
    try {
         fos=new FileOutputStream(folderPath+"/"+name);
        } catch (FileNotFoundException ex) {
            System.out.println("Could write the file");
        Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
    }
    try {

        fos.write(arr);
        fos.flush();
        } catch (IOException ex) {
            System.out.println("Could write the file2");
        Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
    }

    try {
        fos.close();
        } catch (IOException ex) {
        Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
    }


        try {
        in.close();
        input.close();
        reader.close();
        socket.close();
        } catch (IOException ex) {
        Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
        }



}

}

【问题讨论】:

  • 不要在同一个套接字上使用多个读取器、写入器和流。它行不通。选择一种技术并坚持下去。

标签: java sockets bytearray


【解决方案1】:

在同一个流上混合二进制和文本模式是很棘手的。建议您不要这样做。使用DataInputStream(用于名称、计数和文件内容)是一种可能的解决方案。 (这就是我会尝试的)。另一种是将文件内容编码为文本(例如使用 Base64 编码)。

您当前的“混合流:代码在客户端的问题。当您从 BufferedReader 读取名称和大小时,您将导致读取器从套接字读取并缓冲多达 4096 个字节。问题是其中一些字节是文件内容。因此,当您尝试从底层InputStream 读取内容时:

    input.read(arr);

您可能会发现没有什么可阅读的了。结果:一个空的或损坏的文件。


还有另一个问题。您的代码假定 input.read(arr) 语句将读取流的其余部分,或者直到它填满字节数组。这个假设是不正确的。当您从套接字流中读取数据时,read 可能只返回当前可用的字节(在客户端网络堆栈中)。

再一次,结果很可能是一个损坏的文件。 (在这种情况下被截断。)

读取的代码应如下所示:

  int count = 0;
  while (count < size) {
      int bytesRead = is.read(bytes, count, bytes.length - count);
      if (bytesRead == -1) {
           throw EOFException("didn't get a complete file");
      }
      count += bytesRead;
  }

最后:

  • 将文件内容读入两端的字节数组会浪费内存,而且对于非常大的文件会产生问题。

  • 您确实应该使用“尝试使用资源”来确保所有流都正确关闭。手工操作很麻烦,并且有资源泄漏的风险。

【讨论】:

  • 谢谢。当我修改代码以便只有一种模式(另一端的 DataInputStream 和 DataOutputStream)在服务器端和客户端发送和接收文件时,它起作用了。我在另一端使用 DataOutputStream.writeUTF() 和 readUTF() 发送字符串。
【解决方案2】:

您可以使用 DataOutputStream 使用 writeUTF() 函数在输出流上直接写入一些字符串(消息)。然后你可以通过 readUTF() 方法使用 DataInputStream 类的对象接收你的消息。

你可以使用以下方式发送数据:-

String message="something";
DataOutputStream out=new DataOutputStream(socket.getOutputStream());
out.writeUTF(message);

您可以使用以下方式接收数据或消息:-

 DataInputStream in=new DataInputStream(socket.getInputStream());
 String message=in.readUTF();

我基本上是使用这些方法从输入流中读取数据并将数据写入输出流多次并且每次都有效,所以你也应该检查这种方式。

【讨论】:

    【解决方案3】:

    我正在制作一个程序,它接受一个文件,并通过套接字将它发送到客户端。客户端接收它并将其保存到文件中。这就是它应该做的。

    如果您不需要检查正在通过的内容,那么我认为直接InputStreamOutputStream 是要走的路。代码简单快速,因为它避免了检查内容以进行编码等的高级流类型所带来的任何开销。这也减少了破坏信息的机会。

    我同意 Stephen C 的回答,除了

    在两端将文件内容读入字节数组会浪费内存,而且对于非常大的文件会产生问题。

    由于特定要求只需将一个文件移动到另一个系统而无需查看值,如果您知道如何处理内容,这不是问题。基本流程是

    client:  InputStream in = getFileInputStream();
             OutputStream out = socket.getOutputStream();
             byte[] bytes = new byte[BUFFER_SIZE]; // could be anything
             int bytesRead;
             while((bytesRead = in.read(bytes)) != -1){
                 out.write(bytes,0,bytesRead);
             }
             in.close();
             out.close();
    
    server:  InputStream in = socket.getInputStream();
             OutputStream out = getFileOutputStream();
             // the rest is the exact same thing as the client
    

    这将处理任意大小的文件,仅受服务器磁盘大小的限制。

    这是我整理的一个例子。诚然,这很 hacky(例如使用 FILE_COUNTERSTOP_KEY),但我只是试图展示让用户输入文件然后在客户端和服务器之间发送文件的各个方面。

    public class FileSenderDemo {
    
        private static final int PORT = 7999;
        private static final String STOP_KEY = "server.stop";
    
        private static final int[] FILE_COUNTER = {0};
    
        public static void main(String[] args) {
    
            FileSenderDemo sender = new FileSenderDemo();
    
            Thread client = new Thread(sender.getClient());
            Thread server = new Thread(sender.getServer());
    
            server.start();
            client.start();
            try {
                server.join();
                client.join();
            } catch (InterruptedException e) {
                FILE_COUNTER[0] = 999 ;
                System.setProperty(STOP_KEY,"stop");
                throw new IllegalStateException(e);
            }
        }
    
        public void send(File f, OutputStream out) throws IOException{
            try(BufferedInputStream in = new BufferedInputStream(new FileInputStream(f),1<<11)){
                byte[] bytes = new byte[1<<11];
                int bytesRead;
                while((bytesRead = in.read(bytes)) != -1){
                    out.write(bytes,0,bytesRead);
                }
            }
        }
    
        public Runnable getClient() {
            return () -> {
                while(FILE_COUNTER[0] < 3 && System.getProperty(STOP_KEY) == null) {
                    Socket socket;
                    try {
                        socket = new Socket("localhost", PORT);
                    } catch (IOException e) {
                        throw new IllegalStateException("CLIENT: Can't create the client: " + e.getMessage(), e);
                    }
    
                    File f = getFile();
    
                    try (BufferedOutputStream out = new BufferedOutputStream(socket.getOutputStream())) {
                        send(f, out);
                    } catch (IOException e) {
                        System.out.println("CLIENT: Failed to send file " + f.getAbsolutePath()+" due to: " + e.getMessage());
                        e.printStackTrace(System.err);
                    } finally {
                        FILE_COUNTER[0]++;
                    }
                }
                System.setProperty(STOP_KEY,"stop");
            };
        }
    
        public File getFile(){
            Scanner scanner = new Scanner(System.in);
            System.out.println("CLIENT: Enter a file Name: ");
            return new File(scanner.next());
        }
    
        public Runnable getServer(){
            return () -> {
                OutputStream out = null;
                try{
                    ServerSocket server = new ServerSocket(PORT);
                    server.setSoTimeout(20000);
                    while(System.getProperty(STOP_KEY) == null){
                        Socket socket = null;
                        try {
                            socket = server.accept();
                        }catch (SocketTimeoutException e){
                            System.out.println("SERVER: Waited 20 seconds for an accept.  Now checking if we need to stop.");
                            continue;
                        }
                        String fileName = "receivedFile_"+System.currentTimeMillis()+".content";
                        File outFile = new File(fileName);
                        out = new BufferedOutputStream(new FileOutputStream(outFile));
                        InputStream in = socket.getInputStream();
                        int bytesRead;
                        byte[] bytes = new byte[1<<12];
                        while((bytesRead = in.read(bytes)) != -1){
                            out.write(bytes,0,bytesRead);
                        }
                        out.close();
                        socket.close();
                        System.out.println("SERVER: Just created a new file: " + outFile.getAbsolutePath());
                    }
                    System.out.println("SERVER: " + STOP_KEY + " was not null, so quit.");
                }catch (IOException e){
                    throw new IllegalStateException("SERVER: failed to receive the file content",e);
                }finally {
                    if(out != null){
                        try{out.close();}catch (IOException e){}
                    }
                }
            };
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2010-11-13
      • 2012-10-25
      • 2016-01-27
      • 1970-01-01
      • 1970-01-01
      • 2014-09-30
      • 1970-01-01
      • 2013-04-05
      • 1970-01-01
      相关资源
      最近更新 更多