Вопрос

Я использую java.net в одном из своих проектов. И я написал сервер приложений, который получает InputStream от клиента. Но иногда мой (буферный) inputStream не может получить все выходные данные, которые клиент отправил на мой сервер. Как я могу написать ожидание или что -то в этом роде, что мой 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();
    }
}

Спасибо.

Это было полезно?

Решение

Проблема, которую у вас есть, связана с потоковой природой 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: тип, длина, значение. Таким образом, вы определяете, что каждое отправленное сервер форм формы для клиента приходит:

  • 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();
}

Следующий код компилирует и выглядит лучше. Предполагается, что первые два байта, обеспечивающие длину в бинарном формате, в сетевой эндианстве (Big Endian). Не фокусируется на различных типах кодирования для остальной части сообщения.

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();
        }
    }
}

Другие советы

Вы можете прочитать свой 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
}
int c;
    String raw = "";
    do {
        c = inputstream.read();
        raw+=(char)c;
    } while(inputstream.available()>0);

InputStream.available () показывает доступные байты только после того, как один байт прочитал, следовательно, сделайте ... пока

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top