سؤال

أنا أستخدم java.net في أحد مشروعي. وكتبت خادم تطبيق يحصل على inputStream من عميل. ولكن في بعض الأحيان ، لا يمكن لـ (Buffered) InportStream الحصول على كل الإخراج الذي أرسله العميل إلى الخادم الخاص بي. كيف يمكنني كتابة انتظار أو شيء من هذا القبيل ، أن يحصل inputStream على كل إخراج العميل؟

(inpectstream الخاص بي ليس سلسلة)

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.availivers

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top