質問

私はプロジェクトの1つでjava.netを使用しています。また、クライアントから入力ストリームを取得するアプリサーバーを書きました。しかし、私の(バッファリングされた)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();
}

これで、通常、1つのノード(ここのサーバー)によって送信されるデータサイズは、事前に不明です。次に、TCPと通信するサーバーとクライアント(または任意の2つのノード)の間の通信のための独自の小さなプロトコルを定義する必要があります。

最も一般的でシンプルなのは、TLVを定義することです:タイプ、長さ、値。したがって、フォームサーバーにクライアントに送信されるすべてのメッセージが付属していることを定義します。

  • タイプを示す1バイト(たとえば、2つまたは何でもあります)。
  • メッセージの長さに対して1バイト(または何でも)
  • 値のnバイト(nは長さが示されています)。

したがって、最低2バイトを受け取る必要があり、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)で到着する最初の2バイトを想定しています。メッセージの残りの部分の異なるエンコードタイプに焦点を当てません。

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.abailable()は、1つのバイトが読み取られた後にのみ使用可能なバイトを表示します。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top