ObjectOutputStream 和 java.io.StreamCorruptedException

2024-04-05

当我尝试使用 ObjectOutputStream 将自定义对象(请参阅 Content.java)从客户端发送到服务器时,在发送第一个对象后收到 StreamCorruptedException。因此,如果我尝试发送另一个对象,我会收到异常(第一次有效)。我已经用谷歌搜索并阅读了很多东西,现在我即将放弃,所以我请求你的帮助。

客户端.java

public class Client extends Thread {
private final static String TAG ="Client";
private final static String IP = "10.0.2.2";
private final static int PORT = 12345;
private Socket s;
private static ObjectOutputStream out;
private static ObjectInputStream in;
//private PrintWriter out;
//private BufferedReader in;
private TextView tv;
private Content c = new Content("");

public Client(TextView tv) {
    this.tv = tv;

}

public void run() {
    s = null;
    out = null;
    in = null;
    String res;

    try {
        s = new Socket(IP, PORT);
        Log.v(TAG, "C: Connected to server" + s.toString());

        out = new ObjectOutputStream(s.getOutputStream());
        in = new ObjectInputStream(s.getInputStream());

        //out = new PrintWriter(s.getOutputStream(), true);
        //in = new BufferedReader(new InputStreamReader(s.getInputStream()));
        //c.setText("PING to server from client");
        //out.writeObject(c);


        while((c = (Content)in.readObject()) != null) {
            try {
                    res = c.getText();
                    Log.i(TAG, res);
            } catch (Exception e) {
                Log.e("readobject", e.toString());
            }
        }

    } catch(Exception e) {
        Log.e("run @ client", e.toString());
    } finally {
        try {
            out.close();
            in.close();
            s.close();
        } catch(IOException e) {
            Log.e(TAG, e.toString());
        }
    }
}

public String setText() throws Exception{
    return in.toString();

}

public void sendText(String text) {
    Content cont = new Content(text);
    try {
        out.writeObject(cont);
    } catch(Exception e) {
        e.printStackTrace();
        Log.e("writeObject", e.toString());
    } finally {
        try {
            out.flush();
            out.close();
            s.close();
            Log.i(TAG, "Object sent");
        } catch (Exception e){}
    }


}
}

内容.java

public class Content implements Serializable{
private String text;

public Content(String text) {
    this.text = text;
}

public String getText() {
    return text;
}

public void setText(String text) {
    this.text = text;
}
}

Stack:

04-24 17:09:12.345: WARN/System.err(520): java.io.StreamCorruptedException
04-24 17:09:12.355: WARN/System.err(520): at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:1707)
04-24 17:09:12.355: WARN/System.err(520): at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:1660)
04-24 17:09:12.365: WARN/System.err(520): at client.android.Client.sendText(Client.java:83)
04-24 17:09:12.365: WARN/System.err(520): at client.android.ClientActivity.sendToServer(ClientActivity.java:38)
04-24 17:09:12.365: WARN/System.err(520): at java.lang.reflect.Method.invokeNative(Native Method)
04-24 17:09:12.365: WARN/System.err(520): at java.lang.reflect.Method.invoke(Method.java:521)
04-24 17:09:12.365: WARN/System.err(520): at android.view.View$1.onClick(View.java:2026)
04-24 17:09:12.365: WARN/System.err(520): at android.view.View.performClick(View.java:2364)
04-24 17:09:12.365: WARN/System.err(520): at android.view.View.onTouchEvent(View.java:4179)
04-24 17:09:12.365: WARN/System.err(520): at android.widget.TextView.onTouchEvent(TextView.java:6541)
04-24 17:09:12.375: WARN/System.err(520): at android.view.View.dispatchTouchEvent(View.java:3709)
04-24 17:09:12.375: WARN/System.err(520): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:884)
0    4-24 17:09:12.385: WARN/System.err(520): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:884)
04-24 17:09:12.385: WARN/System.err(520): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:884)
04-24 17:09:12.385: WARN/System.err(520): at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:884)
04-24 17:09:12.385: WARN/System.err(520): at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:1659)
04-24 17:09:12.385: WARN/System.err(520): at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1107)
04-24 17:09:12.385: WARN/System.err(520): at android.app.Activity.dispatchTouchEvent(Activity.java:2061)
04-24 17:09:12.395: WARN/System.err(520): at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:1643)
04-24 17:09:12.395: WARN/System.err(520): at android.view.ViewRoot.handleMessage(ViewRoot.java:1691)
04-24 17:09:12.395: WARN/System.err(520): at android.os.Handler.dispatchMessage(Handler.java:99)
04-24 17:09:12.395: WARN/System.err(520): at android.os.Looper.loop(Looper.java:123)
04-24 17:09:12.395: WARN/System.err(520): at android.app.ActivityThread.main(ActivityThread.java:4363)
04-24 17:09:12.395: WARN/System.err(520): at java.lang.reflect.Method.invokeNative(Native Method)
04-24 17:09:12.395: WARN/System.err(520): at java.lang.reflect.Method.invoke(Method.java:521)
04-24 17:09:12.395: WARN/System.err(520): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:860)
04-24 17:09:12.395: WARN/System.err(520): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618)
04-24 17:09:12.395: WARN/System.err(520): at dalvik.system.NativeStart.main(Native Method)

编辑:添加了 ClientActivity.java 客户端活动.java

public class ClientActivity extends Activity {
private EditText et;
private Client c;
private TextView tv;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    et =(EditText)findViewById(R.id.clientTxt);
    tv = (TextView)findViewById(R.id.recievedTxt);

    c = new Client(tv);
    c.start();

    try {
        tv.setText(c.setText());
    } catch (Exception e) {}


}

public void sendToServer(View v) throws Exception{
    String text = et.getText().toString();
    Log.i("EdittextVALUE", text);
    c.sendText(text);

}

}

服务器.java

public class Server extends Thread {
private static final String TAG = "ServerThread";
private static final int PORT = 12345;

public void run() {
    ServerSocket ss = null;
    Socket s = null;
    String res = "";

    try {
        Log.i(TAG, "Start server");
        ss = new ServerSocket(PORT);
        Log.i(TAG, "ServerSocket created waiting for Client..");
        while(true) {
            s = ss.accept();
            Log.v(TAG, "Client connected");
            Connection c = new Connection(s);
        }
    }catch(IOException e) {
        e.printStackTrace();
    } finally {
        try {
            //out.close();
            //in.close();
            s.close();
            ss.close();
        } catch (IOException e) {}
    }
}

连接.java

public class Connection extends Thread {
private Socket socket;
private static ObjectOutputStream out;
private static ObjectInputStream in;
private final String TAG = "ConnectionClass";

public Connection(Socket socket) {
    try {
        this.socket = socket;
        out = new ObjectOutputStream(socket.getOutputStream());
        in = new ObjectInputStream(socket.getInputStream());

        this.start();

    } catch (IOException ex) {
        ex.printStackTrace();
        Log.e(TAG, ex.toString());
    }

}

public void run() {
    String res = "";
    Content c = null;
    try {
        while(true) {
        while((c = (Content)in.readObject()) != null) {
            try {

                    res = c.getText();
                    Log.i(TAG, res);

            } catch (Exception e) {
                Log.e("lololololo", e.toString());
            }
        }
        }
    } catch (Exception ex) {
        Log.e(TAG, ex.toString());
    } finally {
        try {
            socket.close();
            in.close();
            out.close();
        } catch (Exception e) {}
    }

}

服务器活动.java

public class ServerActivity extends Activity {
public Server server;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    server = new Server();
    server.start();
}
}

编辑:我在接收器中添加了一个数组,以在接收器停止时关闭所有流。

您应该重新设计您的协议层。在这两种设备中,您都必须创建一个ServerSocket聆听新的Sockets。显然,如果你调用任何read()方法当前线程将进入阻塞状态,因此需要使用辅助线程。您需要 start() 和 stop() 接收器并使用侦听器来通知套接字创建。一个可能的实现(可以改进很多,但核心是这样的):

接收器.java

public class Receiver{
private ArrayList<SocketStream> socketStreams;
    private OnNewSocketListener listener;
    private ServerSocket server;
    private Thread thread;
    private int port;

    public static interface OnNewSocketListener{
        void onNewSocket (Stream stream);
    }

    public Receiver (int port, OnNewSocketListener listener){
        this.listener = listener;
            this.port = port;
    }

    public synchronized start (){
        if (thread != null) return;

        server = new ServerSocket (port);
        thread = new Thread (new Runnable (){
                @Override
                public void run (){
                    try{
                        running = true;
                        while (running){
                        socketStreams.add (stream);
                                                    //See Stream.java below
                            listener.onNewSocket (new Stream (server.accept ()));
                        }
                    }catch (SocketException e){
                        //stop() has been called
                    }catch (IOException e){
                        //Error handling
                    }
                }
            }).start ();
        }
    }

    public synchronized void stop (){
        if (thread == null) return;

        running = false;
        try{
            if (server != null){
                server.close ();
            }
        }catch (IOException e){}

    for (SocketStream stream: socketStreams){
        stream.close ();
    }
    socketStreams.clear ();

        thread = null;
    }
}

然后,当您想要读取和写入此套接字时,您需要另一个类来启动一个线程。要阅读您需要另一个线程。您还需要另一个侦听器来通知对象读取并在其他设备关闭流时发出通知。您需要 startReading() 和 close() 方法(如果您停止读取套接字,它将关闭):

Stream.java

public class Stream{
    private Socket socket;
    private OnCloseStreamListener closeListener;
    private OnReadObjectListener readListener;
    private ObjectInputStream in;
    private ObjectOutputStream out;
    private Thread thread;

    public static interface OnReadObjectListener{
        void onReadObject (Object obj);
    }

    public static interface OnCloseStreamListener{
        void onCloseStream ();
    }

    //Used by the receiver to create an input socket
    public Stream (Socket socket){
        this.socket = socket;
        out = new ObjectOutputStream (socket.getOutputStream ());
    }

    //Used by the user to create an output socket, when the client wants to create a socket with the server
    public Stream (String address, int port){
        socket = new Socket (address, port);
        out = new ObjectOutputStream (socket.getOutputStream ());
    }

    public void setOnCloseStreamListener (OnCloseStreamListener listener){
        closeListener = listener;
    }

    public void setOnReadObjectListener (OnReadObjectListener listener){
        readListener = listener;
    }

    public synchronized void startReading (){
        if (thread != null) return;

        thread = new Thread (new Runnable (){
            @Override
            public void run (){
                try{
                    in = new ObjectInputStream (socket.getInputStream ());
                    reading = true;
                    while (reading){
                        Object obj = in.readObject ();
                        if (obj == null){
                            //The other device has closed its socket stream
                            reading = false;
                            closeListener.onCloseSocketStream ();
                        }else{
                            readListener.onReadObject (obj);
                        }
                    }
                }catch (SocketException e){
                    //stopReading() has been called
                }catch (IOException e){
                    //Error handling
                }
            }
        }).start ();
    }

    public synchronized void writeObject (Object obj){
        out.writeObject (obj);
        out.flush;
    }

    public synchronized void close (){
        if (thread != null){
            reading = false;
            socket.close ();
            in.close ();
            out.close ();
            thread = null;
        }else{
            socket.close ();
            in.close ();
        }
    }
}

Usage:
Server

Receiver receiver = new Receiver (5000, new Receiver.OnNewSocketListener (){
    @Override
    void onNewSocket (Stream stream){
        stream.setOnCloseStreamListener (new Stream.OnCloseStreamListener (){
            @Override
            void onCloseStream (){
                //Stream is closed automatically, don't need to call close()
                //Do something
            }
        });
        stream.setOnReadObjectListener (new Stream.OnReadObjectListener (){
            @Override
            void onReadObject (Object obj){
                //Do something with obj
                if (obj.isDoingSomeMaliciousActivities ()){
                    stream.close ();
                }else if (obj.isDoingGoodStuff){
                                    stream.writeObject (new GoodStuff ());
                            }
            }
        });
        stream.startReading ();
    }
});
receiver.start ();
Thread.sleep (10000);
receiver.stop ();

Client

Stream stream = new Stream ("localhost", 5000);
stream.setOnCloseStreamListener (new Stream.OnCloseStreamListener (){
    @Override
    void onCloseStream (){
        //Stream is closed automatically, don't need to call close()
        //Do something
    }
});
stream.setOnReadObjectListener (new Stream.OnReadObjectListener (){
    @Override
    void onReadObject (Object obj){
        //Do something with obj
        if (obj.isDoingSomeMaliciousActivities ()){
            stream.close ();
        }else if (obj.isDoingGoodStuff){
            stream.writeObject (new GoodStuff ());
        }
    }
});
stream.startReading ();
if (iHaveAGoodDay){
    stream.writeObject (new IamHappy ());
}else{
    stream.writeObject (new IwillHackYou ());
}
Thread.sleep (10000);
stream.close ();

这段代码是socket层的核心。它不会工作,因为我没有测试它。您首先需要了解代码才能继续执行该协议。
注意:不要害怕使用您认为需要的所有侦听器,因为您正在构建一个层notifies事件。这就像按下按钮但使用套接字时的用户交互。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

ObjectOutputStream 和 java.io.StreamCorruptedException 的相关文章

随机推荐