ObjectOutputStream和java.io.StreamCorruptedException
当我尝试使用ObjectOutputStream将customobject(请参见Content.java)从我的客户端发送到服务器时,在发送第一个对象后,我会得到StreamCorruptedException。因此,如果我尝试发送另一个对象,我会得到异常(它第一次工作)。我在谷歌上搜索并阅读了很多东西,现在我要放弃了,所以我请求你的帮助 Client.javaObjectOutputStream和java.io.StreamCorruptedException,java,android,objectoutputstream,Java,Android,Objectoutputstream,当我尝试使用ObjectOutputStream将customobject(请参见Content.java)从我的客户端发送到服务器时,在发送第一个对象后,我会得到StreamCorruptedException。因此,如果我尝试发送另一个对象,我会得到异常(它第一次工作)。我在谷歌上搜索并阅读了很多东西,现在我要放弃了,所以我请求你的帮助 Client.java public class Client extends Thread { private final static String T
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;
}
}
堆栈:
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
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);
}
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();
}
}
}
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 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);
}
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
,以侦听新的Socket
s。显然,如果调用任何read()
方法,当前线程将进入阻塞状态,因此需要使用辅助线程。您需要启动()和停止()接收器,并使用侦听器通知套接字创建。一个可能的实现(可以改进很多,但核心是):
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;
}
}
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 ();
}
}
}
用法:服务器
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 ();
客户端
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 ();
此代码是套接字层的核心。它不会工作,因为我没有测试它。您首先需要理解代码才能继续协议。注意:不要害怕使用您认为需要的所有侦听器,因为您正在构建一个通知事件的层。这就像用户在按下按钮时使用套接字进行交互一样。好的,所以我添加了服务器端代码,它也有Content类,但已经发布了。5号,你建议我在这里做什么?我在阅读大量其他代码时得到的印象是,我必须关闭流才能将我放在流中的内容写入流,您的目标是什么?你能解释一下你想要实现的步骤吗?示例:一个设备向另一个设备发送一个对象,而第二个设备执行某些操作。这应该是游戏的通信部分。一个设备执行某项操作,并通过writeObject将对象中的此信息发送到服务器,或者如果服务器执行了某项操作,则应将此信息发送到客户端。所以我希望服务器和客户端能够一直接收对象。那么也许是某种类型的倾听者?然后在buttonPush上发送对象。在您的情况下,两个设备同时是客户端和服务器,因为设备可以随时接收(服务器角色)和发送(客户端角色)对象。明天我将编辑我的答案。@GagleKas哇,谢谢!!我已经阅读了代码,我想我理解了。我以前很少使用线程和侦听器,但您让它看起来“简单”。我确实有一些问题:1.为什么Thread.sleep(10000)和receiver.stop()/stream.stop()是客户端和服务器端?2.在客户端的末尾,它表示stream.write(xxx.();这是一个打字错误,应该是stream.writeObject(obj)还是?3.为什么在客户端的末尾使用if循环?4.我应该在服务器和客户机中的何处编写代码?在构造函数中,或者像公共类服务器{您的服务器代码中的所有代码}?我认为stacktrace与给定的代码不匹配。您在哪里调用“sendText”方法?在ClientActivity中按下按钮时会调用sendText。因此,我在主帖子中添加了ClientActivity的代码。在我看来,您将在向服务器发送消息后关闭套接字,并且在您希望从服务器接收数据时,套接字已关闭,这将不允许您的InputStream工作。
readObject()
不会返回null,除非您编写了nul,尤其不是在流的末尾:它抛出一个EOFException
。因此,您的读取循环不正确。