当我尝试使用ObjectOutputStream将自定义对象(请参阅Content.java)从客户端发送到服务器时,在发送第一个对象之后,我收到StreamCorruptedException。因此,如果我尝试发送另一个对象,则会收到异常(第一次起作用)。我已经在Google上搜索了很多东西,现在我要放弃了,所以我寻求你的帮助。
客户端程序
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);
}
}
服务器.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) {}
}
}
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();
}
}
最佳答案
编辑:我在接收器中添加了一个数组,以在接收器停止时关闭所有流。
您应该重新设计协议层。在这两种设备中,您都必须创建一个ServerSocket
来侦听新的Socket
。显然,如果调用任何read()
方法,当前线程将进入阻塞状态,因此您需要使用辅助线程。您需要start()和stop()接收器,并使用侦听器来通知套接字创建。一个可能的实现(可以进行很多改进,但是核心是这样):
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;
}
}
然后,当您要读写此套接字时,需要另一个类来启动线程。要阅读,您需要另一个线程。您还需要另一个侦听器来通知对象已读取并通知另一台设备何时关闭流。您需要一个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 ();
}
}
}
用法:
服务器
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 ();
此代码是套接字层的核心。它没有用,因为我没有测试。首先,您需要了解代码才能继续执行协议。
注意:不要害怕使用您认为需要的所有侦听器,因为您正在构造通知事件的层。这就像按下按钮但带有套接字时的用户交互。