سؤال

أقوم بإنشاء تطبيق عميل/خادم بسيط باستخدام مآخذ توصيل جافا وتجربة ObjectOutputStream وما إلى ذلك.

لقد كنت أتابع البرنامج التعليمي على عنوان url هذا http://java.sun.com/developer/technicalArticles/ALT/sockets يبدأ من منتصف الطريق عندما يتحدث عن نقل الأشياء عبر المقابس.

انظر الكود الخاص بي للعميل http://pastebin.com/m37e4c577 ولكن يبدو أن هذا لا يعمل ولا أستطيع معرفة ما الذي لا يعمل.يتم نسخ الكود الذي تم التعليق عليه في الأسفل مباشرةً من البرنامج التعليمي - ويعمل هذا عندما أستخدمه فقط بدلاً من إنشاء كائن العميل.

يمكن لأي شخص أن يرى أي شيء أفعله خطأ؟

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

المحلول

والمشكلة هي النظام الذي تقوم بإنشاء تيارات:

في الملقم من المادة (التي أفترض هو ما تستخدمه)، عند فتح اتصال جديد، الملقم يفتح أول تيار المدخلات، ثم تيار الإخراج:

public Connect(Socket clientSocket) {
 client = clientSocket;
 try {
  ois = new ObjectInputStream(client.getInputStream());
  oos = new ObjectOutputStream(client.getOutputStream());
 } catch(Exception e1) {
     // ...
 }
 this.start();
}

ورمز المثال علق يستخدم ترتيب عكسي، أولا تأسيس تيار الإخراج، ثم دفق الإدخال:

// open a socket connection
socket = new Socket("localhost", 2000);
// open I/O streams for objects
oos = new ObjectOutputStream(socket.getOutputStream());
ois = new ObjectInputStream(socket.getInputStream());

ولكن التعليمات البرمجية يفعل ذلك على العكس من ذلك:

server = new Socket(host, port);
in = new ObjectInputStream(server.getInputStream());
out = new ObjectOutputStream(server.getOutputStream());

وإنشاء الناتج تيار / الإدخال الزوج تيار ستتوقف الا بعد ان تبادل المعلومات الخاصة بهم المصافحة، لذلك يجب أن تتناسب مع نظام الخلق. يمكنك القيام بذلك فقط عن طريق مبادلة خطوط 34 و 35 في المثال التعليمات البرمجية.

نصائح أخرى

وأنت لا تكتب الكائن في أي مكان.

ونرى أن الارتباط مرة أخرى، في مكان ما لديك لكتابة:

 oos.writeObject( new Date() );

في التعليمات البرمجية لديك فقط

ois.readObject();

وهذا هو السبب

ووللتذكير فقط.

عند استخدام ObjectOutputStream نضع في اعتبارنا أنه يحافظ على مخبأ للإشارة. إذا كنت أكتب كائن، تغيير محتويات الكائن، ومن ثم ترسل نفس الكائن مرة أخرى، سوف تحصل على بيانات مكررة. على سبيل المثال:

List list = new ArrayList();
list.add("value1");
out.writeObject(list);
list.clear();
list.add("value2");
out.writeObject(list);

هل تنتج في جانب العميل قائمتين مع السلسلة "VALUE1".

لتجنب ذلك، يجب استدعاء طريقة لإعادة ضبط مخبأ تيار عند كتابة نفس مرجع كائن عدة مرات:

List list = new ArrayList();
list.add("value1");
out.writeObject(list);
out.reset();
list.clear();
list.add("value2");
out.writeObject(list);

ربما سترغب في تعلم الأساسيات أولاً.

إليك عينة قمت بتشفيرها للتو.

يبدأ أ الخادم, ، الذي يحضر عميل واحد فقط، ويرسل كائنًا ويموت.

عندما يضغط المستخدم (أنت) على زر الإدخال، يظهر جديد عميل يتم إنشاؤه، ويتصل بالخادم الذي تم إنشاؤه مسبقًا ويقرأ الكائن الذي سيرسله الخادم.

لا يتم التعامل مع أي استثناء هنا.فقط لتبسيط الأمور، ولكن هذه ليست الطريقة التي ينبغي التعامل بها مع الاستثناء.

عندما تفهم جميع المفاهيم هنا، سيكون من الأسهل فهم تلك الموجودة في البرنامج التعليمي.

import java.io.*;
import java.net.*;
import java.util.*;

public class SimpleServer implements Runnable { 

     // Creates the server, send a "date" and die.
    public void run() { 
        try {
            ServerSocket server = new ServerSocket( 8090 );
            Date creationDate = new Date();
            System.out.println("(Server) Server is ready " 
                                 + "and running at " + creationDate );

            Socket uniqueClient = server.accept();

            // We will write using this "chained" object.
            ObjectOutputStream out = new ObjectOutputStream( 
                                                 uniqueClient.getOutputStream());

            out.writeObject( creationDate );


            // close all, at this point forget about the exceptions.
            // this is lesson #1      
            out.close();

            uniqueClient.close();

            server.close();        

            System.out.println("(Server) The server is down");
        }catch( IOException ioe ) {}

     }

    public static void main ( String [] args ) throws IOException ,
                                                 ClassNotFoundException { 

         Thread serverThread = new Thread( new SimpleServer() );

         serverThread.start(); // start the server thread ... doh..

         System.out.println("(Client) Press enter when you want "+ 
                               " to connect to the server...");

         Scanner scanner = new Scanner( System.in );

         scanner.nextLine();

         Socket client = new Socket("localhost", 8090 );

         // Read from this object.
         ObjectInputStream in = new ObjectInputStream( client.getInputStream() );

         Date date = ( Date ) in.readObject();

         System.out.println("(Client) Current time is:          " + new Date() );
         System.out.println("(Client) Object read from server : " + date );

         in.close();
         client.close();

    }
}

آمل أن يساعد هذا.

إذا حاولت مصحح أخطاء كان يمكن أن يكون قال لك أين هي المشكلة. (ربما ليس لماذا)

وقضية لديك هو أن ObjectOutputStream يكتب رأس وObjectInputStream يقرأ أن الرأس. لقد خلق ObjectInputStream أولا مما يعني أنه يحاول قراءة رأس التي لن تكون مكتوبة.

والحل: قم دوما بإنشاء ObjectOutputStream أولا ودافق () أنه قبل إنشاء ObjectInputStream

ومن الأفضل أن فتح outputStream لأن لا يمنع تيار الانتاج. ثم، لديك تيار الإدخال الذي ينتظر Stream. بعد كل تيارات، تكتب لتيار ومسح هذا - outputStream.flush() لإرسال بايت من البيانات. ستحتاج أيضا أسلوب على الطرف الآخر لقراءة المدخلات، سواء كان ذلك ببساطة inputStream.read() الذي يقرأ كل بايت كعدد لchar، أو باستخدام BufferedReader أو Scanner. لقد استعملت تقريبا كل الطرق الممكنة، ولكن الأسلوب الأكثر فعالية لإرسال غير outputStream.write(String) الذي يكتب سلسلة من chars كما bytes في مجرى وقراءة inputStream.read() يقرأ char احد. آمل أن يساعد هذا.

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