Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/345.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/301.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/python-3.x/19.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 通过TCP/IP套接字发送大数据_Java_C#_Networking_Tcp_Large Data - Fatal编程技术网

Java 通过TCP/IP套接字发送大数据

Java 通过TCP/IP套接字发送大数据,java,c#,networking,tcp,large-data,Java,C#,Networking,Tcp,Large Data,我有一个小项目,在C中运行服务器,在Java中运行客户端。服务器将图像发送到客户端。 有些图像相当大(有时高达10Mb),因此我将图像字节分割,并以32768字节的块发送。 我的C#服务器代码如下: using (var stream = new MemoryStream(ImageData)) { for (int j = 1; j <= dataSplitParameters.NumberOfChunks; j++) { byte[] chunk;

我有一个小项目,在
C
中运行服务器,在
Java
中运行客户端。服务器将图像发送到客户端。 有些图像相当大(有时高达10Mb),因此我将图像字节分割,并以
32768字节的块发送。
我的C#服务器代码如下:

using (var stream = new MemoryStream(ImageData))
{
   for (int j = 1; j <= dataSplitParameters.NumberOfChunks; j++)
   {
      byte[] chunk;
      if (j == dataSplitParameters.NumberOfChunks)
         chunk = new byte[dataSplitParameters.FinalChunkSize];
      else
         chunk = new byte[dataSplitParameters.ChunkSize];

      int result = stream.Read(chunk, 0, chunk.Length);

      string line = DateTime.Now + ", Status OK, " + ImageName+ ", ImageChunk, " + j + ", " + dataSplitParameters.NumberOfChunks + ", " + chunk.Length;

      //write read params
      streamWriter.WriteLine(line);
      streamWriter.Flush();
      
      //write the data
      binaryWriter.Write(chunk);
      binaryWriter.Flush();
      Console.WriteLine(line);

      string deliveryReport = streamReader.ReadLine();
      Console.WriteLine(deliveryReport);
     }
  }
long dataRead = 0;
for (int j = 1; j <= numberOfChunks; j++) {
    String line = bufferedReader.readLine();
    tokens = line.split(", ");
    System.out.println(line);

    int toRead = Integer.parseInt(tokens[tokens.length - 1]);
    byte[] chunk = new byte[toRead];
    int read = inputStream.read(chunk, 0, toRead);
    //do something with the data
    dataRead += read;

    String progressReport = pageLabel + ", progress: " + dataRead + "/" + dataLength + " bytes.";
    bufferedOutputStream.write((progressReport + "\n").getBytes());
    bufferedOutputStream.flush();

    System.out.println(progressReport);
}

我做错了什么?

您的Java代码似乎使用了
BufferedReader
。它将数据读入自己的缓冲区,这意味着它在底层套接字输入流中不再可用——这是您的第一个问题。第二个问题是如何使用
inputStream.read
——它不能保证读取您请求的所有字节,您必须在它周围设置一个循环

这不是一个特别容易解决的问题。当在同一个流中混合二进制和文本数据时,很难将其读回。在Java中,有一个名为的类可以提供一些帮助-它有一个
readLine
方法来读取一行文本,还有一些方法来读取二进制数据:

DataInputStream dataInput = new DataInputStream(inputStream);

for (int j = 1; j <= numberOfChunks; j++) {
    String line = dataInput.readLine();
    ...
    byte[] chunk = new byte[toRead];
    int read = dataInput.readFully(chunk);
    ...
}
DataInputStream dataInput=新的DataInputStream(inputStream);
对于(int j=1;j)基本问题。
一旦您将inputstream包装到bufferedreader中,您必须停止访问inputstream。bufferedreader已被缓冲,它将读取它想要的任何数据,仅限于读取精确到下一个换行符的数据,并在那里停止

java端的BufferedReader读取的数据远远不止这些,因此它已经消耗了大量的图像数据,并且没有出路。通过制作BufferedReader,您已经无法完成这项工作,因此您无法做到这一点

根本问题。 您只有一个TCP/IP连接。在此连接上,您发送一些不相关的文本(页面、进度等),然后发送未知数量的图像数据,然后发送另一个不相关的进度更新

这从根本上说是错误的。图像解析器怎么可能知道在发送图像的中途,您会得到一个状态更新行?文本也是二进制数据,没有神奇的标识符让客户端知道:这个字节是图像数据的一部分,但这个字节是中间发送的带有进度信息的文本

简单的解决方法。 你会认为简单的解决办法是..好吧,那就停止吧!你为什么要发送这个进度?客户端完全能够知道它读取了多少字节,发送没有意义。只需..获取二进制数据。打开outputstream。发送所有数据。在客户端,打开inputstream,读取所有数据。不要参与字符串。不要使用任何带有“与字符一起工作”味道的东西(所以,BufferedReader?不。BufferedInputStream可以)

…但现在客户不知道标题,也不知道总尺寸! 所以,制作一个有线协议。它几乎是微不足道的

这是您的有线协议:

  • 4字节,大端:SizeOfName
  • SizeOfName字节数。UTF-8编码的文档标题
  • 4字节,大端:SizeOfData
  • SizeOfData字节数。图像数据
  • 如果您真的希望客户端能够呈现进度条并知道标题,则不必执行任何操作,直接发送字节,并通过..关闭连接发出文件已完全发送的信号

    下面是一些示例java代码:

    try (InputStream in = ....) {
      int nameSize = readInt(in);
      byte[] nameBytes = in.readNBytes(nameSize);
      String name = new String(nameBytes, StandardCharsets.UTF_8);
      int dataSize = readInt(in);
      try (OutputStream out = 
        Files.newOutputStream(Paths.get("/Users/TriSky/image.png")) {
    
        byte[] buffer = new byte[65536];
        while (dataSize > 0) {
          int r = in.read(buffer);
          if (r == -1) throw new IOException("Early end-of-stream");
          out.write(buffer, 0, r);
          dataSize -= r;
        }
      }
    }
    
    public int readInt(InputStream in) throws IOException {
        byte[] b = in.readNBytes(4);
        return ByteBuffer.wrap(b).getInt();
    }
    
    闭幕词 应用程序中的另一个错误是使用了错误的方法。Java的“读取(字节)”方法(必要时)不会完全填充该字节数组。所有读取(字节[])将执行至少读取1个字节的操作(除非流被关闭,否则它将读取none,并返回-1。其思想是:read将读取最佳的字节数:正好与当前准备提供给您的字节数相同。有多少字节?谁知道-如果忽略in.read(字节)的返回值,您的代码必然会被破坏,而您正是这样做的。您真正想要的是,例如
    readNBytes
    ,它保证它完全填充该字节数组(或者直到流结束,以先发生的为准)


    请注意,在上面的传输代码中,我也使用基本读取,但在这里我不会忽略返回值。

    当您尝试发送图像时,您必须将图像作为普通文件打开,然后将图像子串成一些块,每个块将其更改为“base64encode”由于图像数据不是正常数据,因此当您发送并由客户端解码时,base64encode将此符号更改为正常字符,如AfHM65Hkgf7MM

    调试您的应用程序。您的代码假定您可以拆分到达客户端的任何行。如果二进制数据包含换行字符,会发生什么情况(0x0D 0x0A或仅0x0A)?@f1sh我不认为是这样,因为我有一个定义良好的协议:(1)服务器发送
    读取参数作为一行文本数据,客户端读取一行文本数据;(2)服务器发送预定义大小的二进制数据,客户端读取预定义大小的二进制数据;(3)客户端发送一行文本数据,服务器读取一行文本数据。我只是想知道这个协议是如何崩溃的。你先发送了一个日期时间。你处理了吗?并且在将原始流包装到BufferedReader中后,出于许多原因,不要使用原始流。你有没有将
    打印到控制台?这将是第一件要做的事情开始调试过程。回答得很好!你涵盖了各个方面。
    try (InputStream in = ....) {
      int nameSize = readInt(in);
      byte[] nameBytes = in.readNBytes(nameSize);
      String name = new String(nameBytes, StandardCharsets.UTF_8);
      int dataSize = readInt(in);
      try (OutputStream out = 
        Files.newOutputStream(Paths.get("/Users/TriSky/image.png")) {
    
        byte[] buffer = new byte[65536];
        while (dataSize > 0) {
          int r = in.read(buffer);
          if (r == -1) throw new IOException("Early end-of-stream");
          out.write(buffer, 0, r);
          dataSize -= r;
        }
      }
    }
    
    public int readInt(InputStream in) throws IOException {
        byte[] b = in.readNBytes(4);
        return ByteBuffer.wrap(b).getInt();
    }