问题
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. 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
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
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
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
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
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
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();
}
}
回答1:
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. Obviously, if you call any read()
method the current thread will enter in a blocked state, so you need to use a secondary thread. You need to start() and stop() the receiver and use a listener to notify the socket creations. A possible implementation (it can be improved a lot, but the core is this):
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):
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.
来源:https://stackoverflow.com/questions/5771434/objectoutputstream-and-java-io-streamcorruptedexception