32

我在我的一个项目中使用 Java.net。我编写了一个从客户端获取 inputStream 的 App Server。但有时我的(缓冲的)InputStream 无法获取客户端发送到我的服务器的所有 OutputStream。我怎样才能写一个等待或类似的东西,让我的 InputStream 获得客户端的所有 OutputStream?

(我的 InputStream 不是字符串)

private Socket clientSocket;
private ServerSocket server;
private BufferedOutputStream outputS;
private BufferedInputStream inputS;
private InputStream inBS;
private OutputStream outBS;

server = new ServerSocket(30501, 100);
clientSocket = server.accept();

public void getStreamFromClient()  {
    try {
        outBS = clientSocket.getOutputStream();
        outputS = new BufferedOutputStream( outBS);
        outputS.flush();

        inBS = clientSocket.getInputStream();
        inputS = new BufferedInputStream( inBS );

    } catch (Exception e) {
        e.printStackTrace();
    }
}

谢谢。

4

3 回答 3

69

您遇到的问题与 TCP 流性质有关。

您从服务器发送 100 字节(例如)这一事实并不意味着您在第一次读取时会在客户端读取 100 字节。也许从服务器发送的字节在几个 TCP 段中到达客户端。

您需要实现一个循环,在该循环中阅读直到收到整个消息。让我举一个例子,DataInputStream而不是BufferedinputStream。东西很简单,给你举个例子。

假设您事先知道服务器要发送 100 字节的数据。

在客户端中,您需要编写:

byte[] messageByte = new byte[1000];
boolean end = false;
String dataString = "";

try 
{
    DataInputStream in = new DataInputStream(clientSocket.getInputStream());

    while(!end)
    {
        int bytesRead = in.read(messageByte);
        dataString += new String(messageByte, 0, bytesRead);
        if (dataString.length == 100)
        {
            end = true;
        }
    }
    System.out.println("MESSAGE: " + dataString);
}
catch (Exception e)
{
    e.printStackTrace();
}

现在,通常事先不知道一个节点(这里的服务器)发送的数据大小。然后您需要定义自己的小协议,用于服务器和客户端(或任何两个节点)之间的通信,使用 TCP 进行通信。

最常见最简单的就是定义TLV:Type、Length、Value。因此,您定义从服务器发送到客户端的每条消息都带有:

  • 1 字节指示类型(例如,它也可以是 2 或其他)。
  • 消息长度为 1 个字节(或其他)
  • 值的 N 个字节(N 表示长度)。

因此,您知道您必须至少接收 2 个字节,并且通过第二个字节,您知道您需要读取多少后续字节。

这只是一个可能的协议的建议。您也可以摆脱“类型”。

所以它会是这样的:

byte[] messageByte = new byte[1000];
boolean end = false;
String dataString = "";

try 
{
    DataInputStream in = new DataInputStream(clientSocket.getInputStream());
    int bytesRead = 0;

    messageByte[0] = in.readByte();
    messageByte[1] = in.readByte();

    int bytesToRead = messageByte[1];

    while(!end)
    {
        bytesRead = in.read(messageByte);
        dataString += new String(messageByte, 0, bytesRead);
        if (dataString.length == bytesToRead )
        {
            end = true;
        }
    }
    System.out.println("MESSAGE: " + dataString);
}
catch (Exception e)
{
    e.printStackTrace();
}

以下代码编译并看起来更好。它假定提供长度的前两个字节以二进制格式以网络字节序(大字节序)形式到达。没有关注消息其余部分的不同编码类型。

import java.nio.ByteBuffer;
import java.io.DataInputStream;
import java.net.ServerSocket;
import java.net.Socket;

class Test
{
    public static void main(String[] args)
    {
        byte[] messageByte = new byte[1000];
        boolean end = false;
        String dataString = "";

        try 
        {
            Socket clientSocket;
            ServerSocket server;

            server = new ServerSocket(30501, 100);
            clientSocket = server.accept();

            DataInputStream in = new DataInputStream(clientSocket.getInputStream());
            int bytesRead = 0;

            messageByte[0] = in.readByte();
            messageByte[1] = in.readByte();
            ByteBuffer byteBuffer = ByteBuffer.wrap(messageByte, 0, 2);

            int bytesToRead = byteBuffer.getShort();
            System.out.println("About to read " + bytesToRead + " octets");

            //The following code shows in detail how to read from a TCP socket

            while(!end)
            {
                bytesRead = in.read(messageByte);
                dataString += new String(messageByte, 0, bytesRead);
                if (dataString.length() == bytesToRead )
                {
                    end = true;
                }
            }

            //All the code in the loop can be replaced by these two lines
            //in.readFully(messageByte, 0, bytesToRead);
            //dataString = new String(messageByte, 0, bytesToRead);

            System.out.println("MESSAGE: " + dataString);
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }
}
于 2013-11-08T16:17:41.047 回答
1
int c;
    String raw = "";
    do {
        c = inputstream.read();
        raw+=(char)c;
    } while(inputstream.available()>0);

InputStream.available() 仅在读取一个字节后才显示可用字节,因此 do .. while

于 2018-05-25T14:12:08.120 回答
0

您可以像这样阅读 BufferedInputStream 。它将读取数据,直到到达流的末尾,由 -1 指示。

inputS = new BufferedInputStream(inBS);
byte[] buffer = new byte[1024];    //If you handle larger data use a bigger buffer size
int read;
while((read = inputS.read(buffer)) != -1) {
    System.out.println(read);
    // Your code to handle the data
}
于 2013-11-07T15:29:14.823 回答