سؤال

وأنا خلقت SocketChannel إلى ملقم بعيد لإرسال واستقبال الرسائل على القط. لتلقي الرسائل من كمبيوتر بعيد، أنا استخدم موضوع مخصص لمهمة (إلا أن هذا موضوع القراءة من مأخذ، شيء آخر).

عند ورود بعض بايت في SocketChannel (أظل الاقتراع SocketChannel على حجب عدم وضع بيانات جديد)، قرأت لأول مرة 4 بايت للحصول على طول الرسالة التالية، ثم تخصيص وقراءة س بايت من SocketChannel ثم يتم فك وإعادة بنائها في رسالة.

وفيما يلي قانون بلدي لموضوع تلقي:

@Override
public void run() {

    while (true) { //Don't exit thread

        //Attempt to read the size of the incoming message
        ByteBuffer buf = ByteBuffer.allocate(4);

        int bytesread = 0;
        try {
            while (buf.remaining() > 0) {
                bytesread = schannel.read(buf);

                if (bytesread == -1) { //Socket was terminated

                } 

                if (quitthread) break;
            }

        } catch (IOException ex) {

        }

        if (buf.remaining() == 0) {
            //Read the header
            byte[] header = buf.array();
            int msgsize = (0xFF & (int)header[0]) + ((0xFF & (int)header[1]) << 8)
                    + ((0xFF & (int)header[2]) << 16) + ((0xFF & (int)header[3]) << 24);

            //Read the message coming from the pipeline
            buf = ByteBuffer.allocate(msgsize);
            try {
                while (buf.remaining() > 0) {
                    bytesread = schannel.read(buf);

                    if (bytesread == -1) { //Socket was terminated

                    }

                    if (quitthread) break;
                }
            } catch (IOException ex) {

            }

            parent.recvMessage(buf.array());
        }

        if (quitthread) {
            break;
        }
    }

}

وحدات البايت الأولى التي وصلتني من SocketChannel على ما يرام، وأنا بنجاح فك الرسالة. ومع ذلك، في المرة القادمة قرأت من SocketChannel، تخطي مأخذ قبل حوالي 100 بايت، والذي تسبب في الخطأ بايت يمكن ان تقرأ وتفسر على أنها طول، مما تسبب في كل شيء إلى إعطابها.

ما هو الخطأ مع رمز؟ لا ترابط آخر يقرأ من SocketChannel.

هل كانت مفيدة؟

المحلول

وأقواس الخاص بك هي خارج، رمز هو:

(0xFF & ((int)header[1] << 8))

والذي هو دائما 0 (نفس مع << 16 و << 24)، تخميني هو أنت يعني:

((0xFF & ((int)header[1])) << 8)

وهذا من شأنه أن يؤدي إلى قراءة بايت رسالة ليست كافية، كما يؤدي إلى عدم تطابق في التزامن (بالمقارنة مع القراءة كثيرة جدا.)

تعديل : لكنت الآن الثابتة ما سبق، لا أستطيع أن أرى أي شيء خاطئ. هل يمكن أن تخبرنا العلاقة بين طول الرسالة الأولى والعدد الدقيق للبايت التي تؤكل؟

واستنادا إلى الكود الظاهر، بلدي فقط تخمين هو أن قمت بتحرير بعض السلوك من العينة أظهرت التي قد تؤثر على SCHANNEL، هو SCHANNEL المشار إليها في مكان آخر؟

إذا السطر:

ByteBuffer buf = ByteBuffer.allocate(4);

وسيكون خارج while التي من شأنها أن تؤدي إلى سلوك تصفون، ولكن في نموذج التعليمات البرمجية الخاصة بك ليست كذلك.

نصائح أخرى

وأفترض عندما يقول لك هل كنت الاقتراع مأخذ في وضع عدم عرقلة تقصد كنت تستخدم "المعيار" نهج Selector.select()؟

عند اختيار العودة، ويشير إلى أن هناك بيانات متاحة للقراءة من مأخذ يجب عليك قراءة فقط بايت المتوفرة قبل دخول إعادة الدعوة لتحديد (). لو عاد قراءة () -1 فإنه يشير إلى أن ليست أكثر بايت المتاحة للقراءة المباشرة في المخزن المؤقت - وهذا لا يعني أن مأخذ تم إغلاق. وبالتالي أظن بك من محاولة لملء تماما المخزن المؤقت قبل أن تعود غير صحيح. حتى إذا لم عملكم موضوع I / O سيكون الغزل باستمرار في حين تصل البيانات. على وجه الخصوص، يبدو أنك ببساطة تجاهل قيمة إرجاع -1.

والنظر في التعليمات البرمجية لاستخدام نهج آلة الدولة محدود يصمم إعادة. على سبيل المثال، لقد نفذ هذا في الماضي باستخدام 3-دولة نموذجية: IDLE، READ_MESSAGE_LENGTH وREAD_MESSAGE

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