简体   繁体   English

ObjectOutputStream和java.io.StreamCorruptedException

[英]ObjectOutputStream and java.io.StreamCorruptedException

When I try to send a customobject (See Content.java) from my client to the server with ObjectOutputStream, I get StreamCorruptedException after the first object is sent. 当我尝试使用ObjectOutputStream从客户端向服务器发送customobject(请参阅Content.java)时,在发送第一个对象后,我得到StreamCorruptedException。 So if I try to send another object I get the exception, (it works the first time). 因此,如果我尝试发送另一个对象,我会得到异常,(它第一次工作)。 I have googled and read a LOT of stuff, and now I'm about to give up, so I ask for your help. 我用谷歌搜索了很多东西,现在我要放弃了,所以我请求你的帮助。

Client.java Client.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){}
    }


}
}

Content.java Content.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)

EDIT: added ClientActivity.java ClientActivity.java 编辑:添加了ClientActivity.java ClientActivity.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);

}

} }

Server.java Server.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) {}
    }
}

Connection.java Connection.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) {}
    }

}

ServerActivity.java ServerActivity.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();
}
}

EDIT: I've added an array in the receiver to close all streams when the receiver stops. 编辑:我在接收器中添加了一个数组,以便在接收器停止时关闭所有流。

You should redesign your protocol layer. 您应该重新设计协议层。 In both devices you have to create a ServerSocket to listen for new Socket s. 在这两个设备中,您必须创建一个ServerSocket来侦听新的Socket Obviously, if you call any read() method the current thread will enter in a blocked state, so you need to use a secondary thread. 显然,如果调用任何read()方法,当前线程将进入阻塞状态,因此您需要使用辅助线程。 You need to start() and stop() the receiver and use a listener to notify the socket creations. 你需要start()和stop()接收器并使用一个监听器来通知套接字创建。 A possible implementation (it can be improved a lot, but the core is this): 一个可能的实现(它可以改进很多,但核心是这个):

Receiver.java Receiver.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;
    }
}

Then you need another class that starts a thread when you want to read and write to this socket. 然后,当您想要读取和写入此套接字时,需要另一个启动线程的类。 To read you need another thread. 要阅读你需要另一个线程。 You also need another listener to notify the object read and to notify when the other device closes the stream. 您还需要另一个侦听器来通知读取的对象,并在其他设备关闭流时进行通知。 You need a startReading() and close() methods (if you stop reading the socket it will close): 你需要一个startReading()和close()方法(如果你停止读取它将关闭的套接字):

Stream.java 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 ();

This code is the core of the socket layer. 此代码是套接字层的核心。 It won't work because I don't tested it. 它不起作用,因为我没有测试它。 You first need to understand the code to proceed with the protocol. 您首先需要了解代码以继续协议。
Note: Don't be afraid to use all the listeners you think you need because you are constructing a layer that notifies events. 注意:不要害怕使用您认为需要的所有侦听器,因为您正在构建一个通知事件的层。 It's like the user interaction when presses a button but with sockets. 这就像按下按钮但使用套接字时的用户交互。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM